FuriHal: fix start duration furi_hal_subghz_async_tx (#3230)
* FuriHal: fix start duration furi_hal_subghz_async_tx * FuriHal: add check min duration arr for the first level * FuriHal: fix conflict dev * SubGhz: fix unit_test * FuriHal: subghz internal fix start/stop transmit duration * Drivers: subghz external fix start/stop transmit duration * FuriHal: subghz optimization * SubGhz: fix unit_test subghz * FuriHal: subghz fix end duration if size == size dma buf * FuriHal: revert enum values order, remove garbage * FuriHal: revert one more small bit in subghz * FuriHal: handle various corner cases in subghz transmission * FuriHal: cleanup subghz code * FuriHal: add parenthesis around value in subghz defines * FuriHal: add packer subghz_async_tx * FuriHal: more reliable subghz transmission end handling, fixes stuck transmission * FuriHal: add subghz crutch docs, and rename some defines to conform naming standards * FuriHal: subghz, the logic of timers has been changed. disabling the shadow register ARR * FuriHal: fix subghz off dma irq * SubGhzExt: fun rename * FuriHal,SubGhz: fix g0 state on reset, fix incorrect async_tx stop sequence, remove dead code. Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									0b15fc3807
								
							
						
					
					
						commit
						34539cda17
					
				| @ -231,17 +231,17 @@ typedef struct { | |||||||
|     size_t pos; |     size_t pos; | ||||||
| } SubGhzHalAsyncTxTest; | } SubGhzHalAsyncTxTest; | ||||||
| 
 | 
 | ||||||
| #define SUBGHZ_HAL_TEST_DURATION 1 | #define SUBGHZ_HAL_TEST_DURATION 3 | ||||||
| 
 | 
 | ||||||
| static LevelDuration subghz_hal_async_tx_test_yield(void* context) { | static LevelDuration subghz_hal_async_tx_test_yield(void* context) { | ||||||
|     SubGhzHalAsyncTxTest* test = context; |     SubGhzHalAsyncTxTest* test = context; | ||||||
|     bool is_odd = test->pos % 2; |     bool is_odd = test->pos % 2; | ||||||
| 
 | 
 | ||||||
|     if(test->type == SubGhzHalAsyncTxTestTypeNormal) { |     if(test->type == SubGhzHalAsyncTxTestTypeNormal) { | ||||||
|         if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { |         if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); |             return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); | ||||||
|         } else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { |         } else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_reset(); |             return level_duration_reset(); | ||||||
|         } else { |         } else { | ||||||
| @ -251,36 +251,36 @@ static LevelDuration subghz_hal_async_tx_test_yield(void* context) { | |||||||
|         if(test->pos == 0) { |         if(test->pos == 0) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION); |             return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION); | ||||||
|         } else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { |         } else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); |             return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); | ||||||
|         } else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { |         } else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_reset(); |             return level_duration_reset(); | ||||||
|         } else { |         } else { | ||||||
|             furi_crash("Yield after reset"); |             furi_crash("Yield after reset"); | ||||||
|         } |         } | ||||||
|     } else if(test->type == SubGhzHalAsyncTxTestTypeInvalidMid) { |     } else if(test->type == SubGhzHalAsyncTxTestTypeInvalidMid) { | ||||||
|         if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) { |         if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION); |             return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION); | ||||||
|         } else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { |         } else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); |             return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); | ||||||
|         } else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { |         } else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_reset(); |             return level_duration_reset(); | ||||||
|         } else { |         } else { | ||||||
|             furi_crash("Yield after reset"); |             furi_crash("Yield after reset"); | ||||||
|         } |         } | ||||||
|     } else if(test->type == SubGhzHalAsyncTxTestTypeInvalidEnd) { |     } else if(test->type == SubGhzHalAsyncTxTestTypeInvalidEnd) { | ||||||
|         if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) { |         if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION); |             return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION); | ||||||
|         } else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { |         } else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); |             return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); | ||||||
|         } else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { |         } else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_reset(); |             return level_duration_reset(); | ||||||
|         } else { |         } else { | ||||||
| @ -294,20 +294,20 @@ static LevelDuration subghz_hal_async_tx_test_yield(void* context) { | |||||||
|             furi_crash("Yield after reset"); |             furi_crash("Yield after reset"); | ||||||
|         } |         } | ||||||
|     } else if(test->type == SubGhzHalAsyncTxTestTypeResetMid) { |     } else if(test->type == SubGhzHalAsyncTxTestTypeResetMid) { | ||||||
|         if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) { |         if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); |             return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); | ||||||
|         } else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) { |         } else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_reset(); |             return level_duration_reset(); | ||||||
|         } else { |         } else { | ||||||
|             furi_crash("Yield after reset"); |             furi_crash("Yield after reset"); | ||||||
|         } |         } | ||||||
|     } else if(test->type == SubGhzHalAsyncTxTestTypeResetEnd) { |     } else if(test->type == SubGhzHalAsyncTxTestTypeResetEnd) { | ||||||
|         if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) { |         if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); |             return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); | ||||||
|         } else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) { |         } else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL) { | ||||||
|             test->pos++; |             test->pos++; | ||||||
|             return level_duration_reset(); |             return level_duration_reset(); | ||||||
|         } else { |         } else { | ||||||
| @ -334,6 +334,8 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) { | |||||||
| 
 | 
 | ||||||
|     while(!furi_hal_subghz_is_async_tx_complete()) { |     while(!furi_hal_subghz_is_async_tx_complete()) { | ||||||
|         if(furi_hal_cortex_timer_is_expired(timer)) { |         if(furi_hal_cortex_timer_is_expired(timer)) { | ||||||
|  |             furi_hal_subghz_stop_async_tx(); | ||||||
|  |             furi_hal_subghz_sleep(); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         furi_delay_ms(10); |         furi_delay_ms(10); | ||||||
|  | |||||||
| @ -18,14 +18,14 @@ | |||||||
| 
 | 
 | ||||||
| #define TAG "SubGhzDeviceCc1101Ext" | #define TAG "SubGhzDeviceCc1101Ext" | ||||||
| 
 | 
 | ||||||
| #define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO &gpio_ext_pb2 | #define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO (&gpio_ext_pb2) | ||||||
| 
 | 
 | ||||||
| /* DMA Channels definition */ | /* DMA Channels definition */ | ||||||
| #define SUBGHZ_DEVICE_CC1101_EXT_DMA DMA2 | #define SUBGHZ_DEVICE_CC1101_EXT_DMA (DMA2) | ||||||
| #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL LL_DMA_CHANNEL_3 | #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL (LL_DMA_CHANNEL_3) | ||||||
| #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL LL_DMA_CHANNEL_4 | #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL (LL_DMA_CHANNEL_4) | ||||||
| #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL LL_DMA_CHANNEL_5 | #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL (LL_DMA_CHANNEL_5) | ||||||
| #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ FuriHalInterruptIdDma2Ch3 | #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ (FuriHalInterruptIdDma2Ch3) | ||||||
| #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF \ | #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF \ | ||||||
|     SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL |     SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL | ||||||
| #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF \ | #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF \ | ||||||
| @ -34,10 +34,10 @@ | |||||||
|     SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL |     SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL | ||||||
| 
 | 
 | ||||||
| /** Low level buffer dimensions and guard times */ | /** Low level buffer dimensions and guard times */ | ||||||
| #define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL (256) | #define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL (256u) | ||||||
| #define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF \ | #define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF \ | ||||||
|     (SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL / 2) |     (SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL / 2) | ||||||
| #define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME 999 << 1 | #define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME (999u >> 1) | ||||||
| 
 | 
 | ||||||
| /** SubGhz state */ | /** SubGhz state */ | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -55,13 +55,25 @@ typedef enum { | |||||||
|     SubGhzDeviceCC1101ExtRegulationTxRx, /**TxRx*/ |     SubGhzDeviceCC1101ExtRegulationTxRx, /**TxRx*/ | ||||||
| } SubGhzDeviceCC1101ExtRegulation; | } SubGhzDeviceCC1101ExtRegulation; | ||||||
| 
 | 
 | ||||||
|  | typedef enum { | ||||||
|  |     SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateIdle, | ||||||
|  |     SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateReset, | ||||||
|  |     SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateRun, | ||||||
|  | } SubGhzDeviceCC1101ExtAsyncTxMiddlewareState; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     SubGhzDeviceCC1101ExtAsyncTxMiddlewareState state; | ||||||
|  |     bool is_odd_level; | ||||||
|  |     uint32_t adder_duration; | ||||||
|  | } SubGhzDeviceCC1101ExtAsyncTxMiddleware; | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint32_t* buffer; |     uint32_t* buffer; | ||||||
|     LevelDuration carry_ld; |  | ||||||
|     SubGhzDeviceCC1101ExtCallback callback; |     SubGhzDeviceCC1101ExtCallback callback; | ||||||
|     void* callback_context; |     void* callback_context; | ||||||
|     uint32_t gpio_tx_buff[2]; |     uint32_t gpio_tx_buff[2]; | ||||||
|     uint32_t debug_gpio_buff[2]; |     uint32_t debug_gpio_buff[2]; | ||||||
|  |     SubGhzDeviceCC1101ExtAsyncTxMiddleware middleware; | ||||||
| } SubGhzDeviceCC1101ExtAsyncTx; | } SubGhzDeviceCC1101ExtAsyncTx; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| @ -259,8 +271,8 @@ void subghz_device_cc1101_ext_dump_state() { | |||||||
| 
 | 
 | ||||||
| void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) { | void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) { | ||||||
|     //load config
 |     //load config
 | ||||||
|  |     subghz_device_cc1101_ext_reset(); | ||||||
|     furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); |     furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); | ||||||
|     cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); |  | ||||||
|     uint32_t i = 0; |     uint32_t i = 0; | ||||||
|     uint8_t pa[8] = {0}; |     uint8_t pa[8] = {0}; | ||||||
|     while(preset_data[i]) { |     while(preset_data[i]) { | ||||||
| @ -289,8 +301,8 @@ void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_device_cc1101_ext_load_registers(const uint8_t* data) { | void subghz_device_cc1101_ext_load_registers(const uint8_t* data) { | ||||||
|  |     subghz_device_cc1101_ext_reset(); | ||||||
|     furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); |     furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); | ||||||
|     cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); |  | ||||||
|     uint32_t i = 0; |     uint32_t i = 0; | ||||||
|     while(data[i]) { |     while(data[i]) { | ||||||
|         cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, data[i], data[i + 1]); |         cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, data[i], data[i + 1]); | ||||||
| @ -371,6 +383,7 @@ void subghz_device_cc1101_ext_reset() { | |||||||
|     furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); |     furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||||
|     cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle); |     cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle); | ||||||
|     cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); |     cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); | ||||||
|  |     // Warning: push pull cc1101 clock output on GD0
 | ||||||
|     cc1101_write_reg( |     cc1101_write_reg( | ||||||
|         subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); |         subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); | ||||||
|     furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); |     furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); | ||||||
| @ -563,50 +576,91 @@ void subghz_device_cc1101_ext_stop_async_rx() { | |||||||
|     furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); |     furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t samples) { | void subghz_device_cc1101_ext_async_tx_middleware_idle( | ||||||
|     furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx); |     SubGhzDeviceCC1101ExtAsyncTxMiddleware* middleware) { | ||||||
|     while(samples > 0) { |     middleware->state = SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateIdle; | ||||||
|         bool is_odd = samples % 2; |     middleware->is_odd_level = false; | ||||||
|         LevelDuration ld; |     middleware->adder_duration = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME; | ||||||
|         if(level_duration_is_reset(subghz_device_cc1101_ext->async_tx.carry_ld)) { |  | ||||||
|             ld = subghz_device_cc1101_ext->async_tx.callback( |  | ||||||
|                 subghz_device_cc1101_ext->async_tx.callback_context); |  | ||||||
|         } else { |  | ||||||
|             ld = subghz_device_cc1101_ext->async_tx.carry_ld; |  | ||||||
|             subghz_device_cc1101_ext->async_tx.carry_ld = level_duration_reset(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|         if(level_duration_is_wait(ld)) { | static inline uint32_t subghz_device_cc1101_ext_async_tx_middleware_get_duration( | ||||||
|             *buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME; |     SubGhzDeviceCC1101ExtAsyncTxMiddleware* middleware, | ||||||
|             buffer++; |     SubGhzDeviceCC1101ExtCallback callback) { | ||||||
|             samples--; |     uint32_t ret = 0; | ||||||
|         } else if(level_duration_is_reset(ld)) { |     bool is_level = false; | ||||||
|  | 
 | ||||||
|  |     if(middleware->state == SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateReset) return 0; | ||||||
|  | 
 | ||||||
|  |     while(1) { | ||||||
|  |         LevelDuration ld = callback(subghz_device_cc1101_ext->async_tx.callback_context); | ||||||
|  |         if(level_duration_is_reset(ld)) { | ||||||
|  |             middleware->state = SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateReset; | ||||||
|  |             if(!middleware->is_odd_level) { | ||||||
|  |                 return 0; | ||||||
|  |             } else { | ||||||
|  |                 return middleware->adder_duration; | ||||||
|  |             } | ||||||
|  |         } else if(level_duration_is_wait(ld)) { | ||||||
|  |             middleware->is_odd_level = !middleware->is_odd_level; | ||||||
|  |             ret = middleware->adder_duration + SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME; | ||||||
|  |             middleware->adder_duration = 0; | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         is_level = level_duration_get_level(ld); | ||||||
|  | 
 | ||||||
|  |         if(middleware->state == SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateIdle) { | ||||||
|  |             if(is_level != middleware->is_odd_level) { | ||||||
|  |                 middleware->state = SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateRun; | ||||||
|  |                 middleware->is_odd_level = is_level; | ||||||
|  |                 middleware->adder_duration = level_duration_get_duration(ld); | ||||||
|  |                 return SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME; | ||||||
|  |             } else { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(middleware->state == SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateRun) { | ||||||
|  |             if(is_level == middleware->is_odd_level) { | ||||||
|  |                 middleware->adder_duration += level_duration_get_duration(ld); | ||||||
|  |                 continue; | ||||||
|  |             } else { | ||||||
|  |                 middleware->is_odd_level = is_level; | ||||||
|  |                 ret = middleware->adder_duration; | ||||||
|  |                 middleware->adder_duration = level_duration_get_duration(ld); | ||||||
|  |                 return ret; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t samples) { | ||||||
|  |     furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx); | ||||||
|  | 
 | ||||||
|  |     while(samples > 0) { | ||||||
|  |         volatile uint32_t duration = subghz_device_cc1101_ext_async_tx_middleware_get_duration( | ||||||
|  |             &subghz_device_cc1101_ext->async_tx.middleware, | ||||||
|  |             subghz_device_cc1101_ext->async_tx.callback); | ||||||
|  |         if(duration == 0) { | ||||||
|             *buffer = 0; |             *buffer = 0; | ||||||
|             buffer++; |             buffer++; | ||||||
|             samples--; |             samples--; | ||||||
|             LL_DMA_DisableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); |             LL_DMA_DisableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); | ||||||
|             LL_DMA_DisableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); |             LL_DMA_DisableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); | ||||||
|  |             if(LL_DMA_IsActiveFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) { | ||||||
|  |                 LL_DMA_ClearFlag_HT3(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_TIM_EnableIT_UPDATE(TIM17); |             LL_TIM_EnableIT_UPDATE(TIM17); | ||||||
|             break; |             break; | ||||||
|         } else { |         } else { | ||||||
|             bool level = level_duration_get_level(ld); |             // Lowest possible value is 4us
 | ||||||
| 
 |             if(duration < 4) duration = 4; | ||||||
|             // Inject guard time if level is incorrect
 |             // Divide by 2 since timer resolution is 2us
 | ||||||
|             if(is_odd != level) { |             // Subtract 1 since we counting from 0
 | ||||||
|                 *buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME; |             *buffer = (duration >> 1) - 1; | ||||||
|                 buffer++; |  | ||||||
|                 samples--; |  | ||||||
| 
 |  | ||||||
|                 // Special case: prevent buffer overflow if sample is last
 |  | ||||||
|                 if(samples == 0) { |  | ||||||
|                     subghz_device_cc1101_ext->async_tx.carry_ld = ld; |  | ||||||
|                     break; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             uint32_t duration = level_duration_get_duration(ld); |  | ||||||
|             furi_assert(duration > 0); |  | ||||||
|             *buffer = duration >> 1; |  | ||||||
|             buffer++; |             buffer++; | ||||||
|             samples--; |             samples--; | ||||||
|         } |         } | ||||||
| @ -638,12 +692,14 @@ static void subghz_device_cc1101_ext_async_tx_dma_isr() { | |||||||
| static void subghz_device_cc1101_ext_async_tx_timer_isr() { | static void subghz_device_cc1101_ext_async_tx_timer_isr() { | ||||||
|     if(LL_TIM_IsActiveFlag_UPDATE(TIM17)) { |     if(LL_TIM_IsActiveFlag_UPDATE(TIM17)) { | ||||||
|         if(LL_TIM_GetAutoReload(TIM17) == 0) { |         if(LL_TIM_GetAutoReload(TIM17) == 0) { | ||||||
|  |             if(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx) { | ||||||
|                 LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); |                 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); |                 furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false); | ||||||
|                 if(subghz_device_cc1101_ext->async_mirror_pin != NULL) |                 if(subghz_device_cc1101_ext->async_mirror_pin != NULL) | ||||||
|                     furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false); |                     furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false); | ||||||
|                 LL_TIM_DisableCounter(TIM17); |                 LL_TIM_DisableCounter(TIM17); | ||||||
|             subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTxEnd; |             } | ||||||
|         } |         } | ||||||
|         LL_TIM_ClearFlag_UPDATE(TIM17); |         LL_TIM_ClearFlag_UPDATE(TIM17); | ||||||
|     } |     } | ||||||
| @ -693,16 +749,18 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb | |||||||
| 
 | 
 | ||||||
|     // Configure TIM
 |     // Configure TIM
 | ||||||
|     // Set the timer resolution to 2 us
 |     // Set the timer resolution to 2 us
 | ||||||
|     LL_TIM_SetPrescaler(TIM17, (64 << 1) - 1); |  | ||||||
|     LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP); |     LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP); | ||||||
|     LL_TIM_SetAutoReload(TIM17, 0xFFFF); |  | ||||||
|     LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1); |     LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1); | ||||||
|  |     LL_TIM_SetAutoReload(TIM17, 500); | ||||||
|  |     LL_TIM_SetPrescaler(TIM17, (64 << 1) - 1); | ||||||
|     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( |     furi_hal_interrupt_set_isr( | ||||||
|         FuriHalInterruptIdTim1TrgComTim17, subghz_device_cc1101_ext_async_tx_timer_isr, NULL); |         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); | ||||||
|     subghz_device_cc1101_ext_async_tx_refill( |     subghz_device_cc1101_ext_async_tx_refill( | ||||||
|         subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL); |         subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL); | ||||||
| 
 | 
 | ||||||
| @ -748,7 +806,6 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb | |||||||
| 
 | 
 | ||||||
|     // Start counter
 |     // Start counter
 | ||||||
|     LL_TIM_EnableDMAReq_UPDATE(TIM17); |     LL_TIM_EnableDMAReq_UPDATE(TIM17); | ||||||
|     LL_TIM_GenerateEvent_UPDATE(TIM17); |  | ||||||
| 
 | 
 | ||||||
|     subghz_device_cc1101_ext_tx(); |     subghz_device_cc1101_ext_tx(); | ||||||
| 
 | 
 | ||||||
| @ -767,11 +824,15 @@ void subghz_device_cc1101_ext_stop_async_tx() { | |||||||
|         subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx || |         subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx || | ||||||
|         subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd); |         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 Timer
 |     // Deinitialize Timer
 | ||||||
|     FURI_CRITICAL_ENTER(); |  | ||||||
|     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); | ||||||
| 
 | 
 | ||||||
| @ -780,17 +841,11 @@ void subghz_device_cc1101_ext_stop_async_tx() { | |||||||
|     LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF); |     LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF); | ||||||
|     furi_hal_interrupt_set_isr(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, NULL, NULL); |     furi_hal_interrupt_set_isr(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, NULL, NULL); | ||||||
| 
 | 
 | ||||||
|     // 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); |  | ||||||
| 
 |  | ||||||
|     // Stop debug
 |     // Stop debug
 | ||||||
|     if(subghz_device_cc1101_ext_stop_debug()) { |     if(subghz_device_cc1101_ext_stop_debug()) { | ||||||
|         LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF); |         LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     FURI_CRITICAL_EXIT(); |  | ||||||
| 
 |  | ||||||
|     free(subghz_device_cc1101_ext->async_tx.buffer); |     free(subghz_device_cc1101_ext->async_tx.buffer); | ||||||
| 
 | 
 | ||||||
|     subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle; |     subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle; | ||||||
|  | |||||||
| @ -18,7 +18,6 @@ struct SubGhzFileEncoderWorker { | |||||||
| 
 | 
 | ||||||
|     volatile bool worker_running; |     volatile bool worker_running; | ||||||
|     volatile bool worker_stoping; |     volatile bool worker_stoping; | ||||||
|     bool level; |  | ||||||
|     bool is_storage_slow; |     bool is_storage_slow; | ||||||
|     FuriString* str_data; |     FuriString* str_data; | ||||||
|     FuriString* file_path; |     FuriString* file_path; | ||||||
| @ -41,19 +40,8 @@ void subghz_file_encoder_worker_callback_end( | |||||||
| void subghz_file_encoder_worker_add_level_duration( | void subghz_file_encoder_worker_add_level_duration( | ||||||
|     SubGhzFileEncoderWorker* instance, |     SubGhzFileEncoderWorker* instance, | ||||||
|     int32_t duration) { |     int32_t duration) { | ||||||
|     bool res = true; |     size_t ret = furi_stream_buffer_send(instance->stream, &duration, sizeof(int32_t), 100); | ||||||
|     if(duration < 0 && !instance->level) { |     if(sizeof(int32_t) != ret) FURI_LOG_E(TAG, "Invalid add duration in the stream"); | ||||||
|         res = false; |  | ||||||
|     } else if(duration > 0 && instance->level) { |  | ||||||
|         res = false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(res) { |  | ||||||
|         instance->level = !instance->level; |  | ||||||
|         furi_stream_buffer_send(instance->stream, &duration, sizeof(int32_t), 100); |  | ||||||
|     } else { |  | ||||||
|         FURI_LOG_E(TAG, "Invalid level in the stream"); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_file_encoder_worker_data_parse(SubGhzFileEncoderWorker* instance, const char* strStart) { | bool subghz_file_encoder_worker_data_parse(SubGhzFileEncoderWorker* instance, const char* strStart) { | ||||||
| @ -190,7 +178,6 @@ SubGhzFileEncoderWorker* subghz_file_encoder_worker_alloc() { | |||||||
| 
 | 
 | ||||||
|     instance->str_data = furi_string_alloc(); |     instance->str_data = furi_string_alloc(); | ||||||
|     instance->file_path = furi_string_alloc(); |     instance->file_path = furi_string_alloc(); | ||||||
|     instance->level = false; |  | ||||||
|     instance->worker_stoping = true; |     instance->worker_stoping = true; | ||||||
| 
 | 
 | ||||||
|     return instance; |     return instance; | ||||||
|  | |||||||
| @ -17,13 +17,13 @@ | |||||||
| 
 | 
 | ||||||
| #define TAG "FuriHalSubGhz" | #define TAG "FuriHalSubGhz" | ||||||
| 
 | 
 | ||||||
| static uint32_t furi_hal_subghz_debug_gpio_buff[2]; | static uint32_t furi_hal_subghz_debug_gpio_buff[2] = {0}; | ||||||
| 
 | 
 | ||||||
| /* DMA Channels definition */ | /* DMA Channels definition */ | ||||||
| #define SUBGHZ_DMA DMA2 | #define SUBGHZ_DMA (DMA2) | ||||||
| #define SUBGHZ_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 | #define SUBGHZ_DMA_CH1_CHANNEL (LL_DMA_CHANNEL_1) | ||||||
| #define SUBGHZ_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2 | #define SUBGHZ_DMA_CH2_CHANNEL (LL_DMA_CHANNEL_2) | ||||||
| #define SUBGHZ_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1 | #define SUBGHZ_DMA_CH1_IRQ (FuriHalInterruptIdDma2Ch1) | ||||||
| #define SUBGHZ_DMA_CH1_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH1_CHANNEL | #define SUBGHZ_DMA_CH1_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH1_CHANNEL | ||||||
| #define SUBGHZ_DMA_CH2_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH2_CHANNEL | #define SUBGHZ_DMA_CH2_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH2_CHANNEL | ||||||
| 
 | 
 | ||||||
| @ -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 */ | ||||||
|     SubGhzStateAsyncTxLast, /**< Async TX continue, DMA completed and timer got last value to go */ |  | ||||||
|     SubGhzStateAsyncTxEnd, /**< Async TX complete, cleanup needed */ |     SubGhzStateAsyncTxEnd, /**< Async TX complete, cleanup needed */ | ||||||
| 
 | 
 | ||||||
| } SubGhzState; | } SubGhzState; | ||||||
| @ -79,6 +78,10 @@ void furi_hal_subghz_init() { | |||||||
|             &FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); |             &FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef FURI_HAL_SUBGHZ_ASYNC_MIRROR_GPIO | ||||||
|  |         furi_hal_subghz_set_async_mirror_pin(&FURI_HAL_SUBGHZ_ASYNC_MIRROR_GPIO); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|         // Reset
 |         // Reset
 | ||||||
|         furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); |         furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||||
|         cc1101_reset(&furi_hal_spi_bus_handle_subghz); |         cc1101_reset(&furi_hal_spi_bus_handle_subghz); | ||||||
| @ -158,8 +161,8 @@ void furi_hal_subghz_dump_state() { | |||||||
| 
 | 
 | ||||||
| void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data) { | void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data) { | ||||||
|     //load config
 |     //load config
 | ||||||
|  |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); |     furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); | ||||||
|     cc1101_reset(&furi_hal_spi_bus_handle_subghz); |  | ||||||
|     uint32_t i = 0; |     uint32_t i = 0; | ||||||
|     uint8_t pa[8] = {0}; |     uint8_t pa[8] = {0}; | ||||||
|     while(preset_data[i]) { |     while(preset_data[i]) { | ||||||
| @ -187,8 +190,8 @@ void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_subghz_load_registers(const uint8_t* data) { | void furi_hal_subghz_load_registers(const uint8_t* data) { | ||||||
|  |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); |     furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); | ||||||
|     cc1101_reset(&furi_hal_spi_bus_handle_subghz); |  | ||||||
|     uint32_t i = 0; |     uint32_t i = 0; | ||||||
|     while(data[i]) { |     while(data[i]) { | ||||||
|         cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, data[i], data[i + 1]); |         cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, data[i], data[i + 1]); | ||||||
| @ -266,6 +269,7 @@ void furi_hal_subghz_reset() { | |||||||
|     furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); |     furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||||
|     cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz); |     cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz); | ||||||
|     cc1101_reset(&furi_hal_spi_bus_handle_subghz); |     cc1101_reset(&furi_hal_spi_bus_handle_subghz); | ||||||
|  |     // Warning: push pull cc1101 clock output on GD0
 | ||||||
|     cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); |     cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); | ||||||
|     furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); |     furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); | ||||||
| } | } | ||||||
| @ -382,6 +386,7 @@ void furi_hal_subghz_set_path(FuriHalSubGhzPath path) { | |||||||
| static bool furi_hal_subghz_start_debug() { | static bool furi_hal_subghz_start_debug() { | ||||||
|     bool ret = false; |     bool ret = false; | ||||||
|     if(furi_hal_subghz.async_mirror_pin != NULL) { |     if(furi_hal_subghz.async_mirror_pin != NULL) { | ||||||
|  |         furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, false); | ||||||
|         furi_hal_gpio_init( |         furi_hal_gpio_init( | ||||||
|             furi_hal_subghz.async_mirror_pin, |             furi_hal_subghz.async_mirror_pin, | ||||||
|             GpioModeOutputPushPull, |             GpioModeOutputPushPull, | ||||||
| @ -522,76 +527,124 @@ void furi_hal_subghz_stop_async_rx() { | |||||||
|     furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); |     furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | typedef enum { | ||||||
|  |     FuriHalSubGhzAsyncTxMiddlewareStateIdle, | ||||||
|  |     FuriHalSubGhzAsyncTxMiddlewareStateReset, | ||||||
|  |     FuriHalSubGhzAsyncTxMiddlewareStateRun, | ||||||
|  | } FuriHalSubGhzAsyncTxMiddlewareState; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     FuriHalSubGhzAsyncTxMiddlewareState state; | ||||||
|  |     bool is_odd_level; | ||||||
|  |     uint32_t adder_duration; | ||||||
|  | } FuriHalSubGhzAsyncTxMiddleware; | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint32_t* buffer; |     uint32_t* buffer; | ||||||
|     LevelDuration carry_ld; |  | ||||||
|     FuriHalSubGhzAsyncTxCallback callback; |     FuriHalSubGhzAsyncTxCallback callback; | ||||||
|     void* callback_context; |     void* callback_context; | ||||||
|     uint64_t duty_high; |     uint64_t duty_high; | ||||||
|     uint64_t duty_low; |     uint64_t duty_low; | ||||||
|  |     FuriHalSubGhzAsyncTxMiddleware middleware; | ||||||
| } FuriHalSubGhzAsyncTx; | } FuriHalSubGhzAsyncTx; | ||||||
| 
 | 
 | ||||||
| static FuriHalSubGhzAsyncTx furi_hal_subghz_async_tx = {0}; | static FuriHalSubGhzAsyncTx furi_hal_subghz_async_tx = {0}; | ||||||
| 
 | 
 | ||||||
| static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { | void furi_hal_subghz_async_tx_middleware_idle(FuriHalSubGhzAsyncTxMiddleware* middleware) { | ||||||
|     furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx); |     middleware->state = FuriHalSubGhzAsyncTxMiddlewareStateIdle; | ||||||
|     while(samples > 0) { |     middleware->is_odd_level = false; | ||||||
|         bool is_odd = samples % 2; |     middleware->adder_duration = 0; | ||||||
|         LevelDuration ld; |  | ||||||
|         if(level_duration_is_reset(furi_hal_subghz_async_tx.carry_ld)) { |  | ||||||
|             ld = furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context); |  | ||||||
|         } else { |  | ||||||
|             ld = furi_hal_subghz_async_tx.carry_ld; |  | ||||||
|             furi_hal_subghz_async_tx.carry_ld = level_duration_reset(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|         if(level_duration_is_wait(ld)) { | static inline uint32_t furi_hal_subghz_async_tx_middleware_get_duration( | ||||||
|             *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; |     FuriHalSubGhzAsyncTxMiddleware* middleware, | ||||||
|             buffer++; |     FuriHalSubGhzAsyncTxCallback callback) { | ||||||
|             samples--; |     uint32_t ret = 0; | ||||||
|         } else if(level_duration_is_reset(ld)) { |     bool is_level = false; | ||||||
|  | 
 | ||||||
|  |     if(middleware->state == FuriHalSubGhzAsyncTxMiddlewareStateReset) return 0; | ||||||
|  | 
 | ||||||
|  |     while(1) { | ||||||
|  |         LevelDuration ld = callback(furi_hal_subghz_async_tx.callback_context); | ||||||
|  |         if(level_duration_is_reset(ld)) { | ||||||
|  |             middleware->state = FuriHalSubGhzAsyncTxMiddlewareStateReset; | ||||||
|  |             if(!middleware->is_odd_level) { | ||||||
|  |                 return 0; | ||||||
|  |             } else { | ||||||
|  |                 return middleware->adder_duration; | ||||||
|  |             } | ||||||
|  |         } else if(level_duration_is_wait(ld)) { | ||||||
|  |             middleware->is_odd_level = !middleware->is_odd_level; | ||||||
|  |             ret = middleware->adder_duration + FURI_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; | ||||||
|  |             middleware->adder_duration = 0; | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         is_level = level_duration_get_level(ld); | ||||||
|  | 
 | ||||||
|  |         if(middleware->state == FuriHalSubGhzAsyncTxMiddlewareStateIdle) { | ||||||
|  |             if(is_level != middleware->is_odd_level) { | ||||||
|  |                 middleware->state = FuriHalSubGhzAsyncTxMiddlewareStateRun; | ||||||
|  |                 middleware->is_odd_level = is_level; | ||||||
|  |                 middleware->adder_duration = 0; | ||||||
|  |             } else { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(middleware->state == FuriHalSubGhzAsyncTxMiddlewareStateRun) { | ||||||
|  |             if(is_level == middleware->is_odd_level) { | ||||||
|  |                 middleware->adder_duration += level_duration_get_duration(ld); | ||||||
|  |                 continue; | ||||||
|  |             } else { | ||||||
|  |                 middleware->is_odd_level = is_level; | ||||||
|  |                 ret = middleware->adder_duration; | ||||||
|  |                 middleware->adder_duration = level_duration_get_duration(ld); | ||||||
|  |                 return ret; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { | ||||||
|  |     furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx); | ||||||
|  | 
 | ||||||
|  |     while(samples > 0) { | ||||||
|  |         volatile uint32_t duration = furi_hal_subghz_async_tx_middleware_get_duration( | ||||||
|  |             &furi_hal_subghz_async_tx.middleware, furi_hal_subghz_async_tx.callback); | ||||||
|  |         if(duration == 0) { | ||||||
|             *buffer = 0; |             *buffer = 0; | ||||||
|             buffer++; |             buffer++; | ||||||
|             samples--; |             samples--; | ||||||
|             LL_DMA_DisableIT_HT(SUBGHZ_DMA_CH1_DEF); |             LL_DMA_DisableIT_HT(SUBGHZ_DMA_CH1_DEF); | ||||||
|             LL_DMA_DisableIT_TC(SUBGHZ_DMA_CH1_DEF); |             LL_DMA_DisableIT_TC(SUBGHZ_DMA_CH1_DEF); | ||||||
|  |             if(LL_DMA_IsActiveFlag_HT1(SUBGHZ_DMA)) { | ||||||
|  |                 LL_DMA_ClearFlag_HT1(SUBGHZ_DMA); | ||||||
|  |             } | ||||||
|  |             if(LL_DMA_IsActiveFlag_TC1(SUBGHZ_DMA)) { | ||||||
|  |                 LL_DMA_ClearFlag_TC1(SUBGHZ_DMA); | ||||||
|  |             } | ||||||
|             LL_TIM_EnableIT_UPDATE(TIM2); |             LL_TIM_EnableIT_UPDATE(TIM2); | ||||||
|             break; |             break; | ||||||
|         } else { |         } else { | ||||||
|             bool level = level_duration_get_level(ld); |             // Lowest possible value is 2us
 | ||||||
| 
 |             if(duration > 2) { | ||||||
|             // Inject guard time if level is incorrect
 |                 // Subtract 1 since we counting from 0
 | ||||||
|             if(is_odd != level) { |                 *buffer = duration - 1; | ||||||
|                 *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; |  | ||||||
|                 buffer++; |  | ||||||
|                 samples--; |  | ||||||
|                 if(is_odd) { |  | ||||||
|                     furi_hal_subghz_async_tx.duty_high += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; |  | ||||||
|             } else { |             } else { | ||||||
|                     furi_hal_subghz_async_tx.duty_low += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; |                 *buffer = 1; | ||||||
|             } |             } | ||||||
| 
 |  | ||||||
|                 // Special case: prevent buffer overflow if sample is last
 |  | ||||||
|                 if(samples == 0) { |  | ||||||
|                     furi_hal_subghz_async_tx.carry_ld = ld; |  | ||||||
|                     break; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             uint32_t duration = level_duration_get_duration(ld); |  | ||||||
|             furi_assert(duration > 0); |  | ||||||
|             *buffer = duration; |  | ||||||
|             buffer++; |             buffer++; | ||||||
|             samples--; |             samples--; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|             if(is_odd) { |         if(samples % 2) { | ||||||
|             furi_hal_subghz_async_tx.duty_high += duration; |             furi_hal_subghz_async_tx.duty_high += duration; | ||||||
|         } else { |         } else { | ||||||
|             furi_hal_subghz_async_tx.duty_low += duration; |             furi_hal_subghz_async_tx.duty_low += duration; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| static void furi_hal_subghz_async_tx_dma_isr() { | static void furi_hal_subghz_async_tx_dma_isr() { | ||||||
|     furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx); |     furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx); | ||||||
| @ -600,13 +653,13 @@ static void furi_hal_subghz_async_tx_dma_isr() { | |||||||
|     if(LL_DMA_IsActiveFlag_HT1(SUBGHZ_DMA)) { |     if(LL_DMA_IsActiveFlag_HT1(SUBGHZ_DMA)) { | ||||||
|         LL_DMA_ClearFlag_HT1(SUBGHZ_DMA); |         LL_DMA_ClearFlag_HT1(SUBGHZ_DMA); | ||||||
|         furi_hal_subghz_async_tx_refill( |         furi_hal_subghz_async_tx_refill( | ||||||
|             furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); |             furi_hal_subghz_async_tx.buffer, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); | ||||||
|     } |     } | ||||||
|     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); | ||||||
|         furi_hal_subghz_async_tx_refill( |         furi_hal_subghz_async_tx_refill( | ||||||
|             furi_hal_subghz_async_tx.buffer + API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF, |             furi_hal_subghz_async_tx.buffer + FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF, | ||||||
|             API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); |             FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); | ||||||
|     } |     } | ||||||
| #else | #else | ||||||
| #error Update this code. Would you kindly? | #error Update this code. Would you kindly? | ||||||
| @ -618,15 +671,11 @@ static void furi_hal_subghz_async_tx_timer_isr() { | |||||||
|         LL_TIM_ClearFlag_UPDATE(TIM2); |         LL_TIM_ClearFlag_UPDATE(TIM2); | ||||||
|         if(LL_TIM_GetAutoReload(TIM2) == 0) { |         if(LL_TIM_GetAutoReload(TIM2) == 0) { | ||||||
|             if(furi_hal_subghz.state == SubGhzStateAsyncTx) { |             if(furi_hal_subghz.state == SubGhzStateAsyncTx) { | ||||||
|                 furi_hal_subghz.state = SubGhzStateAsyncTxLast; |  | ||||||
|                 LL_DMA_DisableChannel(SUBGHZ_DMA_CH1_DEF); |  | ||||||
|             } else if(furi_hal_subghz.state == SubGhzStateAsyncTxLast) { |  | ||||||
|                 furi_hal_subghz.state = SubGhzStateAsyncTxEnd; |                 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
 |                 //forcibly pulls the pin to the ground so that there is no carrier
 | ||||||
|                 furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullDown, GpioSpeedLow); |                 furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullDown, GpioSpeedLow); | ||||||
|                 LL_TIM_DisableCounter(TIM2); |                 LL_TIM_DisableCounter(TIM2); | ||||||
|             } else { |  | ||||||
|                 furi_crash(); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -648,7 +697,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* | |||||||
|     furi_hal_subghz_async_tx.duty_high = 0; |     furi_hal_subghz_async_tx.duty_high = 0; | ||||||
| 
 | 
 | ||||||
|     furi_hal_subghz_async_tx.buffer = |     furi_hal_subghz_async_tx.buffer = | ||||||
|         malloc(API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); |         malloc(FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); | ||||||
| 
 | 
 | ||||||
|     // Connect CC1101_GD0 to TIM2 as output
 |     // Connect CC1101_GD0 to TIM2 as output
 | ||||||
|     furi_hal_gpio_init_ex( |     furi_hal_gpio_init_ex( | ||||||
| @ -664,7 +713,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* | |||||||
|     dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; |     dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; | ||||||
|     dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; |     dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; | ||||||
|     dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; |     dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; | ||||||
|     dma_config.NbData = API_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_MODE_NORMAL; | ||||||
|     LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config); |     LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config); | ||||||
| @ -676,14 +725,12 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* | |||||||
|     furi_hal_bus_enable(FuriHalBusTIM2); |     furi_hal_bus_enable(FuriHalBusTIM2); | ||||||
| 
 | 
 | ||||||
|     // Configure TIM2
 |     // Configure TIM2
 | ||||||
|     LL_TIM_InitTypeDef TIM_InitStruct = {0}; |     LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); | ||||||
|     TIM_InitStruct.Prescaler = 64 - 1; |     LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); | ||||||
|     TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; |     LL_TIM_SetAutoReload(TIM2, 1000); | ||||||
|     TIM_InitStruct.Autoreload = 1000; |     LL_TIM_SetPrescaler(TIM2, 64 - 1); | ||||||
|     TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; |  | ||||||
|     LL_TIM_Init(TIM2, &TIM_InitStruct); |  | ||||||
|     LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); |     LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); | ||||||
|     LL_TIM_EnableARRPreload(TIM2); |     LL_TIM_DisableARRPreload(TIM2); | ||||||
| 
 | 
 | ||||||
|     // Configure TIM2 CH2
 |     // Configure TIM2 CH2
 | ||||||
|     LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; |     LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; | ||||||
| @ -691,21 +738,21 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* | |||||||
|     TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE; |     TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE; | ||||||
|     TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE; |     TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE; | ||||||
|     TIM_OC_InitStruct.CompareValue = 0; |     TIM_OC_InitStruct.CompareValue = 0; | ||||||
|     TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_LOW; |     TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; | ||||||
|     LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); |     LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); | ||||||
|     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_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_refill( |     furi_hal_subghz_async_tx_refill( | ||||||
|         furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL); |         furi_hal_subghz_async_tx.buffer, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL); | ||||||
| 
 | 
 | ||||||
|     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
 |     // Start counter
 | ||||||
|     LL_TIM_GenerateEvent_UPDATE(TIM2); |  | ||||||
| #ifdef FURI_HAL_SUBGHZ_TX_GPIO | #ifdef FURI_HAL_SUBGHZ_TX_GPIO | ||||||
|     furi_hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, true); |     furi_hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, true); | ||||||
| #endif | #endif | ||||||
| @ -717,8 +764,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* | |||||||
|     // 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; | ||||||
|         furi_hal_subghz_debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; |         furi_hal_subghz_debug_gpio_buff[0] = gpio->pin; | ||||||
|         furi_hal_subghz_debug_gpio_buff[1] = gpio->pin; |         furi_hal_subghz_debug_gpio_buff[1] = (uint32_t)gpio->pin << GPIO_NUMBER; | ||||||
| 
 | 
 | ||||||
|         dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_debug_gpio_buff; |         dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_debug_gpio_buff; | ||||||
|         dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR); |         dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR); | ||||||
| @ -746,9 +793,12 @@ bool furi_hal_subghz_is_async_tx_complete() { | |||||||
| 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 == SubGhzStateAsyncTxLast || |  | ||||||
|         furi_hal_subghz.state == SubGhzStateAsyncTxEnd); |         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(); | ||||||
| #ifdef FURI_HAL_SUBGHZ_TX_GPIO | #ifdef FURI_HAL_SUBGHZ_TX_GPIO | ||||||
| @ -756,7 +806,6 @@ void furi_hal_subghz_stop_async_tx() { | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     // Deinitialize Timer
 |     // Deinitialize Timer
 | ||||||
|     FURI_CRITICAL_ENTER(); |  | ||||||
|     furi_hal_bus_disable(FuriHalBusTIM2); |     furi_hal_bus_disable(FuriHalBusTIM2); | ||||||
|     furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); |     furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); | ||||||
| 
 | 
 | ||||||
| @ -765,16 +814,11 @@ void furi_hal_subghz_stop_async_tx() { | |||||||
| 
 | 
 | ||||||
|     furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, NULL, NULL); |     furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, NULL, NULL); | ||||||
| 
 | 
 | ||||||
|     // Deinitialize GPIO
 |  | ||||||
|     furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); |  | ||||||
| 
 |  | ||||||
|     // Stop debug
 |     // Stop debug
 | ||||||
|     if(furi_hal_subghz_stop_debug()) { |     if(furi_hal_subghz_stop_debug()) { | ||||||
|         LL_DMA_DisableChannel(SUBGHZ_DMA_CH2_DEF); |         LL_DMA_DisableChannel(SUBGHZ_DMA_CH2_DEF); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     FURI_CRITICAL_EXIT(); |  | ||||||
| 
 |  | ||||||
|     free(furi_hal_subghz_async_tx.buffer); |     free(furi_hal_subghz_async_tx.buffer); | ||||||
| 
 | 
 | ||||||
|     float duty_cycle = |     float duty_cycle = | ||||||
|  | |||||||
| @ -17,10 +17,10 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /** Low level buffer dimensions and guard times */ | /** Various subghz defines */ | ||||||
| #define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256) | #define FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256u) | ||||||
| #define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2) | #define FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2) | ||||||
| #define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 999 | #define FURI_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME (999u) | ||||||
| 
 | 
 | ||||||
| /** Switchable Radio Paths */ | /** Switchable Radio Paths */ | ||||||
| typedef enum { | typedef enum { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Skorpionm
						Skorpionm