2022-01-05 16:10:18 +00:00
# include "furi_hal_subghz.h"
# include "furi_hal_version.h"
# include "furi_hal_rtc.h"
2021-09-10 02:19:02 +00:00
2022-01-05 16:10:18 +00:00
# include <furi_hal_gpio.h>
# include <furi_hal_spi.h>
# include <furi_hal_interrupt.h>
# include <furi_hal_resources.h>
2021-09-10 02:19:02 +00:00
2022-03-30 15:23:40 +00:00
# include <stm32wbxx_ll_dma.h>
2021-09-10 02:19:02 +00:00
# include <furi.h>
# include <cc1101.h>
# include <stdio.h>
2021-11-12 13:04:35 +00:00
# define TAG "FuriHalSubGhz"
2021-09-10 02:19:02 +00:00
static volatile SubGhzState furi_hal_subghz_state = SubGhzStateInit ;
2021-09-28 00:05:40 +00:00
static volatile SubGhzRegulation furi_hal_subghz_regulation = SubGhzRegulationTxRx ;
2021-12-22 11:05:14 +00:00
static volatile FuriHalSubGhzPreset furi_hal_subghz_preset = FuriHalSubGhzPresetIDLE ;
2021-09-10 02:19:02 +00:00
static const uint8_t furi_hal_subghz_preset_ook_270khz_async_regs [ ] [ 2 ] = {
// https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration
/* GPIO GD0 */
2021-09-15 15:24:19 +00:00
{ CC1101_IOCFG0 , 0x0D } , // GD0 as async serial data output/input
2021-09-10 02:19:02 +00:00
/* FIFO and internals */
2021-09-15 15:24:19 +00:00
{ CC1101_FIFOTHR , 0x47 } , // The only important bit is ADC_RETENTION, FIFO Tx=33 Rx=32
2021-09-10 02:19:02 +00:00
/* Packet engine */
2021-09-15 15:24:19 +00:00
{ CC1101_PKTCTRL0 , 0x32 } , // Async, continious, no whitening
2021-09-10 02:19:02 +00:00
/* Frequency Synthesizer Control */
2021-09-15 15:24:19 +00:00
{ CC1101_FSCTRL1 , 0x06 } , // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
2021-09-10 02:19:02 +00:00
// Modem Configuration
2021-09-15 15:24:19 +00:00
{ CC1101_MDMCFG0 , 0x00 } , // Channel spacing is 25kHz
{ CC1101_MDMCFG1 , 0x00 } , // Channel spacing is 25kHz
{ CC1101_MDMCFG2 , 0x30 } , // Format ASK/OOK, No preamble/sync
{ CC1101_MDMCFG3 , 0x32 } , // Data rate is 3.79372 kBaud
{ CC1101_MDMCFG4 , 0x67 } , // Rx BW filter is 270.833333kHz
2021-09-10 02:19:02 +00:00
/* Main Radio Control State Machine */
2021-09-15 15:24:19 +00:00
{ CC1101_MCSM0 , 0x18 } , // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
2021-09-10 02:19:02 +00:00
/* Frequency Offset Compensation Configuration */
2021-09-15 15:24:19 +00:00
{ CC1101_FOCCFG ,
0x18 } , // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
2021-09-10 02:19:02 +00:00
/* Automatic Gain Control */
2021-09-28 00:05:40 +00:00
{ CC1101_AGCCTRL0 ,
2021-09-15 15:24:19 +00:00
0x40 } , // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary
2021-09-28 00:05:40 +00:00
{ CC1101_AGCCTRL1 ,
2021-09-15 15:24:19 +00:00
0x00 } , // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
2021-09-28 00:05:40 +00:00
{ CC1101_AGCCTRL2 , 0x03 } , // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB
2021-09-10 02:19:02 +00:00
/* Wake on radio and timeouts control */
2021-09-15 15:24:19 +00:00
{ CC1101_WORCTRL , 0xFB } , // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours
2021-09-10 02:19:02 +00:00
/* Frontend configuration */
2021-09-15 15:24:19 +00:00
{ CC1101_FREND0 , 0x11 } , // Adjusts current TX LO buffer + high is PATABLE[1]
{ CC1101_FREND1 , 0xB6 } , //
2021-09-10 02:19:02 +00:00
/* End */
2021-09-15 15:24:19 +00:00
{ 0 , 0 } ,
2021-09-10 02:19:02 +00:00
} ;
static const uint8_t furi_hal_subghz_preset_ook_650khz_async_regs [ ] [ 2 ] = {
// https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration
/* GPIO GD0 */
2021-09-15 15:24:19 +00:00
{ CC1101_IOCFG0 , 0x0D } , // GD0 as async serial data output/input
2021-09-10 02:19:02 +00:00
/* FIFO and internals */
2021-09-15 15:24:19 +00:00
{ CC1101_FIFOTHR , 0x07 } , // The only important bit is ADC_RETENTION
2021-09-10 02:19:02 +00:00
/* Packet engine */
2021-09-15 15:24:19 +00:00
{ CC1101_PKTCTRL0 , 0x32 } , // Async, continious, no whitening
2021-09-10 02:19:02 +00:00
/* Frequency Synthesizer Control */
2021-09-15 15:24:19 +00:00
{ CC1101_FSCTRL1 , 0x06 } , // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
2021-09-10 02:19:02 +00:00
// Modem Configuration
2021-09-15 15:24:19 +00:00
{ CC1101_MDMCFG0 , 0x00 } , // Channel spacing is 25kHz
{ CC1101_MDMCFG1 , 0x00 } , // Channel spacing is 25kHz
{ CC1101_MDMCFG2 , 0x30 } , // Format ASK/OOK, No preamble/sync
{ CC1101_MDMCFG3 , 0x32 } , // Data rate is 3.79372 kBaud
{ CC1101_MDMCFG4 , 0x17 } , // Rx BW filter is 650.000kHz
2021-09-10 02:19:02 +00:00
/* Main Radio Control State Machine */
2021-09-15 15:24:19 +00:00
{ CC1101_MCSM0 , 0x18 } , // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
2021-09-10 02:19:02 +00:00
/* Frequency Offset Compensation Configuration */
2021-09-15 15:24:19 +00:00
{ CC1101_FOCCFG ,
0x18 } , // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
2021-09-10 02:19:02 +00:00
/* Automatic Gain Control */
2021-09-28 00:05:40 +00:00
// {CC1101_AGCTRL0,0x40}, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary
// {CC1101_AGCTRL1,0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
// {CC1101_AGCCTRL2, 0x03}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB
//MAGN_TARGET for RX filter BW =< 100 kHz is 0x3. For higher RX filter BW's MAGN_TARGET is 0x7.
{ CC1101_AGCCTRL0 ,
0x91 } , // 10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary
{ CC1101_AGCCTRL1 ,
0x0 } , // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
{ CC1101_AGCCTRL2 , 0x07 } , // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB
2021-09-10 02:19:02 +00:00
/* Wake on radio and timeouts control */
2021-09-15 15:24:19 +00:00
{ CC1101_WORCTRL , 0xFB } , // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours
2021-09-10 02:19:02 +00:00
/* Frontend configuration */
2021-09-15 15:24:19 +00:00
{ CC1101_FREND0 , 0x11 } , // Adjusts current TX LO buffer + high is PATABLE[1]
{ CC1101_FREND1 , 0xB6 } , //
2021-09-10 02:19:02 +00:00
/* End */
2021-09-15 15:24:19 +00:00
{ 0 , 0 } ,
2021-09-10 02:19:02 +00:00
} ;
2021-10-10 14:35:10 +00:00
static const uint8_t furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs [ ] [ 2 ] = {
2021-09-10 02:19:02 +00:00
/* GPIO GD0 */
2021-09-15 15:24:19 +00:00
{ CC1101_IOCFG0 , 0x0D } , // GD0 as async serial data output/input
2021-09-10 02:19:02 +00:00
2021-09-28 00:05:40 +00:00
/* Frequency Synthesizer Control */
{ CC1101_FSCTRL1 , 0x06 } , // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
2021-09-10 02:19:02 +00:00
/* Packet engine */
2021-09-15 15:24:19 +00:00
{ CC1101_PKTCTRL0 , 0x32 } , // Async, continious, no whitening
2021-09-28 00:05:40 +00:00
{ CC1101_PKTCTRL1 , 0x04 } ,
2021-09-10 02:19:02 +00:00
2021-09-28 00:05:40 +00:00
// // Modem Configuration
2021-09-15 15:24:19 +00:00
{ CC1101_MDMCFG0 , 0x00 } ,
2021-10-10 14:35:10 +00:00
{ CC1101_MDMCFG1 , 0x02 } ,
{ CC1101_MDMCFG2 , 0x04 } , // Format 2-FSK/FM, No preamble/sync, Disable (current optimized)
2021-09-28 00:05:40 +00:00
{ CC1101_MDMCFG3 , 0x83 } , // Data rate is 4.79794 kBaud
{ CC1101_MDMCFG4 , 0x67 } , //Rx BW filter is 270.833333 kHz
{ CC1101_DEVIATN , 0x04 } , //Deviation 2.380371 kHz
2021-09-10 02:19:02 +00:00
/* Main Radio Control State Machine */
2021-09-15 15:24:19 +00:00
{ CC1101_MCSM0 , 0x18 } , // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
2021-09-10 02:19:02 +00:00
/* Frequency Offset Compensation Configuration */
2021-09-15 15:24:19 +00:00
{ CC1101_FOCCFG ,
0x16 } , // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
2021-09-10 02:19:02 +00:00
/* Automatic Gain Control */
2021-09-28 00:05:40 +00:00
{ CC1101_AGCCTRL0 ,
0x91 } , //10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary
{ CC1101_AGCCTRL1 ,
2021-09-15 15:24:19 +00:00
0x00 } , // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
2021-09-28 00:05:40 +00:00
{ CC1101_AGCCTRL2 , 0x07 } , // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB
2021-09-10 02:19:02 +00:00
/* Wake on radio and timeouts control */
2021-09-15 15:24:19 +00:00
{ CC1101_WORCTRL , 0xFB } , // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours
2021-09-10 02:19:02 +00:00
/* Frontend configuration */
2021-09-15 15:24:19 +00:00
{ CC1101_FREND0 , 0x10 } , // Adjusts current TX LO buffer
2021-09-28 00:05:40 +00:00
{ CC1101_FREND1 , 0x56 } ,
2021-09-10 02:19:02 +00:00
/* End */
2021-09-15 15:24:19 +00:00
{ 0 , 0 } ,
2021-09-10 02:19:02 +00:00
} ;
2022-04-14 12:49:29 +00:00
static const uint8_t furi_hal_subghz_preset_2fsk_dev47_6khz_async_regs [ ] [ 2 ] = {
2021-10-10 14:35:10 +00:00
/* GPIO GD0 */
{ CC1101_IOCFG0 , 0x0D } , // GD0 as async serial data output/input
/* Frequency Synthesizer Control */
{ CC1101_FSCTRL1 , 0x06 } , // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
/* Packet engine */
{ CC1101_PKTCTRL0 , 0x32 } , // Async, continious, no whitening
{ CC1101_PKTCTRL1 , 0x04 } ,
// // Modem Configuration
{ CC1101_MDMCFG0 , 0x00 } ,
{ CC1101_MDMCFG1 , 0x02 } ,
{ CC1101_MDMCFG2 , 0x04 } , // Format 2-FSK/FM, No preamble/sync, Disable (current optimized)
{ CC1101_MDMCFG3 , 0x83 } , // Data rate is 4.79794 kBaud
{ CC1101_MDMCFG4 , 0x67 } , //Rx BW filter is 270.833333 kHz
2022-04-14 12:49:29 +00:00
{ CC1101_DEVIATN , 0x47 } , //Deviation 47.60742 kHz
2021-10-10 14:35:10 +00:00
/* Main Radio Control State Machine */
{ CC1101_MCSM0 , 0x18 } , // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
/* Frequency Offset Compensation Configuration */
{ CC1101_FOCCFG ,
0x16 } , // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
/* Automatic Gain Control */
{ CC1101_AGCCTRL0 ,
0x91 } , //10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary
{ CC1101_AGCCTRL1 ,
0x00 } , // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
{ CC1101_AGCCTRL2 , 0x07 } , // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB
/* Wake on radio and timeouts control */
{ CC1101_WORCTRL , 0xFB } , // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours
/* Frontend configuration */
{ CC1101_FREND0 , 0x10 } , // Adjusts current TX LO buffer
{ CC1101_FREND1 , 0x56 } ,
/* End */
{ 0 , 0 } ,
} ;
2021-12-01 15:44:39 +00:00
static const uint8_t furi_hal_subghz_preset_msk_99_97kb_async_regs [ ] [ 2 ] = {
/* GPIO GD0 */
{ CC1101_IOCFG0 , 0x06 } ,
{ CC1101_FIFOTHR , 0x07 } , // The only important bit is ADC_RETENTION
{ CC1101_SYNC1 , 0x46 } ,
{ CC1101_SYNC0 , 0x4C } ,
{ CC1101_ADDR , 0x00 } ,
{ CC1101_PKTLEN , 0x00 } ,
{ CC1101_CHANNR , 0x00 } ,
{ CC1101_PKTCTRL0 , 0x05 } ,
{ CC1101_FSCTRL0 , 0x23 } ,
{ CC1101_FSCTRL1 , 0x06 } ,
{ CC1101_MDMCFG0 , 0xF8 } ,
{ CC1101_MDMCFG1 , 0x22 } ,
{ CC1101_MDMCFG2 , 0x72 } ,
{ CC1101_MDMCFG3 , 0xF8 } ,
{ CC1101_MDMCFG4 , 0x5B } ,
{ CC1101_DEVIATN , 0x47 } ,
{ CC1101_MCSM0 , 0x18 } ,
{ CC1101_FOCCFG , 0x16 } ,
{ CC1101_AGCCTRL0 , 0xB2 } ,
{ CC1101_AGCCTRL1 , 0x00 } ,
{ CC1101_AGCCTRL2 , 0xC7 } ,
{ CC1101_FREND0 , 0x10 } ,
{ CC1101_FREND1 , 0x56 } ,
{ CC1101_BSCFG , 0x1C } ,
{ CC1101_FSTEST , 0x59 } ,
/* End */
{ 0 , 0 } ,
} ;
2021-12-08 13:42:01 +00:00
static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs [ ] [ 2 ] = {
{ CC1101_IOCFG0 , 0x06 } , //GDO0 Output Pin Configuration
{ CC1101_FIFOTHR , 0x47 } , //RX FIFO and TX FIFO Thresholds
2021-12-22 11:05:14 +00:00
//1 : CRC calculation in TX and CRC check in RX enabled,
2021-12-08 13:42:01 +00:00
//1 : Variable packet length mode. Packet length configured by the first byte after sync word
2021-12-22 11:05:14 +00:00
{ CC1101_PKTCTRL0 , 0x05 } ,
2021-12-08 13:42:01 +00:00
{ CC1101_FSCTRL1 , 0x06 } , //Frequency Synthesizer Control
{ CC1101_SYNC1 , 0x46 } ,
{ CC1101_SYNC0 , 0x4C } ,
{ CC1101_ADDR , 0x00 } ,
{ CC1101_PKTLEN , 0x00 } ,
{ CC1101_MDMCFG4 , 0xC8 } , //Modem Configuration 9.99
{ CC1101_MDMCFG3 , 0x93 } , //Modem Configuration
{ CC1101_MDMCFG2 , 0x12 } , // 2: 16/16 sync word bits detected
{ CC1101_DEVIATN , 0x34 } , //Deviation = 19.042969
{ CC1101_MCSM0 , 0x18 } , //Main Radio Control State Machine Configuration
{ CC1101_FOCCFG , 0x16 } , //Frequency Offset Compensation Configuration
2021-12-22 11:05:14 +00:00
{ CC1101_AGCCTRL2 , 0x43 } , //AGC Control
2021-12-08 13:42:01 +00:00
{ CC1101_AGCCTRL1 , 0x40 } ,
{ CC1101_AGCCTRL0 , 0x91 } ,
{ CC1101_WORCTRL , 0xFB } , //Wake On Radio Control
/* End */
{ 0 , 0 } ,
} ;
2021-12-01 15:44:39 +00:00
2021-09-10 02:19:02 +00:00
static const uint8_t furi_hal_subghz_preset_ook_async_patable [ 8 ] = {
0x00 ,
2021-12-22 11:05:14 +00:00
0xC0 , // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03
0x00 ,
0x00 ,
0x00 ,
0x00 ,
0x00 ,
0x00 } ;
2021-09-10 02:19:02 +00:00
static const uint8_t furi_hal_subghz_preset_2fsk_async_patable [ 8 ] = {
0xC0 , // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
0x00 ,
0x00 ,
0x00 ,
0x00 ,
0x00 ,
0x00 ,
2021-12-01 15:44:39 +00:00
0x00 } ;
static const uint8_t furi_hal_subghz_preset_msk_async_patable [ 8 ] = {
0xC0 , // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
0x00 ,
0x00 ,
0x00 ,
0x00 ,
0x00 ,
0x00 ,
0x00 } ;
2021-12-08 13:42:01 +00:00
static const uint8_t furi_hal_subghz_preset_gfsk_async_patable [ 8 ] = {
0xC0 , // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
0x00 ,
0x00 ,
0x00 ,
0x00 ,
0x00 ,
0x00 ,
0x00 } ;
2021-09-10 02:19:02 +00:00
void furi_hal_subghz_init ( ) {
furi_assert ( furi_hal_subghz_state = = SubGhzStateInit ) ;
furi_hal_subghz_state = SubGhzStateIdle ;
2021-12-22 11:05:14 +00:00
furi_hal_subghz_preset = FuriHalSubGhzPresetIDLE ;
2021-09-10 02:19:02 +00:00
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
# ifdef FURI_HAL_SUBGHZ_TX_GPIO
2022-03-30 15:23:40 +00:00
furi_hal_gpio_init ( & FURI_HAL_SUBGHZ_TX_GPIO , GpioModeOutputPushPull , GpioPullNo , GpioSpeedLow ) ;
2021-09-10 02:19:02 +00:00
# endif
// Reset
2022-03-30 15:23:40 +00:00
furi_hal_gpio_init ( & gpio_cc1101_g0 , GpioModeAnalog , GpioPullNo , GpioSpeedLow ) ;
2021-11-30 12:09:43 +00:00
cc1101_reset ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_IOCFG0 , CC1101IocfgHighImpedance ) ;
2021-09-10 02:19:02 +00:00
// Prepare GD0 for power on self test
2022-03-30 15:23:40 +00:00
furi_hal_gpio_init ( & gpio_cc1101_g0 , GpioModeInput , GpioPullNo , GpioSpeedLow ) ;
2021-09-10 02:19:02 +00:00
// GD0 low
2021-11-30 12:09:43 +00:00
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_IOCFG0 , CC1101IocfgHW ) ;
2022-03-30 15:23:40 +00:00
while ( furi_hal_gpio_read ( & gpio_cc1101_g0 ) ! = false )
2021-09-15 15:24:19 +00:00
;
2021-09-10 02:19:02 +00:00
// GD0 high
2021-12-22 11:05:14 +00:00
cc1101_write_reg (
& furi_hal_spi_bus_handle_subghz , CC1101_IOCFG0 , CC1101IocfgHW | CC1101_IOCFG_INV ) ;
2022-03-30 15:23:40 +00:00
while ( furi_hal_gpio_read ( & gpio_cc1101_g0 ) ! = true )
2021-09-15 15:24:19 +00:00
;
2021-09-10 02:19:02 +00:00
// Reset GD0 to floating state
2021-11-30 12:09:43 +00:00
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_IOCFG0 , CC1101IocfgHighImpedance ) ;
2022-03-30 15:23:40 +00:00
furi_hal_gpio_init ( & gpio_cc1101_g0 , GpioModeAnalog , GpioPullNo , GpioSpeedLow ) ;
2021-09-10 02:19:02 +00:00
// RF switches
2022-03-30 15:23:40 +00:00
furi_hal_gpio_init ( & gpio_rf_sw_0 , GpioModeOutputPushPull , GpioPullNo , GpioSpeedLow ) ;
2021-11-30 12:09:43 +00:00
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_IOCFG2 , CC1101IocfgHW ) ;
2021-09-10 02:19:02 +00:00
// Go to sleep
2021-11-30 12:09:43 +00:00
cc1101_shutdown ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
2021-11-30 12:09:43 +00:00
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-11-12 13:04:35 +00:00
FURI_LOG_I ( TAG , " Init OK " ) ;
2021-09-10 02:19:02 +00:00
}
void furi_hal_subghz_sleep ( ) {
furi_assert ( furi_hal_subghz_state = = SubGhzStateIdle ) ;
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
2021-11-30 12:09:43 +00:00
cc1101_switch_to_idle ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
2021-11-30 12:09:43 +00:00
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_IOCFG0 , CC1101IocfgHighImpedance ) ;
2022-03-30 15:23:40 +00:00
furi_hal_gpio_init ( & gpio_cc1101_g0 , GpioModeAnalog , GpioPullNo , GpioSpeedLow ) ;
2021-09-10 02:19:02 +00:00
2021-11-30 12:09:43 +00:00
cc1101_shutdown ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
2021-11-30 12:09:43 +00:00
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-12-22 11:05:14 +00:00
furi_hal_subghz_preset = FuriHalSubGhzPresetIDLE ;
2021-09-10 02:19:02 +00:00
}
void furi_hal_subghz_dump_state ( ) {
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
printf (
" [furi_hal_subghz] cc1101 chip %d, version %d \r \n " ,
2021-11-30 12:09:43 +00:00
cc1101_get_partnumber ( & furi_hal_spi_bus_handle_subghz ) ,
cc1101_get_version ( & furi_hal_spi_bus_handle_subghz ) ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
}
void furi_hal_subghz_load_preset ( FuriHalSubGhzPreset preset ) {
if ( preset = = FuriHalSubGhzPresetOok650Async ) {
furi_hal_subghz_load_registers ( furi_hal_subghz_preset_ook_650khz_async_regs ) ;
furi_hal_subghz_load_patable ( furi_hal_subghz_preset_ook_async_patable ) ;
2021-09-15 15:24:19 +00:00
} else if ( preset = = FuriHalSubGhzPresetOok270Async ) {
2021-09-10 02:19:02 +00:00
furi_hal_subghz_load_registers ( furi_hal_subghz_preset_ook_270khz_async_regs ) ;
furi_hal_subghz_load_patable ( furi_hal_subghz_preset_ook_async_patable ) ;
2021-10-10 14:35:10 +00:00
} else if ( preset = = FuriHalSubGhzPreset2FSKDev238Async ) {
furi_hal_subghz_load_registers ( furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs ) ;
furi_hal_subghz_load_patable ( furi_hal_subghz_preset_2fsk_async_patable ) ;
} else if ( preset = = FuriHalSubGhzPreset2FSKDev476Async ) {
2022-04-14 12:49:29 +00:00
furi_hal_subghz_load_registers ( furi_hal_subghz_preset_2fsk_dev47_6khz_async_regs ) ;
2021-09-10 02:19:02 +00:00
furi_hal_subghz_load_patable ( furi_hal_subghz_preset_2fsk_async_patable ) ;
2021-12-01 15:44:39 +00:00
} else if ( preset = = FuriHalSubGhzPresetMSK99_97KbAsync ) {
furi_hal_subghz_load_registers ( furi_hal_subghz_preset_msk_99_97kb_async_regs ) ;
furi_hal_subghz_load_patable ( furi_hal_subghz_preset_msk_async_patable ) ;
2021-12-08 13:42:01 +00:00
} else if ( preset = = FuriHalSubGhzPresetGFSK9_99KbAsync ) {
furi_hal_subghz_load_registers ( furi_hal_subghz_preset_gfsk_9_99kb_async_regs ) ;
furi_hal_subghz_load_patable ( furi_hal_subghz_preset_gfsk_async_patable ) ;
2021-12-22 11:05:14 +00:00
} else {
2022-05-31 22:35:31 +00:00
furi_crash ( " SubGhz: Missing config. " ) ;
2021-09-10 02:19:02 +00:00
}
2021-12-22 11:05:14 +00:00
furi_hal_subghz_preset = preset ;
2021-09-10 02:19:02 +00:00
}
void furi_hal_subghz_load_registers ( const uint8_t data [ ] [ 2 ] ) {
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_reset ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
uint32_t i = 0 ;
2021-09-15 15:24:19 +00:00
while ( data [ i ] [ 0 ] ) {
2021-11-30 12:09:43 +00:00
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , data [ i ] [ 0 ] , data [ i ] [ 1 ] ) ;
2021-09-10 02:19:02 +00:00
i + + ;
}
2021-11-30 12:09:43 +00:00
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
}
void furi_hal_subghz_load_patable ( const uint8_t data [ 8 ] ) {
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_set_pa_table ( & furi_hal_spi_bus_handle_subghz , data ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
}
void furi_hal_subghz_write_packet ( const uint8_t * data , uint8_t size ) {
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_flush_tx ( & furi_hal_spi_bus_handle_subghz ) ;
2021-12-01 15:44:39 +00:00
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_FIFO , size ) ;
2021-11-30 12:09:43 +00:00
cc1101_write_fifo ( & furi_hal_spi_bus_handle_subghz , data , size ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
}
void furi_hal_subghz_flush_rx ( ) {
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_flush_rx ( & furi_hal_spi_bus_handle_subghz ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
}
2021-12-08 13:42:01 +00:00
void furi_hal_subghz_flush_tx ( ) {
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_flush_tx ( & furi_hal_spi_bus_handle_subghz ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
}
2021-12-01 15:44:39 +00:00
bool furi_hal_subghz_rx_pipe_not_empty ( ) {
CC1101RxBytes status [ 1 ] ;
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
2021-12-22 11:05:14 +00:00
cc1101_read_reg (
& furi_hal_spi_bus_handle_subghz , ( CC1101_STATUS_RXBYTES ) | CC1101_BURST , ( uint8_t * ) status ) ;
2021-12-01 15:44:39 +00:00
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
// TODO: you can add a buffer overflow flag if needed
if ( status - > NUM_RXBYTES > 0 ) {
return true ;
} else {
return false ;
}
}
bool furi_hal_subghz_is_rx_data_crc_valid ( ) {
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
uint8_t data [ 1 ] ;
cc1101_read_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_STATUS_LQI | CC1101_BURST , data ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
if ( ( ( data [ 0 ] > > 7 ) & 0x01 ) ) {
return true ;
} else {
return false ;
}
}
2021-09-10 02:19:02 +00:00
void furi_hal_subghz_read_packet ( uint8_t * data , uint8_t * size ) {
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_read_fifo ( & furi_hal_spi_bus_handle_subghz , data , size ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
}
void furi_hal_subghz_shutdown ( ) {
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
// Reset and shutdown
2021-11-30 12:09:43 +00:00
cc1101_shutdown ( & furi_hal_spi_bus_handle_subghz ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
}
void furi_hal_subghz_reset ( ) {
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
2022-03-30 15:23:40 +00:00
furi_hal_gpio_init ( & gpio_cc1101_g0 , GpioModeAnalog , GpioPullNo , GpioSpeedLow ) ;
2021-11-30 12:09:43 +00:00
cc1101_switch_to_idle ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_reset ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_IOCFG0 , CC1101IocfgHighImpedance ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
}
void furi_hal_subghz_idle ( ) {
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_switch_to_idle ( & furi_hal_spi_bus_handle_subghz ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
}
void furi_hal_subghz_rx ( ) {
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & 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 ) ;
2021-09-10 02:19:02 +00:00
}
2021-09-28 00:05:40 +00:00
bool furi_hal_subghz_tx ( ) {
if ( furi_hal_subghz_regulation ! = SubGhzRegulationTxRx ) return false ;
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_switch_to_tx ( & furi_hal_spi_bus_handle_subghz ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-28 00:05:40 +00:00
return true ;
2021-09-10 02:19:02 +00:00
}
float furi_hal_subghz_get_rssi ( ) {
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
int32_t rssi_dec = cc1101_get_rssi ( & furi_hal_spi_bus_handle_subghz ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
float rssi = rssi_dec ;
if ( rssi_dec > = 128 ) {
rssi = ( ( rssi - 256.0f ) / 2.0f ) - 74.0f ;
} else {
rssi = ( rssi / 2.0f ) - 74.0f ;
}
return rssi ;
}
2021-12-08 13:42:01 +00:00
uint8_t furi_hal_subghz_get_lqi ( ) {
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
uint8_t data [ 1 ] ;
cc1101_read_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_STATUS_LQI | CC1101_BURST , data ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
return data [ 0 ] & 0x7F ;
}
2021-09-10 02:19:02 +00:00
bool furi_hal_subghz_is_frequency_valid ( uint32_t value ) {
if ( ! ( value > = 299999755 & & value < = 348000335 ) & &
! ( value > = 386999938 & & value < = 464000000 ) & &
! ( value > = 778999847 & & value < = 928000000 ) ) {
return false ;
}
2021-09-28 00:05:40 +00:00
2021-09-10 02:19:02 +00:00
return true ;
}
uint32_t furi_hal_subghz_set_frequency_and_path ( uint32_t value ) {
value = furi_hal_subghz_set_frequency ( value ) ;
if ( value > = 299999755 & & value < = 348000335 ) {
furi_hal_subghz_set_path ( FuriHalSubGhzPath315 ) ;
} else if ( value > = 386999938 & & value < = 464000000 ) {
furi_hal_subghz_set_path ( FuriHalSubGhzPath433 ) ;
} else if ( value > = 778999847 & & value < = 928000000 ) {
furi_hal_subghz_set_path ( FuriHalSubGhzPath868 ) ;
} else {
2022-05-31 22:35:31 +00:00
furi_crash ( " SubGhz: Incorrect frequency during set. " ) ;
2021-09-10 02:19:02 +00:00
}
return value ;
}
2021-12-01 15:44:39 +00:00
bool furi_hal_subghz_is_tx_allowed ( uint32_t value ) {
2022-06-01 13:07:53 +00:00
// Removed region check
2022-06-01 14:03:21 +00:00
if ( ! ( value > = 299999755 & & value < = 348000335 ) & &
! ( value > = 386999938 & & value < = 464000000 ) & &
! ( value > = 778999847 & & value < = 928000000 ) ) {
return false ;
}
2022-06-01 13:07:53 +00:00
return true ;
2021-12-01 15:44:39 +00:00
}
uint32_t furi_hal_subghz_set_frequency ( uint32_t value ) {
if ( furi_hal_subghz_is_tx_allowed ( value ) ) {
2021-09-28 00:05:40 +00:00
furi_hal_subghz_regulation = SubGhzRegulationTxRx ;
} else {
furi_hal_subghz_regulation = SubGhzRegulationOnlyRx ;
}
2021-12-22 11:05:14 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
2021-11-30 12:09:43 +00:00
uint32_t real_frequency = cc1101_set_frequency ( & furi_hal_spi_bus_handle_subghz , value ) ;
cc1101_calibrate ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
while ( true ) {
2021-11-30 12:09:43 +00:00
CC1101Status status = cc1101_get_status ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-15 15:24:19 +00:00
if ( status . STATE = = CC1101StateIDLE ) break ;
2021-09-10 02:19:02 +00:00
}
2021-11-30 12:09:43 +00:00
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
return real_frequency ;
}
void furi_hal_subghz_set_path ( FuriHalSubGhzPath path ) {
2021-11-30 12:09:43 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-15 15:24:19 +00:00
if ( path = = FuriHalSubGhzPath433 ) {
2022-03-30 15:23:40 +00:00
furi_hal_gpio_write ( & gpio_rf_sw_0 , 0 ) ;
2021-12-22 11:05:14 +00:00
cc1101_write_reg (
& furi_hal_spi_bus_handle_subghz , CC1101_IOCFG2 , CC1101IocfgHW | CC1101_IOCFG_INV ) ;
2021-09-15 15:24:19 +00:00
} else if ( path = = FuriHalSubGhzPath315 ) {
2022-03-30 15:23:40 +00:00
furi_hal_gpio_write ( & gpio_rf_sw_0 , 1 ) ;
2021-11-30 12:09:43 +00:00
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_IOCFG2 , CC1101IocfgHW ) ;
2021-09-15 15:24:19 +00:00
} else if ( path = = FuriHalSubGhzPath868 ) {
2022-03-30 15:23:40 +00:00
furi_hal_gpio_write ( & gpio_rf_sw_0 , 1 ) ;
2021-12-22 11:05:14 +00:00
cc1101_write_reg (
& furi_hal_spi_bus_handle_subghz , CC1101_IOCFG2 , CC1101IocfgHW | CC1101_IOCFG_INV ) ;
2021-09-15 15:24:19 +00:00
} else if ( path = = FuriHalSubGhzPathIsolate ) {
2022-03-30 15:23:40 +00:00
furi_hal_gpio_write ( & gpio_rf_sw_0 , 0 ) ;
2021-11-30 12:09:43 +00:00
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_IOCFG2 , CC1101IocfgHW ) ;
2021-09-10 02:19:02 +00:00
} else {
2022-04-09 18:47:14 +00:00
furi_crash ( " SubGhz: Incorrect path during set. " ) ;
2021-09-10 02:19:02 +00:00
}
2021-11-30 12:09:43 +00:00
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2021-09-10 02:19:02 +00:00
}
volatile uint32_t furi_hal_subghz_capture_delta_duration = 0 ;
volatile FuriHalSubGhzCaptureCallback furi_hal_subghz_capture_callback = NULL ;
volatile void * furi_hal_subghz_capture_callback_context = NULL ;
static void furi_hal_subghz_capture_ISR ( ) {
// Channel 1
if ( LL_TIM_IsActiveFlag_CC1 ( TIM2 ) ) {
LL_TIM_ClearFlag_CC1 ( TIM2 ) ;
furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1 ( TIM2 ) ;
2021-09-15 15:24:19 +00:00
if ( furi_hal_subghz_capture_callback ) {
furi_hal_subghz_capture_callback (
true ,
furi_hal_subghz_capture_delta_duration ,
( void * ) furi_hal_subghz_capture_callback_context ) ;
2021-09-10 02:19:02 +00:00
}
}
// Channel 2
if ( LL_TIM_IsActiveFlag_CC2 ( TIM2 ) ) {
LL_TIM_ClearFlag_CC2 ( TIM2 ) ;
2021-09-15 15:24:19 +00:00
if ( furi_hal_subghz_capture_callback ) {
furi_hal_subghz_capture_callback (
false ,
LL_TIM_IC_GetCaptureCH2 ( TIM2 ) - furi_hal_subghz_capture_delta_duration ,
( void * ) furi_hal_subghz_capture_callback_context ) ;
2021-09-10 02:19:02 +00:00
}
}
}
void furi_hal_subghz_start_async_rx ( FuriHalSubGhzCaptureCallback callback , void * context ) {
furi_assert ( furi_hal_subghz_state = = SubGhzStateIdle ) ;
furi_hal_subghz_state = SubGhzStateAsyncRx ;
furi_hal_subghz_capture_callback = callback ;
furi_hal_subghz_capture_callback_context = context ;
2022-03-30 15:23:40 +00:00
furi_hal_gpio_init_ex (
2021-09-15 15:24:19 +00:00
& gpio_cc1101_g0 , GpioModeAltFunctionPushPull , GpioPullNo , GpioSpeedLow , GpioAltFn1TIM2 ) ;
2021-09-10 02:19:02 +00:00
// Timer: base
LL_TIM_InitTypeDef TIM_InitStruct = { 0 } ;
2021-09-15 15:24:19 +00:00
TIM_InitStruct . Prescaler = 64 - 1 ;
2021-09-10 02:19:02 +00:00
TIM_InitStruct . CounterMode = LL_TIM_COUNTERMODE_UP ;
TIM_InitStruct . Autoreload = 0x7FFFFFFE ;
2021-09-28 00:05:40 +00:00
TIM_InitStruct . ClockDivision = LL_TIM_CLOCKDIVISION_DIV4 ;
2021-09-10 02:19:02 +00:00
LL_TIM_Init ( TIM2 , & TIM_InitStruct ) ;
// Timer: advanced
LL_TIM_SetClockSource ( TIM2 , LL_TIM_CLOCKSOURCE_INTERNAL ) ;
LL_TIM_DisableARRPreload ( TIM2 ) ;
LL_TIM_SetTriggerInput ( TIM2 , LL_TIM_TS_TI2FP2 ) ;
LL_TIM_SetSlaveMode ( TIM2 , LL_TIM_SLAVEMODE_RESET ) ;
LL_TIM_SetTriggerOutput ( TIM2 , LL_TIM_TRGO_RESET ) ;
LL_TIM_EnableMasterSlaveMode ( TIM2 ) ;
LL_TIM_DisableDMAReq_TRIG ( TIM2 ) ;
LL_TIM_DisableIT_TRIG ( TIM2 ) ;
// Timer: channel 1 indirect
LL_TIM_IC_SetActiveInput ( TIM2 , LL_TIM_CHANNEL_CH1 , LL_TIM_ACTIVEINPUT_INDIRECTTI ) ;
LL_TIM_IC_SetPrescaler ( TIM2 , LL_TIM_CHANNEL_CH1 , LL_TIM_ICPSC_DIV1 ) ;
LL_TIM_IC_SetPolarity ( TIM2 , LL_TIM_CHANNEL_CH1 , LL_TIM_IC_POLARITY_FALLING ) ;
LL_TIM_IC_SetFilter ( TIM2 , LL_TIM_CHANNEL_CH1 , LL_TIM_IC_FILTER_FDIV1 ) ;
// Timer: channel 2 direct
LL_TIM_IC_SetActiveInput ( TIM2 , LL_TIM_CHANNEL_CH2 , LL_TIM_ACTIVEINPUT_DIRECTTI ) ;
LL_TIM_IC_SetPrescaler ( TIM2 , LL_TIM_CHANNEL_CH2 , LL_TIM_ICPSC_DIV1 ) ;
LL_TIM_IC_SetPolarity ( TIM2 , LL_TIM_CHANNEL_CH2 , LL_TIM_IC_POLARITY_RISING ) ;
2021-09-28 00:05:40 +00:00
LL_TIM_IC_SetFilter ( TIM2 , LL_TIM_CHANNEL_CH2 , LL_TIM_IC_FILTER_FDIV32_N8 ) ;
2021-09-10 02:19:02 +00:00
// ISR setup
2022-03-29 17:37:23 +00:00
furi_hal_interrupt_set_isr ( FuriHalInterruptIdTIM2 , furi_hal_subghz_capture_ISR , NULL ) ;
2021-09-10 02:19:02 +00:00
// Interrupts and channels
LL_TIM_EnableIT_CC1 ( TIM2 ) ;
LL_TIM_EnableIT_CC2 ( TIM2 ) ;
LL_TIM_CC_EnableChannel ( TIM2 , LL_TIM_CHANNEL_CH1 ) ;
LL_TIM_CC_EnableChannel ( TIM2 , LL_TIM_CHANNEL_CH2 ) ;
// Start timer
LL_TIM_SetCounter ( TIM2 , 0 ) ;
LL_TIM_EnableCounter ( TIM2 ) ;
// Switch to RX
furi_hal_subghz_rx ( ) ;
}
void furi_hal_subghz_stop_async_rx ( ) {
furi_assert ( furi_hal_subghz_state = = SubGhzStateAsyncRx ) ;
furi_hal_subghz_state = SubGhzStateIdle ;
// Shutdown radio
furi_hal_subghz_idle ( ) ;
2021-11-30 22:07:17 +00:00
FURI_CRITICAL_ENTER ( ) ;
2021-09-10 02:19:02 +00:00
LL_TIM_DeInit ( TIM2 ) ;
2021-11-30 22:07:17 +00:00
FURI_CRITICAL_EXIT ( ) ;
2022-03-29 17:37:23 +00:00
furi_hal_interrupt_set_isr ( FuriHalInterruptIdTIM2 , NULL , NULL ) ;
2021-09-10 02:19:02 +00:00
2022-03-30 15:23:40 +00:00
furi_hal_gpio_init ( & gpio_cc1101_g0 , GpioModeAnalog , GpioPullNo , GpioSpeedLow ) ;
2021-09-10 02:19:02 +00:00
}
# define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256)
2021-09-15 15:24:19 +00:00
# define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2)
# define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 333
2021-09-10 02:19:02 +00:00
typedef struct {
uint32_t * buffer ;
bool flip_flop ;
FuriHalSubGhzAsyncTxCallback callback ;
void * callback_context ;
2021-12-15 12:23:16 +00:00
uint64_t duty_high ;
uint64_t duty_low ;
2021-09-10 02:19:02 +00:00
} FuriHalSubGhzAsyncTx ;
static FuriHalSubGhzAsyncTx furi_hal_subghz_async_tx = { 0 } ;
static void furi_hal_subghz_async_tx_refill ( uint32_t * buffer , size_t samples ) {
2021-09-15 15:24:19 +00:00
while ( samples > 0 ) {
2021-09-10 02:19:02 +00:00
bool is_odd = samples % 2 ;
2021-09-15 15:24:19 +00:00
LevelDuration ld =
furi_hal_subghz_async_tx . callback ( furi_hal_subghz_async_tx . callback_context ) ;
2021-12-15 12:23:16 +00:00
if ( level_duration_is_wait ( ld ) ) {
return ;
} else if ( level_duration_is_reset ( ld ) ) {
2021-09-10 02:19:02 +00:00
// One more even sample required to end at low level
2021-09-15 15:24:19 +00:00
if ( is_odd ) {
2021-09-10 02:19:02 +00:00
* buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME ;
buffer + + ;
samples - - ;
2021-12-15 12:23:16 +00:00
furi_hal_subghz_async_tx . duty_low + = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME ;
2021-09-10 02:19:02 +00:00
}
break ;
} else {
// Inject guard time if level is incorrect
2021-12-15 12:23:16 +00:00
bool level = level_duration_get_level ( ld ) ;
if ( is_odd = = level ) {
2021-09-10 02:19:02 +00:00
* buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME ;
buffer + + ;
samples - - ;
2021-12-22 11:05:14 +00:00
if ( ! level ) {
2021-12-15 12:23:16 +00:00
furi_hal_subghz_async_tx . duty_high + = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME ;
} else {
furi_hal_subghz_async_tx . duty_low + = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME ;
}
2022-05-08 17:50:20 +00:00
// This code must be invoked only once: when encoder starts with low level.
// Otherwise whole thing will crash.
furi_check ( samples > 0 ) ;
2021-09-10 02:19:02 +00:00
}
uint32_t duration = level_duration_get_duration ( ld ) ;
2021-11-01 20:35:54 +00:00
furi_assert ( duration > 0 ) ;
2021-09-10 02:19:02 +00:00
* buffer = duration ;
buffer + + ;
samples - - ;
2021-12-15 12:23:16 +00:00
2021-12-22 11:05:14 +00:00
if ( level ) {
2021-12-15 12:23:16 +00:00
furi_hal_subghz_async_tx . duty_high + = duration ;
} else {
furi_hal_subghz_async_tx . duty_low + = duration ;
}
2021-09-10 02:19:02 +00:00
}
}
memset ( buffer , 0 , samples * sizeof ( uint32_t ) ) ;
}
static void furi_hal_subghz_async_tx_dma_isr ( ) {
furi_assert ( furi_hal_subghz_state = = SubGhzStateAsyncTx ) ;
2021-09-15 15:24:19 +00:00
if ( LL_DMA_IsActiveFlag_HT1 ( DMA1 ) ) {
2021-09-10 02:19:02 +00:00
LL_DMA_ClearFlag_HT1 ( DMA1 ) ;
2021-09-15 15:24:19 +00:00
furi_hal_subghz_async_tx_refill (
furi_hal_subghz_async_tx . buffer , API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF ) ;
2021-09-10 02:19:02 +00:00
}
2021-09-15 15:24:19 +00:00
if ( LL_DMA_IsActiveFlag_TC1 ( DMA1 ) ) {
2021-09-10 02:19:02 +00:00
LL_DMA_ClearFlag_TC1 ( DMA1 ) ;
2021-09-15 15:24:19 +00:00
furi_hal_subghz_async_tx_refill (
furi_hal_subghz_async_tx . buffer + API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF ,
API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF ) ;
2021-09-10 02:19:02 +00:00
}
}
static void furi_hal_subghz_async_tx_timer_isr ( ) {
if ( LL_TIM_IsActiveFlag_UPDATE ( TIM2 ) ) {
LL_TIM_ClearFlag_UPDATE ( TIM2 ) ;
2021-09-15 15:24:19 +00:00
if ( LL_TIM_GetAutoReload ( TIM2 ) = = 0 ) {
if ( furi_hal_subghz_state = = SubGhzStateAsyncTx ) {
2021-09-10 02:19:02 +00:00
furi_hal_subghz_state = SubGhzStateAsyncTxLast ;
2021-09-28 00:05:40 +00:00
//forcibly pulls the pin to the ground so that there is no carrier
2022-03-30 15:23:40 +00:00
furi_hal_gpio_init ( & gpio_cc1101_g0 , GpioModeInput , GpioPullDown , GpioSpeedLow ) ;
2021-09-10 02:19:02 +00:00
} else {
furi_hal_subghz_state = SubGhzStateAsyncTxEnd ;
LL_TIM_DisableCounter ( TIM2 ) ;
}
}
}
}
2021-09-28 00:05:40 +00:00
bool furi_hal_subghz_start_async_tx ( FuriHalSubGhzAsyncTxCallback callback , void * context ) {
2021-09-10 02:19:02 +00:00
furi_assert ( furi_hal_subghz_state = = SubGhzStateIdle ) ;
furi_assert ( callback ) ;
2021-09-28 00:05:40 +00:00
//If transmission is prohibited by regional settings
if ( furi_hal_subghz_regulation ! = SubGhzRegulationTxRx ) return false ;
2021-09-10 02:19:02 +00:00
furi_hal_subghz_async_tx . callback = callback ;
furi_hal_subghz_async_tx . callback_context = context ;
furi_hal_subghz_state = SubGhzStateAsyncTx ;
2021-12-15 12:23:16 +00:00
furi_hal_subghz_async_tx . duty_low = 0 ;
furi_hal_subghz_async_tx . duty_high = 0 ;
2021-09-15 15:24:19 +00:00
furi_hal_subghz_async_tx . buffer =
2022-02-18 19:53:46 +00:00
malloc ( API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof ( uint32_t ) ) ;
2021-09-15 15:24:19 +00:00
furi_hal_subghz_async_tx_refill (
furi_hal_subghz_async_tx . buffer , API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL ) ;
2021-09-10 02:19:02 +00:00
// Connect CC1101_GD0 to TIM2 as output
2022-03-30 15:23:40 +00:00
furi_hal_gpio_init_ex (
2021-09-15 15:24:19 +00:00
& gpio_cc1101_g0 , GpioModeAltFunctionPushPull , GpioPullDown , GpioSpeedLow , GpioAltFn1TIM2 ) ;
2021-09-10 02:19:02 +00:00
// Configure DMA
LL_DMA_InitTypeDef dma_config = { 0 } ;
2021-09-15 15:24:19 +00:00
dma_config . PeriphOrM2MSrcAddress = ( uint32_t ) & ( TIM2 - > ARR ) ;
2021-09-10 02:19:02 +00:00
dma_config . MemoryOrM2MDstAddress = ( uint32_t ) furi_hal_subghz_async_tx . buffer ;
dma_config . Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH ;
dma_config . Mode = LL_DMA_MODE_CIRCULAR ;
dma_config . PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT ;
dma_config . MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT ;
dma_config . PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD ;
dma_config . MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD ;
dma_config . NbData = API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL ;
dma_config . PeriphRequest = LL_DMAMUX_REQ_TIM2_UP ;
dma_config . Priority = LL_DMA_MODE_NORMAL ;
LL_DMA_Init ( DMA1 , LL_DMA_CHANNEL_1 , & dma_config ) ;
2022-03-29 17:37:23 +00:00
furi_hal_interrupt_set_isr ( FuriHalInterruptIdDma1Ch1 , furi_hal_subghz_async_tx_dma_isr , NULL ) ;
2021-09-10 02:19:02 +00:00
LL_DMA_EnableIT_TC ( DMA1 , LL_DMA_CHANNEL_1 ) ;
LL_DMA_EnableIT_HT ( DMA1 , LL_DMA_CHANNEL_1 ) ;
LL_DMA_EnableChannel ( DMA1 , LL_DMA_CHANNEL_1 ) ;
// Configure TIM2
LL_TIM_InitTypeDef TIM_InitStruct = { 0 } ;
2021-09-15 15:24:19 +00:00
TIM_InitStruct . Prescaler = 64 - 1 ;
2021-09-10 02:19:02 +00:00
TIM_InitStruct . CounterMode = LL_TIM_COUNTERMODE_UP ;
TIM_InitStruct . Autoreload = 1000 ;
TIM_InitStruct . ClockDivision = LL_TIM_CLOCKDIVISION_DIV1 ;
LL_TIM_Init ( TIM2 , & TIM_InitStruct ) ;
LL_TIM_SetClockSource ( TIM2 , LL_TIM_CLOCKSOURCE_INTERNAL ) ;
LL_TIM_EnableARRPreload ( TIM2 ) ;
// Configure TIM2 CH2
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = { 0 } ;
TIM_OC_InitStruct . OCMode = LL_TIM_OCMODE_TOGGLE ;
TIM_OC_InitStruct . OCState = LL_TIM_OCSTATE_DISABLE ;
TIM_OC_InitStruct . OCNState = LL_TIM_OCSTATE_DISABLE ;
TIM_OC_InitStruct . CompareValue = 0 ;
TIM_OC_InitStruct . OCPolarity = LL_TIM_OCPOLARITY_HIGH ;
LL_TIM_OC_Init ( TIM2 , LL_TIM_CHANNEL_CH2 , & TIM_OC_InitStruct ) ;
LL_TIM_OC_DisableFast ( TIM2 , LL_TIM_CHANNEL_CH2 ) ;
LL_TIM_DisableMasterSlaveMode ( TIM2 ) ;
2022-03-29 17:37:23 +00:00
furi_hal_interrupt_set_isr ( FuriHalInterruptIdTIM2 , furi_hal_subghz_async_tx_timer_isr , NULL ) ;
2022-03-28 13:42:31 +00:00
2021-09-10 02:19:02 +00:00
LL_TIM_EnableIT_UPDATE ( TIM2 ) ;
LL_TIM_EnableDMAReq_UPDATE ( TIM2 ) ;
LL_TIM_CC_EnableChannel ( TIM2 , LL_TIM_CHANNEL_CH2 ) ;
// Start counter
LL_TIM_GenerateEvent_UPDATE ( TIM2 ) ;
# ifdef FURI_HAL_SUBGHZ_TX_GPIO
2022-03-30 15:23:40 +00:00
furi_hal_gpio_write ( & FURI_HAL_SUBGHZ_TX_GPIO , true ) ;
2021-09-10 02:19:02 +00:00
# endif
furi_hal_subghz_tx ( ) ;
LL_TIM_SetCounter ( TIM2 , 0 ) ;
LL_TIM_EnableCounter ( TIM2 ) ;
2021-09-28 00:05:40 +00:00
return true ;
2021-09-10 02:19:02 +00:00
}
bool furi_hal_subghz_is_async_tx_complete ( ) {
return furi_hal_subghz_state = = SubGhzStateAsyncTxEnd ;
}
void furi_hal_subghz_stop_async_tx ( ) {
furi_assert (
2021-09-15 15:24:19 +00:00
furi_hal_subghz_state = = SubGhzStateAsyncTx | |
furi_hal_subghz_state = = SubGhzStateAsyncTxLast | |
furi_hal_subghz_state = = SubGhzStateAsyncTxEnd ) ;
2021-09-10 02:19:02 +00:00
// Shutdown radio
furi_hal_subghz_idle ( ) ;
# ifdef FURI_HAL_SUBGHZ_TX_GPIO
2022-03-30 15:23:40 +00:00
furi_hal_gpio_write ( & FURI_HAL_SUBGHZ_TX_GPIO , false ) ;
2021-09-10 02:19:02 +00:00
# endif
// Deinitialize Timer
2021-11-30 22:07:17 +00:00
FURI_CRITICAL_ENTER ( ) ;
2021-09-10 02:19:02 +00:00
LL_TIM_DeInit ( TIM2 ) ;
2022-03-29 17:37:23 +00:00
furi_hal_interrupt_set_isr ( FuriHalInterruptIdTIM2 , NULL , NULL ) ;
2021-09-10 02:19:02 +00:00
// Deinitialize DMA
LL_DMA_DeInit ( DMA1 , LL_DMA_CHANNEL_1 ) ;
2022-03-29 17:37:23 +00:00
furi_hal_interrupt_set_isr ( FuriHalInterruptIdDma1Ch1 , NULL , NULL ) ;
2021-09-10 02:19:02 +00:00
// Deinitialize GPIO
2022-03-30 15:23:40 +00:00
furi_hal_gpio_init ( & gpio_cc1101_g0 , GpioModeAnalog , GpioPullNo , GpioSpeedLow ) ;
2021-11-30 22:07:17 +00:00
FURI_CRITICAL_EXIT ( ) ;
2021-09-10 02:19:02 +00:00
free ( furi_hal_subghz_async_tx . buffer ) ;
2021-12-22 11:05:14 +00:00
float duty_cycle =
100.0f * ( float ) furi_hal_subghz_async_tx . duty_high /
( ( float ) furi_hal_subghz_async_tx . duty_low + ( float ) furi_hal_subghz_async_tx . duty_high ) ;
FURI_LOG_D (
TAG ,
" Async TX Radio stats: on %0.0fus, off %0.0fus, DutyCycle: %0.0f%% " ,
2022-05-11 09:45:01 +00:00
( double ) furi_hal_subghz_async_tx . duty_high ,
( double ) furi_hal_subghz_async_tx . duty_low ,
( double ) duty_cycle ) ;
2021-12-15 12:23:16 +00:00
2021-09-10 02:19:02 +00:00
furi_hal_subghz_state = SubGhzStateIdle ;
}