SubGhz: add subghz tx_from_file CLI cmd, major TX flow refactoring, various improvements and bug fixes (#3302)
				
					
				
			* SubGhz: add cmd CLI "subghz tx_from_file" * SubGhz: add sending raw.sub files * SubGhz: add load custom preset * SubGhz: remove unnecessary files * SubGhz: change message * SubGhz: fix printf formatting * SubGhz: Cli refactoring code * FuriHal: add furi_hal_subghz Tx Rx IDLE state switching test * SubGhz: remove debug code, fix ext driver compilation * SubGhz: cleanup code, move wait status routine to cc1101 driver * SubGhz: proper pin mode transition in tx stop isr routine, proper DMA and ISR priorities, fix issue with async tx stuck * SubGhz: simplify async tx stop flow, fix ISR ARR check condition race * SubGhz: check ARR only when we transmitting * SubGhz: check ARR only when we transmitting for ext cc1101 * SubGhz: lower ISR priorities to safe level * SubGhz: proper gpio config, comments update Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									3fd5f15e7f
								
							
						
					
					
						commit
						d73d007797
					
				@ -45,7 +45,6 @@ typedef enum {
 | 
				
			|||||||
    SubGhzDeviceCC1101ExtStateIdle, /**< Idle, energy save mode */
 | 
					    SubGhzDeviceCC1101ExtStateIdle, /**< Idle, energy save mode */
 | 
				
			||||||
    SubGhzDeviceCC1101ExtStateAsyncRx, /**< Async RX started */
 | 
					    SubGhzDeviceCC1101ExtStateAsyncRx, /**< Async RX started */
 | 
				
			||||||
    SubGhzDeviceCC1101ExtStateAsyncTx, /**< Async TX started, DMA and timer is on */
 | 
					    SubGhzDeviceCC1101ExtStateAsyncTx, /**< Async TX started, DMA and timer is on */
 | 
				
			||||||
    SubGhzDeviceCC1101ExtStateAsyncTxEnd, /**< Async TX complete, cleanup needed */
 | 
					 | 
				
			||||||
} SubGhzDeviceCC1101ExtState;
 | 
					} SubGhzDeviceCC1101ExtState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** SubGhz regulation, receive transmission on the current frequency for the
 | 
					/** SubGhz regulation, receive transmission on the current frequency for the
 | 
				
			||||||
@ -392,12 +391,18 @@ void subghz_device_cc1101_ext_reset() {
 | 
				
			|||||||
void subghz_device_cc1101_ext_idle() {
 | 
					void subghz_device_cc1101_ext_idle() {
 | 
				
			||||||
    furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
 | 
					    furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
 | 
				
			||||||
    cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle);
 | 
					    cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle);
 | 
				
			||||||
 | 
					    //waiting for the chip to switch to IDLE mode
 | 
				
			||||||
 | 
					    furi_check(cc1101_wait_status_state(
 | 
				
			||||||
 | 
					        subghz_device_cc1101_ext->spi_bus_handle, CC1101StateIDLE, 10000));
 | 
				
			||||||
    furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
 | 
					    furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_device_cc1101_ext_rx() {
 | 
					void subghz_device_cc1101_ext_rx() {
 | 
				
			||||||
    furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
 | 
					    furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
 | 
				
			||||||
    cc1101_switch_to_rx(subghz_device_cc1101_ext->spi_bus_handle);
 | 
					    cc1101_switch_to_rx(subghz_device_cc1101_ext->spi_bus_handle);
 | 
				
			||||||
 | 
					    //waiting for the chip to switch to Rx mode
 | 
				
			||||||
 | 
					    furi_check(
 | 
				
			||||||
 | 
					        cc1101_wait_status_state(subghz_device_cc1101_ext->spi_bus_handle, CC1101StateRX, 10000));
 | 
				
			||||||
    furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
 | 
					    furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -405,6 +410,9 @@ bool subghz_device_cc1101_ext_tx() {
 | 
				
			|||||||
    if(subghz_device_cc1101_ext->regulation != SubGhzDeviceCC1101ExtRegulationTxRx) return false;
 | 
					    if(subghz_device_cc1101_ext->regulation != SubGhzDeviceCC1101ExtRegulationTxRx) return false;
 | 
				
			||||||
    furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
 | 
					    furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
 | 
				
			||||||
    cc1101_switch_to_tx(subghz_device_cc1101_ext->spi_bus_handle);
 | 
					    cc1101_switch_to_tx(subghz_device_cc1101_ext->spi_bus_handle);
 | 
				
			||||||
 | 
					    //waiting for the chip to switch to Tx mode
 | 
				
			||||||
 | 
					    furi_check(
 | 
				
			||||||
 | 
					        cc1101_wait_status_state(subghz_device_cc1101_ext->spi_bus_handle, CC1101StateTX, 10000));
 | 
				
			||||||
    furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
 | 
					    furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -653,7 +661,6 @@ static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t sa
 | 
				
			|||||||
            if(LL_DMA_IsActiveFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) {
 | 
					            if(LL_DMA_IsActiveFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) {
 | 
				
			||||||
                LL_DMA_ClearFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA);
 | 
					                LL_DMA_ClearFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            LL_TIM_EnableIT_UPDATE(TIM17);
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            // Lowest possible value is 4us
 | 
					            // Lowest possible value is 4us
 | 
				
			||||||
@ -689,22 +696,6 @@ static void subghz_device_cc1101_ext_async_tx_dma_isr() {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void subghz_device_cc1101_ext_async_tx_timer_isr() {
 | 
					 | 
				
			||||||
    if(LL_TIM_IsActiveFlag_UPDATE(TIM17)) {
 | 
					 | 
				
			||||||
        if(LL_TIM_GetAutoReload(TIM17) == 0) {
 | 
					 | 
				
			||||||
            if(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx) {
 | 
					 | 
				
			||||||
                LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
 | 
					 | 
				
			||||||
                subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTxEnd;
 | 
					 | 
				
			||||||
                furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
 | 
					 | 
				
			||||||
                if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
 | 
					 | 
				
			||||||
                    furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false);
 | 
					 | 
				
			||||||
                LL_TIM_DisableCounter(TIM17);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        LL_TIM_ClearFlag_UPDATE(TIM17);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callback, void* context) {
 | 
					bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callback, void* context) {
 | 
				
			||||||
    furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle);
 | 
					    furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle);
 | 
				
			||||||
    furi_assert(callback);
 | 
					    furi_assert(callback);
 | 
				
			||||||
@ -733,7 +724,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
 | 
				
			|||||||
        SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF,
 | 
					        SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF,
 | 
				
			||||||
        LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
 | 
					        LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
 | 
				
			||||||
            LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD |
 | 
					            LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD |
 | 
				
			||||||
            LL_DMA_MODE_NORMAL);
 | 
					            LL_DMA_PRIORITY_VERYHIGH);
 | 
				
			||||||
    LL_DMA_SetDataLength(
 | 
					    LL_DMA_SetDataLength(
 | 
				
			||||||
        SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL);
 | 
					        SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL);
 | 
				
			||||||
    LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, LL_DMAMUX_REQ_TIM17_UP);
 | 
					    LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, LL_DMAMUX_REQ_TIM17_UP);
 | 
				
			||||||
@ -756,9 +747,6 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
 | 
				
			|||||||
    LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL);
 | 
					    LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL);
 | 
				
			||||||
    LL_TIM_DisableARRPreload(TIM17);
 | 
					    LL_TIM_DisableARRPreload(TIM17);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    furi_hal_interrupt_set_isr(
 | 
					 | 
				
			||||||
        FuriHalInterruptIdTim1TrgComTim17, subghz_device_cc1101_ext_async_tx_timer_isr, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    subghz_device_cc1101_ext_async_tx_middleware_idle(
 | 
					    subghz_device_cc1101_ext_async_tx_middleware_idle(
 | 
				
			||||||
        &subghz_device_cc1101_ext->async_tx.middleware);
 | 
					        &subghz_device_cc1101_ext->async_tx.middleware);
 | 
				
			||||||
    subghz_device_cc1101_ext_async_tx_refill(
 | 
					    subghz_device_cc1101_ext_async_tx_refill(
 | 
				
			||||||
@ -816,22 +804,21 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool subghz_device_cc1101_ext_is_async_tx_complete() {
 | 
					bool subghz_device_cc1101_ext_is_async_tx_complete() {
 | 
				
			||||||
    return subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd;
 | 
					    return (
 | 
				
			||||||
 | 
					        (subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx) &&
 | 
				
			||||||
 | 
					        (LL_TIM_GetAutoReload(TIM17) == 0));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_device_cc1101_ext_stop_async_tx() {
 | 
					void subghz_device_cc1101_ext_stop_async_tx() {
 | 
				
			||||||
    furi_assert(
 | 
					    furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
 | 
				
			||||||
        subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx ||
 | 
					 | 
				
			||||||
        subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Deinitialize GPIO
 | 
					 | 
				
			||||||
    furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
 | 
					 | 
				
			||||||
    furi_hal_gpio_init(
 | 
					 | 
				
			||||||
        subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Shutdown radio
 | 
					    // Shutdown radio
 | 
				
			||||||
    subghz_device_cc1101_ext_idle();
 | 
					    subghz_device_cc1101_ext_idle();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Deinitialize GPIO
 | 
				
			||||||
 | 
					    furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
 | 
				
			||||||
 | 
					    furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Deinitialize Timer
 | 
					    // Deinitialize Timer
 | 
				
			||||||
    furi_hal_bus_disable(FuriHalBusTIM17);
 | 
					    furi_hal_bus_disable(FuriHalBusTIM17);
 | 
				
			||||||
    furi_hal_interrupt_set_isr(FuriHalInterruptIdTim1TrgComTim17, NULL, NULL);
 | 
					    furi_hal_interrupt_set_isr(FuriHalInterruptIdTim1TrgComTim17, NULL, NULL);
 | 
				
			||||||
 | 
				
			|||||||
@ -121,7 +121,7 @@ static void nfc_scene_read_menu_on_enter_mf_classic(NfcApp* instance) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nfc_scene_read_success_on_enter_mf_classic(NfcApp* instance) {
 | 
					static void nfc_scene_read_success_on_enter_mf_classic(NfcApp* instance) { //-V524
 | 
				
			||||||
    const NfcDevice* device = instance->nfc_device;
 | 
					    const NfcDevice* device = instance->nfc_device;
 | 
				
			||||||
    const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic);
 | 
					    const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -72,7 +72,6 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
 | 
				
			|||||||
    uint32_t frequency = 0;
 | 
					    uint32_t frequency = 0;
 | 
				
			||||||
    float rssi_temp = -127.0f;
 | 
					    float rssi_temp = -127.0f;
 | 
				
			||||||
    uint32_t frequency_temp = 0;
 | 
					    uint32_t frequency_temp = 0;
 | 
				
			||||||
    CC1101Status status;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Start CC1101
 | 
					    //Start CC1101
 | 
				
			||||||
    furi_hal_subghz_reset();
 | 
					    furi_hal_subghz_reset();
 | 
				
			||||||
@ -123,9 +122,9 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
 | 
				
			|||||||
                    subghz_setting_get_frequency(instance->setting, i));
 | 
					                    subghz_setting_get_frequency(instance->setting, i));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                cc1101_calibrate(&furi_hal_spi_bus_handle_subghz);
 | 
					                cc1101_calibrate(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
                do {
 | 
					
 | 
				
			||||||
                    status = cc1101_get_status(&furi_hal_spi_bus_handle_subghz);
 | 
					                furi_check(cc1101_wait_status_state(
 | 
				
			||||||
                } while(status.STATE != CC1101StateIDLE);
 | 
					                    &furi_hal_spi_bus_handle_subghz, CC1101StateIDLE, 10000));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz);
 | 
					                cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
                furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 | 
					                furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
@ -168,9 +167,9 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
 | 
				
			|||||||
                    frequency = cc1101_set_frequency(&furi_hal_spi_bus_handle_subghz, i);
 | 
					                    frequency = cc1101_set_frequency(&furi_hal_spi_bus_handle_subghz, i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    cc1101_calibrate(&furi_hal_spi_bus_handle_subghz);
 | 
					                    cc1101_calibrate(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
                    do {
 | 
					
 | 
				
			||||||
                        status = cc1101_get_status(&furi_hal_spi_bus_handle_subghz);
 | 
					                    furi_check(cc1101_wait_status_state(
 | 
				
			||||||
                    } while(status.STATE != CC1101StateIDLE);
 | 
					                        &furi_hal_spi_bus_handle_subghz, CC1101StateIDLE, 10000));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz);
 | 
					                    cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
                    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 | 
					                    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
 | 
				
			|||||||
@ -49,6 +49,28 @@ static void subghz_cli_radio_device_power_off() {
 | 
				
			|||||||
    if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg();
 | 
					    if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SubGhzEnvironment* subghz_cli_environment_init(void) {
 | 
				
			||||||
 | 
					    SubGhzEnvironment* environment = subghz_environment_alloc();
 | 
				
			||||||
 | 
					    if(subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_NAME)) {
 | 
				
			||||||
 | 
					        printf("Load_keystore keeloq_mfcodes \033[0;32mOK\033[0m\r\n");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        printf("Load_keystore keeloq_mfcodes \033[0;31mERROR\033[0m\r\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_USER_NAME)) {
 | 
				
			||||||
 | 
					        printf("Load_keystore keeloq_mfcodes_user \033[0;32mOK\033[0m\r\n");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        printf("Load_keystore keeloq_mfcodes_user \033[0;33mAbsent\033[0m\r\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    subghz_environment_set_came_atomo_rainbow_table_file_name(
 | 
				
			||||||
 | 
					        environment, SUBGHZ_CAME_ATOMO_DIR_NAME);
 | 
				
			||||||
 | 
					    subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
 | 
				
			||||||
 | 
					        environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME);
 | 
				
			||||||
 | 
					    subghz_environment_set_nice_flor_s_rainbow_table_file_name(
 | 
				
			||||||
 | 
					        environment, SUBGHZ_NICE_FLOR_S_DIR_NAME);
 | 
				
			||||||
 | 
					    subghz_environment_set_protocol_registry(environment, (void*)&subghz_protocol_registry);
 | 
				
			||||||
 | 
					    return environment;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void subghz_cli_command_tx_carrier(Cli* cli, FuriString* args, void* context) {
 | 
					void subghz_cli_command_tx_carrier(Cli* cli, FuriString* args, void* context) {
 | 
				
			||||||
    UNUSED(context);
 | 
					    UNUSED(context);
 | 
				
			||||||
    uint32_t frequency = 433920000;
 | 
					    uint32_t frequency = 433920000;
 | 
				
			||||||
@ -324,16 +346,7 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) {
 | 
				
			|||||||
        furi_stream_buffer_alloc(sizeof(LevelDuration) * 1024, sizeof(LevelDuration));
 | 
					        furi_stream_buffer_alloc(sizeof(LevelDuration) * 1024, sizeof(LevelDuration));
 | 
				
			||||||
    furi_check(instance->stream);
 | 
					    furi_check(instance->stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SubGhzEnvironment* environment = subghz_environment_alloc();
 | 
					    SubGhzEnvironment* environment = subghz_cli_environment_init();
 | 
				
			||||||
    subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_NAME);
 | 
					 | 
				
			||||||
    subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_USER_NAME);
 | 
					 | 
				
			||||||
    subghz_environment_set_came_atomo_rainbow_table_file_name(
 | 
					 | 
				
			||||||
        environment, SUBGHZ_CAME_ATOMO_DIR_NAME);
 | 
					 | 
				
			||||||
    subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
 | 
					 | 
				
			||||||
        environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME);
 | 
					 | 
				
			||||||
    subghz_environment_set_nice_flor_s_rainbow_table_file_name(
 | 
					 | 
				
			||||||
        environment, SUBGHZ_NICE_FLOR_S_DIR_NAME);
 | 
					 | 
				
			||||||
    subghz_environment_set_protocol_registry(environment, (void*)&subghz_protocol_registry);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SubGhzReceiver* receiver = subghz_receiver_alloc_init(environment);
 | 
					    SubGhzReceiver* receiver = subghz_receiver_alloc_init(environment);
 | 
				
			||||||
    subghz_receiver_set_filter(receiver, SubGhzProtocolFlag_Decodable);
 | 
					    subghz_receiver_set_filter(receiver, SubGhzProtocolFlag_Decodable);
 | 
				
			||||||
@ -517,25 +530,7 @@ void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) {
 | 
				
			|||||||
        // Allocate context
 | 
					        // Allocate context
 | 
				
			||||||
        SubGhzCliCommandRx* instance = malloc(sizeof(SubGhzCliCommandRx));
 | 
					        SubGhzCliCommandRx* instance = malloc(sizeof(SubGhzCliCommandRx));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SubGhzEnvironment* environment = subghz_environment_alloc();
 | 
					        SubGhzEnvironment* environment = subghz_cli_environment_init();
 | 
				
			||||||
        if(subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_NAME)) {
 | 
					 | 
				
			||||||
            printf("SubGhz decode_raw: Load_keystore keeloq_mfcodes \033[0;32mOK\033[0m\r\n");
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            printf("SubGhz decode_raw: Load_keystore keeloq_mfcodes \033[0;31mERROR\033[0m\r\n");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_USER_NAME)) {
 | 
					 | 
				
			||||||
            printf("SubGhz decode_raw: Load_keystore keeloq_mfcodes_user \033[0;32mOK\033[0m\r\n");
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            printf(
 | 
					 | 
				
			||||||
                "SubGhz decode_raw: Load_keystore keeloq_mfcodes_user \033[0;31mERROR\033[0m\r\n");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        subghz_environment_set_came_atomo_rainbow_table_file_name(
 | 
					 | 
				
			||||||
            environment, SUBGHZ_CAME_ATOMO_DIR_NAME);
 | 
					 | 
				
			||||||
        subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
 | 
					 | 
				
			||||||
            environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME);
 | 
					 | 
				
			||||||
        subghz_environment_set_nice_flor_s_rainbow_table_file_name(
 | 
					 | 
				
			||||||
            environment, SUBGHZ_NICE_FLOR_S_DIR_NAME);
 | 
					 | 
				
			||||||
        subghz_environment_set_protocol_registry(environment, (void*)&subghz_protocol_registry);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SubGhzReceiver* receiver = subghz_receiver_alloc_init(environment);
 | 
					        SubGhzReceiver* receiver = subghz_receiver_alloc_init(environment);
 | 
				
			||||||
        subghz_receiver_set_filter(receiver, SubGhzProtocolFlag_Decodable);
 | 
					        subghz_receiver_set_filter(receiver, SubGhzProtocolFlag_Decodable);
 | 
				
			||||||
@ -580,6 +575,262 @@ void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) {
 | 
				
			|||||||
    furi_string_free(file_name);
 | 
					    furi_string_free(file_name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static FuriHalSubGhzPreset subghz_cli_get_preset_name(const char* preset_name) {
 | 
				
			||||||
 | 
					    FuriHalSubGhzPreset preset = FuriHalSubGhzPresetIDLE;
 | 
				
			||||||
 | 
					    if(!strcmp(preset_name, "FuriHalSubGhzPresetOok270Async")) {
 | 
				
			||||||
 | 
					        preset = FuriHalSubGhzPresetOok270Async;
 | 
				
			||||||
 | 
					    } else if(!strcmp(preset_name, "FuriHalSubGhzPresetOok650Async")) {
 | 
				
			||||||
 | 
					        preset = FuriHalSubGhzPresetOok650Async;
 | 
				
			||||||
 | 
					    } else if(!strcmp(preset_name, "FuriHalSubGhzPreset2FSKDev238Async")) {
 | 
				
			||||||
 | 
					        preset = FuriHalSubGhzPreset2FSKDev238Async;
 | 
				
			||||||
 | 
					    } else if(!strcmp(preset_name, "FuriHalSubGhzPreset2FSKDev476Async")) {
 | 
				
			||||||
 | 
					        preset = FuriHalSubGhzPreset2FSKDev476Async;
 | 
				
			||||||
 | 
					    } else if(!strcmp(preset_name, "FuriHalSubGhzPresetCustom")) {
 | 
				
			||||||
 | 
					        preset = FuriHalSubGhzPresetCustom;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        printf("subghz tx_from_file: unknown preset");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return preset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void subghz_cli_command_tx_from_file(Cli* cli, FuriString* args, void* context) { // -V524
 | 
				
			||||||
 | 
					    UNUSED(context);
 | 
				
			||||||
 | 
					    FuriString* file_name;
 | 
				
			||||||
 | 
					    file_name = furi_string_alloc();
 | 
				
			||||||
 | 
					    furi_string_set(file_name, ANY_PATH("subghz/test.sub"));
 | 
				
			||||||
 | 
					    uint32_t repeat = 10;
 | 
				
			||||||
 | 
					    uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Storage* storage = furi_record_open(RECORD_STORAGE);
 | 
				
			||||||
 | 
					    FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
 | 
				
			||||||
 | 
					    FlipperFormat* fff_data_raw = flipper_format_string_alloc();
 | 
				
			||||||
 | 
					    FuriString* temp_str;
 | 
				
			||||||
 | 
					    temp_str = furi_string_alloc();
 | 
				
			||||||
 | 
					    uint32_t temp_data32;
 | 
				
			||||||
 | 
					    bool check_file = false;
 | 
				
			||||||
 | 
					    const SubGhzDevice* device = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t frequency = 0;
 | 
				
			||||||
 | 
					    SubGhzTransmitter* transmitter = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    subghz_devices_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SubGhzEnvironment* environment = subghz_cli_environment_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        if(furi_string_size(args)) {
 | 
				
			||||||
 | 
					            if(!args_read_string_and_trim(args, file_name)) {
 | 
				
			||||||
 | 
					                cli_print_usage(
 | 
				
			||||||
 | 
					                    "subghz tx_from_file: ",
 | 
				
			||||||
 | 
					                    "<file_name: path_file> <Repeat count> <Device: 0 - CC1101_INT, 1 - CC1101_EXT>",
 | 
				
			||||||
 | 
					                    furi_string_get_cstr(args));
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(furi_string_size(args)) {
 | 
				
			||||||
 | 
					            int ret = sscanf(furi_string_get_cstr(args), "%lu %lu", &repeat, &device_ind);
 | 
				
			||||||
 | 
					            if(ret != 2) {
 | 
				
			||||||
 | 
					                printf("sscanf returned %d, repeat: %lu device: %lu\r\n", ret, repeat, device_ind);
 | 
				
			||||||
 | 
					                cli_print_usage(
 | 
				
			||||||
 | 
					                    "subghz tx_from_file:",
 | 
				
			||||||
 | 
					                    "<file_name: path_file> <Repeat count> <Device: 0 - CC1101_INT, 1 - CC1101_EXT>",
 | 
				
			||||||
 | 
					                    furi_string_get_cstr(args));
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        device = subghz_cli_command_get_device(&device_ind);
 | 
				
			||||||
 | 
					        if(device == NULL) {
 | 
				
			||||||
 | 
					            printf("subghz tx_from_file: \033[0;31mError device not found\033[0m\r\n");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!flipper_format_file_open_existing(fff_data_file, furi_string_get_cstr(file_name))) {
 | 
				
			||||||
 | 
					            printf(
 | 
				
			||||||
 | 
					                "subghz tx_from_file: \033[0;31mError open file\033[0m %s\r\n",
 | 
				
			||||||
 | 
					                furi_string_get_cstr(file_name));
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
 | 
				
			||||||
 | 
					            printf("subghz tx_from_file: \033[0;31mMissing or incorrect header\033[0m\r\n");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(((!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) ||
 | 
				
			||||||
 | 
					            (!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) &&
 | 
				
			||||||
 | 
					           temp_data32 == SUBGHZ_KEY_FILE_VERSION) {
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            printf("subghz tx_from_file: \033[0;31mType or version mismatch\033[0m\r\n");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //Load frequency
 | 
				
			||||||
 | 
					        if(!flipper_format_read_uint32(fff_data_file, "Frequency", &frequency, 1)) {
 | 
				
			||||||
 | 
					            printf("subghz tx_from_file: \033[0;31mMissing Frequency\033[0m\r\n");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!subghz_devices_is_frequency_valid(device, frequency)) {
 | 
				
			||||||
 | 
					            printf("subghz tx_from_file: \033[0;31mFrequency not supported\033[0m\r\n");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //Load preset
 | 
				
			||||||
 | 
					        if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
 | 
				
			||||||
 | 
					            printf("subghz tx_from_file: \033[0;31mMissing Preset\033[0m\r\n");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subghz_devices_begin(device);
 | 
				
			||||||
 | 
					        subghz_devices_reset(device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) {
 | 
				
			||||||
 | 
					            uint8_t* custom_preset_data;
 | 
				
			||||||
 | 
					            uint32_t custom_preset_data_size;
 | 
				
			||||||
 | 
					            if(!flipper_format_get_value_count(fff_data_file, "Custom_preset_data", &temp_data32))
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            if(!temp_data32 || (temp_data32 % 2)) {
 | 
				
			||||||
 | 
					                printf("subghz tx_from_file: \033[0;31mCustom_preset_data size error\033[0m\r\n");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            custom_preset_data_size = sizeof(uint8_t) * temp_data32;
 | 
				
			||||||
 | 
					            custom_preset_data = malloc(custom_preset_data_size);
 | 
				
			||||||
 | 
					            if(!flipper_format_read_hex(
 | 
				
			||||||
 | 
					                   fff_data_file,
 | 
				
			||||||
 | 
					                   "Custom_preset_data",
 | 
				
			||||||
 | 
					                   custom_preset_data,
 | 
				
			||||||
 | 
					                   custom_preset_data_size)) {
 | 
				
			||||||
 | 
					                printf("subghz tx_from_file: \033[0;31mCustom_preset_data read error\033[0m\r\n");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            subghz_devices_load_preset(
 | 
				
			||||||
 | 
					                device,
 | 
				
			||||||
 | 
					                subghz_cli_get_preset_name(furi_string_get_cstr(temp_str)),
 | 
				
			||||||
 | 
					                custom_preset_data);
 | 
				
			||||||
 | 
					            free(custom_preset_data);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            subghz_devices_load_preset(
 | 
				
			||||||
 | 
					                device, subghz_cli_get_preset_name(furi_string_get_cstr(temp_str)), NULL);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subghz_devices_set_frequency(device, frequency);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //Load protocol
 | 
				
			||||||
 | 
					        if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
 | 
				
			||||||
 | 
					            printf("subghz tx_from_file: \033[0;31mMissing protocol\033[0m\r\n");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        SubGhzProtocolStatus status;
 | 
				
			||||||
 | 
					        bool is_init_protocol = true;
 | 
				
			||||||
 | 
					        if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { // if RAW protocol
 | 
				
			||||||
 | 
					            subghz_protocol_raw_gen_fff_data(
 | 
				
			||||||
 | 
					                fff_data_raw, furi_string_get_cstr(file_name), subghz_devices_get_name(device));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            transmitter =
 | 
				
			||||||
 | 
					                subghz_transmitter_alloc_init(environment, furi_string_get_cstr(temp_str));
 | 
				
			||||||
 | 
					            if(transmitter == NULL) {
 | 
				
			||||||
 | 
					                printf("subghz tx_from_file: \033[0;31mError transmitter\033[0m\r\n");
 | 
				
			||||||
 | 
					                is_init_protocol = false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(is_init_protocol) {
 | 
				
			||||||
 | 
					                status = subghz_transmitter_deserialize(transmitter, fff_data_raw);
 | 
				
			||||||
 | 
					                if(status != SubGhzProtocolStatusOk) {
 | 
				
			||||||
 | 
					                    printf(
 | 
				
			||||||
 | 
					                        "subghz tx_from_file: \033[0;31mError deserialize protocol\033[0m %d\r\n",
 | 
				
			||||||
 | 
					                        status);
 | 
				
			||||||
 | 
					                    is_init_protocol = false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else { //if not RAW protocol
 | 
				
			||||||
 | 
					            flipper_format_insert_or_update_uint32(fff_data_file, "Repeat", &repeat, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            transmitter =
 | 
				
			||||||
 | 
					                subghz_transmitter_alloc_init(environment, furi_string_get_cstr(temp_str));
 | 
				
			||||||
 | 
					            if(transmitter == NULL) {
 | 
				
			||||||
 | 
					                printf("subghz tx_from_file: \033[0;31mError transmitter\033[0m\r\n");
 | 
				
			||||||
 | 
					                is_init_protocol = false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(is_init_protocol) {
 | 
				
			||||||
 | 
					                status = subghz_transmitter_deserialize(transmitter, fff_data_file);
 | 
				
			||||||
 | 
					                if(status != SubGhzProtocolStatusOk) {
 | 
				
			||||||
 | 
					                    printf(
 | 
				
			||||||
 | 
					                        "subghz tx_from_file: \033[0;31mError deserialize protocol\033[0m %d\r\n",
 | 
				
			||||||
 | 
					                        status);
 | 
				
			||||||
 | 
					                    is_init_protocol = false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            flipper_format_delete_key(fff_data_file, "Repeat");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(is_init_protocol) {
 | 
				
			||||||
 | 
					            check_file = true;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            subghz_devices_sleep(device);
 | 
				
			||||||
 | 
					            subghz_devices_end(device);
 | 
				
			||||||
 | 
					            subghz_transmitter_free(transmitter);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } while(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flipper_format_free(fff_data_file);
 | 
				
			||||||
 | 
					    furi_record_close(RECORD_STORAGE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(check_file) {
 | 
				
			||||||
 | 
					        furi_hal_power_suppress_charge_enter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        printf(
 | 
				
			||||||
 | 
					            "Listening at \033[0;33m%s\033[0m. Frequency=%lu, Protocol=%s\r\n\r\nPress CTRL+C to stop\r\n\r\n",
 | 
				
			||||||
 | 
					            furi_string_get_cstr(file_name),
 | 
				
			||||||
 | 
					            frequency,
 | 
				
			||||||
 | 
					            furi_string_get_cstr(temp_str));
 | 
				
			||||||
 | 
					        do {
 | 
				
			||||||
 | 
					            //delay in downloading files and other preparatory processes
 | 
				
			||||||
 | 
					            furi_delay_ms(200);
 | 
				
			||||||
 | 
					            if(subghz_devices_start_async_tx(device, subghz_transmitter_yield, transmitter)) {
 | 
				
			||||||
 | 
					                while(
 | 
				
			||||||
 | 
					                    !(subghz_devices_is_async_complete_tx(device) ||
 | 
				
			||||||
 | 
					                      cli_cmd_interrupt_received(cli))) {
 | 
				
			||||||
 | 
					                    printf(".");
 | 
				
			||||||
 | 
					                    fflush(stdout);
 | 
				
			||||||
 | 
					                    furi_delay_ms(333);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                subghz_devices_stop_async_tx(device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                printf("Transmission on this frequency is restricted in your region\r\n");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) {
 | 
				
			||||||
 | 
					                subghz_transmitter_stop(transmitter);
 | 
				
			||||||
 | 
					                repeat--;
 | 
				
			||||||
 | 
					                if(!cli_cmd_interrupt_received(cli) && repeat)
 | 
				
			||||||
 | 
					                    subghz_transmitter_deserialize(transmitter, fff_data_raw);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } while(!cli_cmd_interrupt_received(cli) &&
 | 
				
			||||||
 | 
					                (repeat && !strcmp(furi_string_get_cstr(temp_str), "RAW")));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subghz_devices_sleep(device);
 | 
				
			||||||
 | 
					        subghz_devices_end(device);
 | 
				
			||||||
 | 
					        subghz_cli_radio_device_power_off();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        furi_hal_power_suppress_charge_exit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subghz_transmitter_free(transmitter);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    flipper_format_free(fff_data_raw);
 | 
				
			||||||
 | 
					    furi_string_free(file_name);
 | 
				
			||||||
 | 
					    furi_string_free(temp_str);
 | 
				
			||||||
 | 
					    subghz_devices_deinit();
 | 
				
			||||||
 | 
					    subghz_environment_free(environment);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void subghz_cli_command_print_usage() {
 | 
					static void subghz_cli_command_print_usage() {
 | 
				
			||||||
    printf("Usage:\r\n");
 | 
					    printf("Usage:\r\n");
 | 
				
			||||||
    printf("subghz <cmd> <args>\r\n");
 | 
					    printf("subghz <cmd> <args>\r\n");
 | 
				
			||||||
@ -592,11 +843,13 @@ static void subghz_cli_command_print_usage() {
 | 
				
			|||||||
    printf("\trx <frequency:in Hz> <device: 0 - CC1101_INT, 1 - CC1101_EXT>\t - Receive\r\n");
 | 
					    printf("\trx <frequency:in Hz> <device: 0 - CC1101_INT, 1 - CC1101_EXT>\t - Receive\r\n");
 | 
				
			||||||
    printf("\trx_raw <frequency:in Hz>\t - Receive RAW\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");
 | 
					    printf("\tdecode_raw <file_name: path_RAW_file>\t - Testing\r\n");
 | 
				
			||||||
 | 
					    printf(
 | 
				
			||||||
 | 
					        "\ttx_from_file <file_name: path_file> <repeat: count> <device: 0 - CC1101_INT, 1 - CC1101_EXT>\t - Transmitting from file\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
 | 
					    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
 | 
				
			||||||
        printf("\r\n");
 | 
					        printf("\r\n");
 | 
				
			||||||
        printf("  debug cmd:\r\n");
 | 
					        printf("  debug cmd:\r\n");
 | 
				
			||||||
        printf("\ttx_carrier <frequency:in Hz>\t - Transmit carrier\r\n");
 | 
					        printf("\ttx_carrier <frequency:in Hz>\t - Transmitting carrier\r\n");
 | 
				
			||||||
        printf("\trx_carrier <frequency:in Hz>\t - Receive carrier\r\n");
 | 
					        printf("\trx_carrier <frequency:in Hz>\t - Receive carrier\r\n");
 | 
				
			||||||
        printf(
 | 
					        printf(
 | 
				
			||||||
            "\tencrypt_keeloq <path_decrypted_file> <path_encrypted_file> <IV:16 bytes in hex>\t - Encrypt keeloq manufacture keys\r\n");
 | 
					            "\tencrypt_keeloq <path_decrypted_file> <path_encrypted_file> <IV:16 bytes in hex>\t - Encrypt keeloq manufacture keys\r\n");
 | 
				
			||||||
@ -915,6 +1168,11 @@ static void subghz_cli_command(Cli* cli, FuriString* args, void* context) {
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(furi_string_cmp_str(cmd, "tx_from_file") == 0) {
 | 
				
			||||||
 | 
					            subghz_cli_command_tx_from_file(cli, args, context);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
 | 
					        if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
 | 
				
			||||||
            if(furi_string_cmp_str(cmd, "encrypt_keeloq") == 0) {
 | 
					            if(furi_string_cmp_str(cmd, "encrypt_keeloq") == 0) {
 | 
				
			||||||
                subghz_cli_command_encrypt_keeloq(cli, args);
 | 
					                subghz_cli_command_encrypt_keeloq(cli, args);
 | 
				
			||||||
 | 
				
			|||||||
@ -78,6 +78,20 @@ CC1101Status cc1101_get_status(FuriHalSpiBusHandle* handle) {
 | 
				
			|||||||
    return cc1101_strobe(handle, CC1101_STROBE_SNOP);
 | 
					    return cc1101_strobe(handle, CC1101_STROBE_SNOP);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool cc1101_wait_status_state(FuriHalSpiBusHandle* handle, CC1101State state, uint32_t timeout_us) {
 | 
				
			||||||
 | 
					    bool result = false;
 | 
				
			||||||
 | 
					    CC1101Status status = {0};
 | 
				
			||||||
 | 
					    FuriHalCortexTimer timer = furi_hal_cortex_timer_get(timeout_us);
 | 
				
			||||||
 | 
					    while(!furi_hal_cortex_timer_is_expired(timer)) {
 | 
				
			||||||
 | 
					        status = cc1101_strobe(handle, CC1101_STROBE_SNOP);
 | 
				
			||||||
 | 
					        if(status.STATE == state) {
 | 
				
			||||||
 | 
					            result = true;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CC1101Status cc1101_shutdown(FuriHalSpiBusHandle* handle) {
 | 
					CC1101Status cc1101_shutdown(FuriHalSpiBusHandle* handle) {
 | 
				
			||||||
    return cc1101_strobe(handle, CC1101_STROBE_SPWD);
 | 
					    return cc1101_strobe(handle, CC1101_STROBE_SPWD);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -59,6 +59,16 @@ CC1101Status cc1101_reset(FuriHalSpiBusHandle* handle);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
CC1101Status cc1101_get_status(FuriHalSpiBusHandle* handle);
 | 
					CC1101Status cc1101_get_status(FuriHalSpiBusHandle* handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Wait specific chip state
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param      handle      The SPI bus handle
 | 
				
			||||||
 | 
					 * @param[in]  state       The state to wait
 | 
				
			||||||
 | 
					 * @param[in]  timeout_us  The timeout in microseconds
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return     true on success, false otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool cc1101_wait_status_state(FuriHalSpiBusHandle* handle, CC1101State state, uint32_t timeout_us);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Enable shutdown mode
 | 
					/** Enable shutdown mode
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param      handle  - pointer to FuriHalSpiHandle
 | 
					 * @param      handle  - pointer to FuriHalSpiHandle
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@
 | 
				
			|||||||
#include <furi_hal_os.h>
 | 
					#include <furi_hal_os.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <furi.h>
 | 
					#include <furi.h>
 | 
				
			||||||
 | 
					#include <FreeRTOS.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stm32wbxx.h>
 | 
					#include <stm32wbxx.h>
 | 
				
			||||||
#include <stm32wbxx_ll_tim.h>
 | 
					#include <stm32wbxx_ll_tim.h>
 | 
				
			||||||
@ -10,7 +11,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define TAG "FuriHalInterrupt"
 | 
					#define TAG "FuriHalInterrupt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define FURI_HAL_INTERRUPT_DEFAULT_PRIORITY 5
 | 
					#define FURI_HAL_INTERRUPT_DEFAULT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    FuriHalInterruptISR isr;
 | 
					    FuriHalInterruptISR isr;
 | 
				
			||||||
 | 
				
			|||||||
@ -36,7 +36,6 @@ typedef enum {
 | 
				
			|||||||
    SubGhzStateAsyncRx, /**< Async RX started */
 | 
					    SubGhzStateAsyncRx, /**< Async RX started */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SubGhzStateAsyncTx, /**< Async TX started, DMA and timer is on */
 | 
					    SubGhzStateAsyncTx, /**< Async TX started, DMA and timer is on */
 | 
				
			||||||
    SubGhzStateAsyncTxEnd, /**< Async TX complete, cleanup needed */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
} SubGhzState;
 | 
					} SubGhzState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -277,12 +276,16 @@ void furi_hal_subghz_reset() {
 | 
				
			|||||||
void furi_hal_subghz_idle() {
 | 
					void furi_hal_subghz_idle() {
 | 
				
			||||||
    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
 | 
					    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
    cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
 | 
					    cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
 | 
					    //waiting for the chip to switch to IDLE mode
 | 
				
			||||||
 | 
					    furi_check(cc1101_wait_status_state(&furi_hal_spi_bus_handle_subghz, CC1101StateIDLE, 10000));
 | 
				
			||||||
    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 | 
					    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void furi_hal_subghz_rx() {
 | 
					void furi_hal_subghz_rx() {
 | 
				
			||||||
    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
 | 
					    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
    cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz);
 | 
					    cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
 | 
					    //waiting for the chip to switch to Rx mode
 | 
				
			||||||
 | 
					    furi_check(cc1101_wait_status_state(&furi_hal_spi_bus_handle_subghz, CC1101StateRX, 10000));
 | 
				
			||||||
    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 | 
					    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -290,6 +293,8 @@ bool furi_hal_subghz_tx() {
 | 
				
			|||||||
    if(furi_hal_subghz.regulation != SubGhzRegulationTxRx) return false;
 | 
					    if(furi_hal_subghz.regulation != SubGhzRegulationTxRx) return false;
 | 
				
			||||||
    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
 | 
					    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
    cc1101_switch_to_tx(&furi_hal_spi_bus_handle_subghz);
 | 
					    cc1101_switch_to_tx(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
 | 
					    //waiting for the chip to switch to Tx mode
 | 
				
			||||||
 | 
					    furi_check(cc1101_wait_status_state(&furi_hal_spi_bus_handle_subghz, CC1101StateTX, 10000));
 | 
				
			||||||
    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 | 
					    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -352,10 +357,7 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
 | 
				
			|||||||
    uint32_t real_frequency = cc1101_set_frequency(&furi_hal_spi_bus_handle_subghz, value);
 | 
					    uint32_t real_frequency = cc1101_set_frequency(&furi_hal_spi_bus_handle_subghz, value);
 | 
				
			||||||
    cc1101_calibrate(&furi_hal_spi_bus_handle_subghz);
 | 
					    cc1101_calibrate(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while(true) {
 | 
					    furi_check(cc1101_wait_status_state(&furi_hal_spi_bus_handle_subghz, CC1101StateIDLE, 10000));
 | 
				
			||||||
        CC1101Status status = cc1101_get_status(&furi_hal_spi_bus_handle_subghz);
 | 
					 | 
				
			||||||
        if(status.STATE == CC1101StateIDLE) break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 | 
					    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 | 
				
			||||||
    return real_frequency;
 | 
					    return real_frequency;
 | 
				
			||||||
@ -624,7 +626,6 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
 | 
				
			|||||||
            if(LL_DMA_IsActiveFlag_TC1(SUBGHZ_DMA)) {
 | 
					            if(LL_DMA_IsActiveFlag_TC1(SUBGHZ_DMA)) {
 | 
				
			||||||
                LL_DMA_ClearFlag_TC1(SUBGHZ_DMA);
 | 
					                LL_DMA_ClearFlag_TC1(SUBGHZ_DMA);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            LL_TIM_EnableIT_UPDATE(TIM2);
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            // Lowest possible value is 2us
 | 
					            // Lowest possible value is 2us
 | 
				
			||||||
@ -666,21 +667,6 @@ static void furi_hal_subghz_async_tx_dma_isr() {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void furi_hal_subghz_async_tx_timer_isr() {
 | 
					 | 
				
			||||||
    if(LL_TIM_IsActiveFlag_UPDATE(TIM2)) {
 | 
					 | 
				
			||||||
        LL_TIM_ClearFlag_UPDATE(TIM2);
 | 
					 | 
				
			||||||
        if(LL_TIM_GetAutoReload(TIM2) == 0) {
 | 
					 | 
				
			||||||
            if(furi_hal_subghz.state == SubGhzStateAsyncTx) {
 | 
					 | 
				
			||||||
                furi_hal_subghz.state = SubGhzStateAsyncTxEnd;
 | 
					 | 
				
			||||||
                LL_DMA_DisableChannel(SUBGHZ_DMA_CH1_DEF);
 | 
					 | 
				
			||||||
                //forcibly pulls the pin to the ground so that there is no carrier
 | 
					 | 
				
			||||||
                furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
 | 
					 | 
				
			||||||
                LL_TIM_DisableCounter(TIM2);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* context) {
 | 
					bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* context) {
 | 
				
			||||||
    furi_assert(furi_hal_subghz.state == SubGhzStateIdle);
 | 
					    furi_assert(furi_hal_subghz.state == SubGhzStateIdle);
 | 
				
			||||||
    furi_assert(callback);
 | 
					    furi_assert(callback);
 | 
				
			||||||
@ -701,7 +687,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Connect CC1101_GD0 to TIM2 as output
 | 
					    // Connect CC1101_GD0 to TIM2 as output
 | 
				
			||||||
    furi_hal_gpio_init_ex(
 | 
					    furi_hal_gpio_init_ex(
 | 
				
			||||||
        &gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn1TIM2);
 | 
					        &gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Configure DMA
 | 
					    // Configure DMA
 | 
				
			||||||
    LL_DMA_InitTypeDef dma_config = {0};
 | 
					    LL_DMA_InitTypeDef dma_config = {0};
 | 
				
			||||||
@ -715,7 +701,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
 | 
				
			|||||||
    dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
 | 
					    dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
 | 
				
			||||||
    dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL;
 | 
					    dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL;
 | 
				
			||||||
    dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
 | 
					    dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
 | 
				
			||||||
    dma_config.Priority = LL_DMA_MODE_NORMAL;
 | 
					    dma_config.Priority =
 | 
				
			||||||
 | 
					        LL_DMA_PRIORITY_VERYHIGH; // Ensure that ARR is updated before anyone else try to check it
 | 
				
			||||||
    LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config);
 | 
					    LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config);
 | 
				
			||||||
    furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, furi_hal_subghz_async_tx_dma_isr, NULL);
 | 
					    furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, furi_hal_subghz_async_tx_dma_isr, NULL);
 | 
				
			||||||
    LL_DMA_EnableIT_TC(SUBGHZ_DMA_CH1_DEF);
 | 
					    LL_DMA_EnableIT_TC(SUBGHZ_DMA_CH1_DEF);
 | 
				
			||||||
@ -743,8 +730,6 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
 | 
				
			|||||||
    LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2);
 | 
					    LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2);
 | 
				
			||||||
    LL_TIM_DisableMasterSlaveMode(TIM2);
 | 
					    LL_TIM_DisableMasterSlaveMode(TIM2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_subghz_async_tx_timer_isr, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    furi_hal_subghz_async_tx_middleware_idle(&furi_hal_subghz_async_tx.middleware);
 | 
					    furi_hal_subghz_async_tx_middleware_idle(&furi_hal_subghz_async_tx.middleware);
 | 
				
			||||||
    furi_hal_subghz_async_tx_refill(
 | 
					    furi_hal_subghz_async_tx_refill(
 | 
				
			||||||
        furi_hal_subghz_async_tx.buffer, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL);
 | 
					        furi_hal_subghz_async_tx.buffer, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL);
 | 
				
			||||||
@ -752,15 +737,6 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
 | 
				
			|||||||
    LL_TIM_EnableDMAReq_UPDATE(TIM2);
 | 
					    LL_TIM_EnableDMAReq_UPDATE(TIM2);
 | 
				
			||||||
    LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2);
 | 
					    LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Start counter
 | 
					 | 
				
			||||||
#ifdef FURI_HAL_SUBGHZ_TX_GPIO
 | 
					 | 
				
			||||||
    furi_hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, true);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    furi_hal_subghz_tx();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    LL_TIM_SetCounter(TIM2, 0);
 | 
					 | 
				
			||||||
    LL_TIM_EnableCounter(TIM2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Start debug
 | 
					    // Start debug
 | 
				
			||||||
    if(furi_hal_subghz_start_debug()) {
 | 
					    if(furi_hal_subghz_start_debug()) {
 | 
				
			||||||
        const GpioPin* gpio = furi_hal_subghz.async_mirror_pin;
 | 
					        const GpioPin* gpio = furi_hal_subghz.async_mirror_pin;
 | 
				
			||||||
@ -777,30 +753,36 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
 | 
				
			|||||||
        dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
 | 
					        dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
 | 
				
			||||||
        dma_config.NbData = 2;
 | 
					        dma_config.NbData = 2;
 | 
				
			||||||
        dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
 | 
					        dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
 | 
				
			||||||
        dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH;
 | 
					        dma_config.Priority = LL_DMA_PRIORITY_HIGH; // Ensure that it's updated after ARR
 | 
				
			||||||
        LL_DMA_Init(SUBGHZ_DMA_CH2_DEF, &dma_config);
 | 
					        LL_DMA_Init(SUBGHZ_DMA_CH2_DEF, &dma_config);
 | 
				
			||||||
        LL_DMA_SetDataLength(SUBGHZ_DMA_CH2_DEF, 2);
 | 
					        LL_DMA_SetDataLength(SUBGHZ_DMA_CH2_DEF, 2);
 | 
				
			||||||
        LL_DMA_EnableChannel(SUBGHZ_DMA_CH2_DEF);
 | 
					        LL_DMA_EnableChannel(SUBGHZ_DMA_CH2_DEF);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start counter
 | 
				
			||||||
 | 
					#ifdef FURI_HAL_SUBGHZ_TX_GPIO
 | 
				
			||||||
 | 
					    furi_hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, true);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    furi_hal_subghz_tx();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LL_TIM_SetCounter(TIM2, 0);
 | 
				
			||||||
 | 
					    LL_TIM_EnableCounter(TIM2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool furi_hal_subghz_is_async_tx_complete() {
 | 
					bool furi_hal_subghz_is_async_tx_complete() {
 | 
				
			||||||
    return furi_hal_subghz.state == SubGhzStateAsyncTxEnd;
 | 
					    return (furi_hal_subghz.state == SubGhzStateAsyncTx) && (LL_TIM_GetAutoReload(TIM2) == 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void furi_hal_subghz_stop_async_tx() {
 | 
					void furi_hal_subghz_stop_async_tx() {
 | 
				
			||||||
    furi_assert(
 | 
					    furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx);
 | 
				
			||||||
        furi_hal_subghz.state == SubGhzStateAsyncTx ||
 | 
					 | 
				
			||||||
        furi_hal_subghz.state == SubGhzStateAsyncTxEnd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Deinitialize GPIO
 | 
					 | 
				
			||||||
    // Keep in mind that cc1101 will try to pull it up in idle.
 | 
					 | 
				
			||||||
    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Shutdown radio
 | 
					    // Shutdown radio
 | 
				
			||||||
    furi_hal_subghz_idle();
 | 
					    furi_hal_subghz_idle();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Deinitialize GPIO
 | 
				
			||||||
 | 
					    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
 | 
				
			||||||
#ifdef FURI_HAL_SUBGHZ_TX_GPIO
 | 
					#ifdef FURI_HAL_SUBGHZ_TX_GPIO
 | 
				
			||||||
    furi_hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, false);
 | 
					    furi_hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, false);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user