[FL-950] CC1101 Stage1, SPI Refactoring, Drivers layer (#386)
* API HAL SPI: refactoring, split into layers, prepare ST HAL separation. API HAL SubGhz: initialize on start. Drivers: add basic cc1101 driver. Update API usage. Debug: increase max debugger port speed. Remove subghz apps. * CC1101: chip status handling. ApiHalSpi: increase SubGhz bus speed to 8mhz. F4: backport subghz initialization. * Api Hal SubGhz: rx path and frequency. CC1101: frequency control. * SubGhz Application: basic tests * SubGhz app: tone and packet test. API HAL SUBGHZ: update configs, add missing bits and pieces.
This commit is contained in:
		
							parent
							
								
									5309bfae41
								
							
						
					
					
						commit
						5439e232cc
					
				| @ -16,7 +16,6 @@ int32_t gui_task(void* p); | |||||||
| int32_t backlight_control(void* p); | int32_t backlight_control(void* p); | ||||||
| int32_t irda(void* p); | int32_t irda(void* p); | ||||||
| int32_t app_loader(void* p); | int32_t app_loader(void* p); | ||||||
| int32_t cc1101_workaround(void* p); |  | ||||||
| int32_t lf_rfid_workaround(void* p); | int32_t lf_rfid_workaround(void* p); | ||||||
| int32_t nfc_task(void* p); | int32_t nfc_task(void* p); | ||||||
| int32_t dolphin_task(void* p); | int32_t dolphin_task(void* p); | ||||||
| @ -31,7 +30,7 @@ int32_t music_player(void* p); | |||||||
| int32_t sdnfc(void* p); | int32_t sdnfc(void* p); | ||||||
| int32_t floopper_bloopper(void* p); | int32_t floopper_bloopper(void* p); | ||||||
| int32_t sd_filesystem(void* p); | int32_t sd_filesystem(void* p); | ||||||
| int32_t app_subghz(void* p); | int32_t subghz_app(void* p); | ||||||
| int32_t gui_test(void* p); | int32_t gui_test(void* p); | ||||||
| int32_t keypad_test(void* p); | int32_t keypad_test(void* p); | ||||||
| 
 | 
 | ||||||
| @ -82,13 +81,6 @@ const FlipperApplication FLIPPER_SERVICES[] = { | |||||||
|     {.app = bt_task, .name = "bt_task", .stack_size = 1024, .icon = A_Plugins_14}, |     {.app = bt_task, .name = "bt_task", .stack_size = 1024, .icon = A_Plugins_14}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef APP_CC1101 |  | ||||||
|     {.app = cc1101_workaround, |  | ||||||
|      .name = "cc1101 workaround", |  | ||||||
|      .stack_size = 1024, |  | ||||||
|      .icon = A_Plugins_14}, |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifdef APP_LF_RFID | #ifdef APP_LF_RFID | ||||||
|     {.app = lf_rfid_workaround, |     {.app = lf_rfid_workaround, | ||||||
|      .name = "lf rfid workaround", |      .name = "lf rfid workaround", | ||||||
| @ -151,10 +143,6 @@ const FlipperApplication FLIPPER_SERVICES[] = { | |||||||
|     {.app = gui_test, .name = "gui_test", .stack_size = 1024, .icon = A_Plugins_14}, |     {.app = gui_test, .name = "gui_test", .stack_size = 1024, .icon = A_Plugins_14}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef APP_SUBGHZ |  | ||||||
|     {.app = app_subghz, .name = "app_subghz", .stack_size = 1024, .icon = A_Plugins_14}, |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifdef APP_KEYPAD_TEST | #ifdef APP_KEYPAD_TEST | ||||||
|     {.app = keypad_test, .name = "keypad_test", .icon = A_Plugins_14}, |     {.app = keypad_test, .name = "keypad_test", .icon = A_Plugins_14}, | ||||||
| #endif | #endif | ||||||
| @ -164,8 +152,8 @@ const size_t FLIPPER_SERVICES_COUNT = sizeof(FLIPPER_SERVICES) / sizeof(FlipperA | |||||||
| 
 | 
 | ||||||
| // Main menu APP
 | // Main menu APP
 | ||||||
| const FlipperApplication FLIPPER_APPS[] = { | const FlipperApplication FLIPPER_APPS[] = { | ||||||
| #ifdef BUILD_CC1101 | #ifdef BUILD_SUBGHZ | ||||||
|     {.app = cc1101_workaround, .name = "Sub-1 GHz", .stack_size = 1024, .icon = A_Sub1ghz_14}, |     {.app = subghz_app, .name = "Sub-1 GHz", .stack_size = 1024, .icon = A_Sub1ghz_14}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef BUILD_LF_RFID | #ifdef BUILD_LF_RFID | ||||||
| @ -228,10 +216,6 @@ const FlipperApplication FLIPPER_PLUGINS[] = { | |||||||
|     {.app = gui_test, .name = "gui_test", .stack_size = 1024, .icon = A_Plugins_14}, |     {.app = gui_test, .name = "gui_test", .stack_size = 1024, .icon = A_Plugins_14}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef BUILD_SUBGHZ |  | ||||||
|     {.app = app_subghz, .name = "app_subghz", .stack_size = 1024, .icon = A_Plugins_14}, |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifdef BUILD_KEYPAD_TEST | #ifdef BUILD_KEYPAD_TEST | ||||||
|     {.app = keypad_test, .name = "keypad_test", .icon = A_Plugins_14}, |     {.app = keypad_test, .name = "keypad_test", .icon = A_Plugins_14}, | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ APP_DOLPHIN = 1 | |||||||
| BUILD_EXAMPLE_BLINK = 1 | BUILD_EXAMPLE_BLINK = 1 | ||||||
| BUILD_EXAMPLE_UART_WRITE = 1 | BUILD_EXAMPLE_UART_WRITE = 1 | ||||||
| BUILD_EXAMPLE_INPUT_DUMP = 1 | BUILD_EXAMPLE_INPUT_DUMP = 1 | ||||||
| BUILD_CC1101 = 1 | BUILD_SUBGHZ = 1 | ||||||
| BUILD_LF_RFID = 1 | BUILD_LF_RFID = 1 | ||||||
| BUILD_SPEAKER_DEMO = 1 | BUILD_SPEAKER_DEMO = 1 | ||||||
| BUILD_VIBRO_DEMO = 1 | BUILD_VIBRO_DEMO = 1 | ||||||
| @ -31,7 +31,6 @@ BUILD_FLOOPPER_BLOOPPER = 1 | |||||||
| BUILD_IBUTTON = 1 | BUILD_IBUTTON = 1 | ||||||
| BUILD_GUI_TEST = 1 | BUILD_GUI_TEST = 1 | ||||||
| BUILD_KEYPAD_TEST = 1 | BUILD_KEYPAD_TEST = 1 | ||||||
| BUILD_SUBGHZ = 1 |  | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| APP_NFC ?= 0 | APP_NFC ?= 0 | ||||||
| @ -146,16 +145,9 @@ C_SOURCES	+= $(APP_DIR)/examples/u8g2_qrcode.c | |||||||
| C_SOURCES	+= $(LIB_DIR)/qrcode/qrcode.c | C_SOURCES	+= $(LIB_DIR)/qrcode/qrcode.c | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| APP_CC1101 ?= 0 | ifeq ($(BUILD_SUBGHZ), 1) | ||||||
| ifeq ($(APP_CC1101), 1) | CFLAGS		+= -DBUILD_SUBGHZ | ||||||
| CFLAGS		+= -DAPP_CC1101 | C_SOURCES	+= $(wildcard $(APP_DIR)/subghz/*.c) | ||||||
| BUILD_CC1101 = 1 |  | ||||||
| endif |  | ||||||
| BUILD_CC1101 ?= 0 |  | ||||||
| ifeq ($(BUILD_CC1101), 1) |  | ||||||
| CFLAGS		+= -DBUILD_CC1101 |  | ||||||
| C_SOURCES	+= $(wildcard $(APP_DIR)/cc1101-workaround/*.c) |  | ||||||
| CPP_SOURCES	+= $(wildcard $(APP_DIR)/cc1101-workaround/*.cpp) |  | ||||||
| APP_INPUT = 1 | APP_INPUT = 1 | ||||||
| APP_GUI = 1 | APP_GUI = 1 | ||||||
| APP_CLI = 1 | APP_CLI = 1 | ||||||
| @ -292,18 +284,6 @@ CFLAGS		+= -DBUILD_GUI_TEST | |||||||
| C_SOURCES	+= $(wildcard $(APP_DIR)/gui-test/*.c) | C_SOURCES	+= $(wildcard $(APP_DIR)/gui-test/*.c) | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| APP_SUBGHZ ?= 0 |  | ||||||
| ifeq ($(APP_SUBGHZ), 1) |  | ||||||
| CFLAGS		+= -DAPP_SUBGHZ |  | ||||||
| BUILD_SUBGHZ = 1 |  | ||||||
| endif |  | ||||||
| BUILD_SUBGHZ ?= 0 |  | ||||||
| ifeq ($(BUILD_SUBGHZ), 1) |  | ||||||
| CFLAGS		+= -DBUILD_SUBGHZ |  | ||||||
| CPP_SOURCES	+= $(wildcard $(APP_DIR)/subghz/*.cpp) |  | ||||||
| CPP_SOURCES	+= $(wildcard $(APP_DIR)/subghz/*/*.cpp) |  | ||||||
| endif |  | ||||||
| 
 |  | ||||||
| APP_SDNFC ?= 0 | APP_SDNFC ?= 0 | ||||||
| ifeq ($(APP_SDNFC), 1) | ifeq ($(APP_SDNFC), 1) | ||||||
| CFLAGS		+= -DAPP_SDNFC | CFLAGS		+= -DAPP_SDNFC | ||||||
|  | |||||||
| @ -1,614 +0,0 @@ | |||||||
| #include "cc1101.h" |  | ||||||
| #include <furi.h> |  | ||||||
| #include <api-hal.h> |  | ||||||
| #include <gui/gui.h> |  | ||||||
| #include <input/input.h> |  | ||||||
| 
 |  | ||||||
| #define RSSI_DELAY 5000 //rssi delay in micro second
 |  | ||||||
| #define CHAN_SPA 0.05 // channel spacing
 |  | ||||||
| 
 |  | ||||||
| int16_t rssi_to_dbm(uint8_t rssi_dec, uint8_t rssiOffset) { |  | ||||||
|     int16_t rssi; |  | ||||||
| 
 |  | ||||||
|     if(rssi_dec >= 128) { |  | ||||||
|         rssi = (int16_t)((int16_t)(rssi_dec - 256) / 2) - rssiOffset; |  | ||||||
|     } else { |  | ||||||
|         rssi = (rssi_dec / 2) - rssiOffset; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return rssi; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     float base_freq; |  | ||||||
|     uint8_t reg[3]; // FREQ2, FREQ1, FREQ0
 |  | ||||||
|     uint8_t first_channel; |  | ||||||
|     uint8_t last_channel; |  | ||||||
|     uint8_t rssi_offset; |  | ||||||
| } Band; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     const Band* band; |  | ||||||
|     uint16_t channel; |  | ||||||
| } FreqConfig; |  | ||||||
| 
 |  | ||||||
| void setup_freq(CC1101* cc1101, float freq) { |  | ||||||
|     // cc1101->SpiWriteReg(CC1101_MCSM0, 0x08); // disalbe FS_AUTOCAL
 |  | ||||||
|     // cc1101->SpiWriteReg(CC1101_AGCCTRL2, 0x43 | 0x0C); // MAX_DVGA_GAIN to 11 for fast rssi
 |  | ||||||
|     // cc1101->SpiWriteReg(CC1101_AGCCTRL0, 0xB0); // max AGC WAIT_TIME; 0 filter_length
 |  | ||||||
|     // cc1101->SetMod(GFSK); // set to GFSK for fast rssi measurement | +8 is dcfilter off
 |  | ||||||
| 
 |  | ||||||
|     uint32_t freq_reg = freq * 1e6 / (F_OSC / 65536); |  | ||||||
|     cc1101->SetFreq((freq_reg >> 16) & 0xFF, (freq_reg >> 8) & 0xFF, (freq_reg)&0xFF); |  | ||||||
|     cc1101->SetChannel(0); |  | ||||||
| 
 |  | ||||||
|     /*
 |  | ||||||
|     //set test0 to 0x09
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_TEST0, 0x09); |  | ||||||
|     //set FSCAL2 to 0x2A to force VCO HIGH
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FSCAL2, 0x2A); |  | ||||||
| 
 |  | ||||||
|     // perform a manual calibration by issuing SCAL command
 |  | ||||||
|     cc1101->SpiStrobe(CC1101_SCAL); |  | ||||||
|     */ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static GpioPin debug_0 = {GPIOB, GPIO_PIN_2}; |  | ||||||
| 
 |  | ||||||
| int16_t rx_rssi(CC1101* cc1101, const FreqConfig* config) { |  | ||||||
|     // cc1101->SpiStrobe(CC1101_SFRX);
 |  | ||||||
|     // cc1101->SetReceive();
 |  | ||||||
| 
 |  | ||||||
|     // uint8_t begin_size = cc1101->SpiReadStatus(CC1101_RXBYTES);
 |  | ||||||
|     // uint8_t rx_status = cc1101->SpiReadStatus(CC1101_MARCSTATE);
 |  | ||||||
| 
 |  | ||||||
|     // delay_us(RSSI_DELAY);
 |  | ||||||
|     // osDelay(15);
 |  | ||||||
| 
 |  | ||||||
|     // uint8_t end_size = cc1101->SpiReadStatus(CC1101_RXBYTES);
 |  | ||||||
| 
 |  | ||||||
|     // 1.4.8) read PKTSTATUS register while the radio is in RX state
 |  | ||||||
|     /*uint8_t _pkt_status = */ // cc1101->SpiReadStatus(CC1101_PKTSTATUS);
 |  | ||||||
| 
 |  | ||||||
|     // 1.4.9) enter IDLE state by issuing a SIDLE command
 |  | ||||||
|     // cc1101->SpiStrobe(CC1101_SIDLE);
 |  | ||||||
| 
 |  | ||||||
|     // //read rssi value and converto to dBm form
 |  | ||||||
|     uint8_t rssi_dec = (uint8_t)cc1101->SpiReadStatus(CC1101_RSSI); |  | ||||||
|     int16_t rssi_dBm = rssi_to_dbm(rssi_dec, config->band->rssi_offset); |  | ||||||
| 
 |  | ||||||
|     /*
 |  | ||||||
|     char buf[256]; |  | ||||||
|     sprintf(buf, "status: %d -> %d, rssi: %d\n", rx_status, cc1101->SpiReadStatus(CC1101_MARCSTATE), rssi_dBm); |  | ||||||
|     printf(buf); |  | ||||||
|     sprintf(buf, "begin: %d, end: %d\n", begin_size, end_size); |  | ||||||
|     printf(buf); |  | ||||||
|     */ |  | ||||||
| 
 |  | ||||||
|     // uint8_t rx_data[64];
 |  | ||||||
|     // uint8_t fifo_length = end_size - begin_size;
 |  | ||||||
| 
 |  | ||||||
|     /*
 |  | ||||||
|     if(fifo_length < 64) { |  | ||||||
|         // cc1101->SpiReadBurstReg(CC1101_RXFIFO, rx_data, fifo_length);
 |  | ||||||
| 
 |  | ||||||
|         * |  | ||||||
|         printf("FIFO:"); |  | ||||||
|         for(uint8_t i = 0; i < fifo_length; i++) { |  | ||||||
|             for(uint8_t bit = 0; bit < 8; bit++) { |  | ||||||
|                 printf("%s", (rx_data[i] & (1 << bit)) > 0 ? "1" : "0"); |  | ||||||
|             } |  | ||||||
|             printf(" "); |  | ||||||
|         } |  | ||||||
|         printf("\r\n"); |  | ||||||
|         * |  | ||||||
| 
 |  | ||||||
|         for(uint8_t i = 0; i < fifo_length; i++) { |  | ||||||
|             for(uint8_t bit = 0; bit < 8; bit++) { |  | ||||||
|                 gpio_write((GpioPin*)&debug_0, (rx_data[i] & (1 << bit)) > 0); |  | ||||||
|                 delay_us(5); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         printf("fifo size over\r\n"); |  | ||||||
|     } |  | ||||||
|     */ |  | ||||||
| 
 |  | ||||||
|     return rssi_dBm; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| void flp_config(CC1101* cc1101) { |  | ||||||
|     cc1101->SpiWriteReg( |  | ||||||
|         CC1101_MCSM0, 0x18); // calibrate when going from IDLE to RX or TX ; 149 - 155 μs timeout
 |  | ||||||
|     // MCSM0.FS_AUTOCAL[1:0] = 1
 |  | ||||||
| 
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_AGCCTRL2, 0x43); |  | ||||||
|     cc1101->SpiWriteReg(CC1101_AGCCTRL1, 0x49); |  | ||||||
|     cc1101->SpiWriteReg(CC1101_AGCCTRL0, 0x91); |  | ||||||
| 
 |  | ||||||
|     //freq synthesizer calibration
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FSCAL3, 0xEA); |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FSCAL2, 0x2A); |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FSCAL1, 0x00); |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FSCAL0, 0x1F); |  | ||||||
| 
 |  | ||||||
|     // async data out
 |  | ||||||
|     cc1101->SpiSetRegValue(CC1101_IOCFG0, 13, 5, 0); // GDO0 Output Pin Configuration
 |  | ||||||
|     cc1101->SpiSetRegValue(CC1101_IOCFG0, 13, 5, 0); // WAT
 |  | ||||||
| 
 |  | ||||||
|     // FIFOTHR.ADC_RETENTION = 1
 |  | ||||||
|     cc1101->SpiSetRegValue(CC1101_FIFOTHR, 1, 6, 6); |  | ||||||
| 
 |  | ||||||
|     // PKTCTRL1.APPEND_STATUS = 0
 |  | ||||||
|     cc1101->SpiSetRegValue(CC1101_PKTCTRL1, 0, 2, 2); |  | ||||||
| 
 |  | ||||||
|     // PKTCTRL0.WHITE_DATA = 0
 |  | ||||||
|     cc1101->SpiSetRegValue(CC1101_PKTCTRL0, 0, 6, 6); |  | ||||||
| 
 |  | ||||||
|     // PKTCTRL0.LENGTH_CONFIG = 2 // Infinite packet length mode
 |  | ||||||
|     cc1101->SpiSetRegValue(CC1101_PKTCTRL0, 2, 1, 0); |  | ||||||
| 
 |  | ||||||
|     // PKTCTRL0.CRC_EN = 0
 |  | ||||||
|     cc1101->SpiSetRegValue(CC1101_PKTCTRL0, 0, 2, 2); |  | ||||||
| 
 |  | ||||||
|     // PKTCTRL0.PKT_FORMAT = 3
 |  | ||||||
|     cc1101->SpiSetRegValue(CC1101_PKTCTRL0, 3, 5, 4); |  | ||||||
| 
 |  | ||||||
|     // bandwidth 50-100 kHz
 |  | ||||||
|     if(!cc1101->setRxBandwidth(75.0)) { |  | ||||||
|         printf("wrong rx bw\r\n"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // datarate ~30 kbps
 |  | ||||||
|     if(!cc1101->setBitRate(100.)) { |  | ||||||
|         printf("wrong bitrate\r\n"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // mod
 |  | ||||||
|     // MDMCFG2.MOD_FORMAT = 3 (3: OOK, 0: 2-FSK)
 |  | ||||||
|     cc1101->SpiSetRegValue(CC1101_MDMCFG2, 3, 6, 4); |  | ||||||
|     // MDMCFG2.SYNC_MODE = 0
 |  | ||||||
|     cc1101->SpiSetRegValue(CC1101_MDMCFG2, 0, 2, 0); |  | ||||||
| } |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| void tx_config(CC1101* cc1101) { |  | ||||||
|     // cc1101->SpiWriteReg(CC1101_IOCFG2,0x0B);  //GDO2 Output Pin Configuration
 |  | ||||||
|     // cc1101->SpiWriteReg(CC1101_IOCFG0,0x0C);  //GDO0 Output Pin Configuration
 |  | ||||||
|     cc1101->SpiSetRegValue(CC1101_IOCFG0, 13, 5, 0); // GDO0 Output Pin Configuration
 |  | ||||||
| 
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FIFOTHR, 0x47); //RX FIFO and TX FIFO Thresholds
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_PKTCTRL0, 0x32); //Packet Automation Control
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FSCTRL1, 0x06); //Frequency Synthesizer Control
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FREQ2, 0x10); //Frequency Control Word, High Byte
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FREQ1, 0xB0); //Frequency Control Word, Middle Byte
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FREQ0, 0x71); //Frequency Control Word, Low Byte
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_MDMCFG4, 0x6A); //Modem Configuration
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_MDMCFG3, 0x2E); //Modem Configuration
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_MDMCFG2, 0x30); //Modem Configuration
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_DEVIATN, 0x15); //Modem Deviation Setting
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_MCSM0, 0x18); //Main Radio Control State Machine Configuration
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FOCCFG, 0x16); //Frequency Offset Compensation Configuration
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_WORCTRL, 0xFB); //Wake On Radio Control
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FREND0, 0x11); //Front End TX Configuration
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FSCAL3, 0xE9); //Frequency Synthesizer Calibration
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FSCAL2, 0x2A); //Frequency Synthesizer Calibration
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FSCAL1, 0x00); //Frequency Synthesizer Calibration
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_FSCAL0, 0x1F); //Frequency Synthesizer Calibration
 |  | ||||||
| 
 |  | ||||||
|     /*
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_TEST2, 0x81); //Various Test Settings
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_TEST1, 0x35); //Various Test Settings
 |  | ||||||
|     cc1101->SpiWriteReg(CC1101_TEST0, 0x09); //Various Test Settings
 |  | ||||||
|     */ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // f = (f_osc/65536) * (FREQ + CHAN * (256 + CH_SP_M) * 2^(CH_SP_E - 2))
 |  | ||||||
| // FREQ = f / (f_osc/65536)
 |  | ||||||
| // CHAN = 0
 |  | ||||||
| // TODO: CHAN number not implemented!
 |  | ||||||
| // TODO: reg values not affetcts
 |  | ||||||
| 
 |  | ||||||
| const Band bands[] = { |  | ||||||
|     {301., {0x00, 0x00, 0x00}, 0, 255, 74}, |  | ||||||
|     {315., {0x00, 0x00, 0x00}, 0, 255, 74}, |  | ||||||
|     {346., {0x00, 0x00, 0x00}, 0, 255, 74}, |  | ||||||
|     {385., {0x00, 0x00, 0x00}, 0, 255, 74}, |  | ||||||
|     {433.92, {0x00, 0x00, 0x00}, 0, 255, 74}, |  | ||||||
|     {438.9, {0x00, 0x00, 0x00}, 0, 255, 74}, |  | ||||||
|     {463., {0x00, 0x00, 0x00}, 0, 255, 74}, |  | ||||||
|     {781., {0x00, 0x00, 0x00}, 0, 255, 74}, |  | ||||||
|     {868., {0x00, 0x00, 0x00}, 0, 255, 74}, |  | ||||||
|     {915., {0x00, 0x00, 0x00}, 0, 255, 74}, |  | ||||||
|     {925., {0x00, 0x00, 0x00}, 0, 255, 74}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const FreqConfig FREQ_LIST[] = { |  | ||||||
|     {&bands[0], 0}, |  | ||||||
|     {&bands[1], 0}, |  | ||||||
|     {&bands[2], 0}, |  | ||||||
|     {&bands[3], 0}, |  | ||||||
|     {&bands[4], 0}, |  | ||||||
|     {&bands[5], 0}, |  | ||||||
|     {&bands[6], 0}, |  | ||||||
|     {&bands[7], 0}, |  | ||||||
|     {&bands[8], 0}, |  | ||||||
|     {&bands[9], 0}, |  | ||||||
|     {&bands[10], 0}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| extern "C" void cc1101_isr(void* _pin, void* _ctx) { |  | ||||||
|     uint32_t pin = (uint32_t)_pin; |  | ||||||
|     if(pin == CC1101_G0_Pin) { |  | ||||||
|         gpio_write((GpioPin*)&debug_0, gpio_read(&cc1101_g0_gpio)); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| typedef enum { |  | ||||||
|     EventTypeTick, |  | ||||||
|     EventTypeKey, |  | ||||||
| } EventType; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     union { |  | ||||||
|         InputEvent input; |  | ||||||
|     } value; |  | ||||||
|     EventType type; |  | ||||||
| } AppEvent; |  | ||||||
| 
 |  | ||||||
| typedef enum { ModeRx, ModeTx } Mode; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     int16_t dbm; |  | ||||||
|     uint8_t reg; |  | ||||||
| } TxLevel; |  | ||||||
| 
 |  | ||||||
| const TxLevel TX_LEVELS[] = { |  | ||||||
|     {-10, 0}, |  | ||||||
|     {-5, 0}, |  | ||||||
|     {0, 0}, |  | ||||||
|     {5, 0}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     Mode mode; |  | ||||||
|     size_t active_freq_idx; |  | ||||||
|     float active_freq; |  | ||||||
|     int16_t last_rssi; |  | ||||||
|     size_t tx_level; |  | ||||||
|     bool need_cc1101_conf; |  | ||||||
|     RfBand rf_band; |  | ||||||
| } State; |  | ||||||
| 
 |  | ||||||
| static void render_callback(Canvas* canvas, void* ctx) { |  | ||||||
|     State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25); |  | ||||||
| 
 |  | ||||||
|     if(!state) return; |  | ||||||
| 
 |  | ||||||
|     canvas_clear(canvas); |  | ||||||
|     canvas_set_color(canvas, ColorBlack); |  | ||||||
|     canvas_set_font(canvas, FontPrimary); |  | ||||||
|     canvas_draw_str(canvas, 2, 12, "cc1101 workaround"); |  | ||||||
| 
 |  | ||||||
|     { |  | ||||||
|         char buf[24]; |  | ||||||
|         sprintf( |  | ||||||
|             buf, |  | ||||||
|             "freq: %ld.%02ld MHz", |  | ||||||
|             (uint32_t)state->active_freq, |  | ||||||
|             (uint32_t)(state->active_freq * 100.) % 100); |  | ||||||
| 
 |  | ||||||
|         canvas_set_font(canvas, FontSecondary); |  | ||||||
|         canvas_draw_str(canvas, 2, 25, buf); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     { |  | ||||||
|         canvas_set_font(canvas, FontSecondary); |  | ||||||
| 
 |  | ||||||
|         if(state->need_cc1101_conf) { |  | ||||||
|             canvas_draw_str(canvas, 2, 36, "mode: configuring..."); |  | ||||||
|         } else if(state->mode == ModeRx) { |  | ||||||
|             canvas_draw_str(canvas, 2, 36, "mode: RX"); |  | ||||||
|         } else if(state->mode == ModeTx) { |  | ||||||
|             canvas_draw_str(canvas, 2, 36, "mode: TX"); |  | ||||||
|         } else { |  | ||||||
|             canvas_draw_str(canvas, 2, 36, "mode: unknown"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     { |  | ||||||
|         if(!state->need_cc1101_conf && state->mode == ModeRx) { |  | ||||||
|             char buf[24]; |  | ||||||
|             sprintf(buf, "RSSI: %d dBm", state->last_rssi); |  | ||||||
| 
 |  | ||||||
|             canvas_set_font(canvas, FontSecondary); |  | ||||||
|             canvas_draw_str(canvas, 2, 48, buf); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     { |  | ||||||
|         char buf[24]; |  | ||||||
|         // sprintf(buf, "tx level: %d dBm", TX_LEVELS[state->tx_level].dbm);
 |  | ||||||
|         sprintf(buf, "RF band: %d", (uint8_t)state->rf_band); |  | ||||||
| 
 |  | ||||||
|         canvas_set_font(canvas, FontSecondary); |  | ||||||
|         if(state->rf_band == RfBandIsolation) { |  | ||||||
|             canvas_draw_str(canvas, 2, 63, "RF band: isolation"); |  | ||||||
|         } else { |  | ||||||
|             canvas_draw_str(canvas, 2, 63, buf); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     release_mutex((ValueMutex*)ctx, state); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void input_callback(InputEvent* input_event, void* ctx) { |  | ||||||
|     osMessageQueueId_t event_queue = ctx; |  | ||||||
| 
 |  | ||||||
|     AppEvent event; |  | ||||||
|     event.type = EventTypeKey; |  | ||||||
|     event.value.input = *input_event; |  | ||||||
|     osMessageQueuePut(event_queue, &event, 0, 0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| extern "C" int32_t cc1101_workaround(void* p) { |  | ||||||
|     osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL); |  | ||||||
|     furi_check(event_queue); |  | ||||||
| 
 |  | ||||||
|     State _state; |  | ||||||
|     _state.mode = ModeRx; |  | ||||||
|     _state.active_freq_idx = 4; |  | ||||||
| 
 |  | ||||||
|     FreqConfig conf = FREQ_LIST[_state.active_freq_idx]; |  | ||||||
|     _state.active_freq = conf.band->base_freq + CHAN_SPA * conf.channel; |  | ||||||
| 
 |  | ||||||
|     _state.need_cc1101_conf = true; |  | ||||||
|     _state.last_rssi = 0; |  | ||||||
|     _state.tx_level = 0; |  | ||||||
|     _state.rf_band = RfBand1; |  | ||||||
| 
 |  | ||||||
|     ValueMutex state_mutex; |  | ||||||
|     if(!init_mutex(&state_mutex, &_state, sizeof(State))) { |  | ||||||
|         printf("[cc1101] cannot create mutex\r\n"); |  | ||||||
|         return 255; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ViewPort* view_port = view_port_alloc(); |  | ||||||
| 
 |  | ||||||
|     view_port_draw_callback_set(view_port, render_callback, &state_mutex); |  | ||||||
|     view_port_input_callback_set(view_port, input_callback, event_queue); |  | ||||||
| 
 |  | ||||||
|     // Open GUI and register view_port
 |  | ||||||
|     Gui* gui = (Gui*)furi_record_open("gui"); |  | ||||||
|     if(gui == NULL) { |  | ||||||
|         printf("[cc1101] gui is not available\r\n"); |  | ||||||
|         return 255; |  | ||||||
|     } |  | ||||||
|     gui_add_view_port(gui, view_port, GuiLayerFullscreen); |  | ||||||
| 
 |  | ||||||
|     gpio_init(&debug_0, GpioModeOutputPushPull); |  | ||||||
|     gpio_write((GpioPin*)&debug_0, false); |  | ||||||
| 
 |  | ||||||
|     printf("[cc1101] creating device\r\n"); |  | ||||||
|     GpioPin cs_pin = {CC1101_CS_GPIO_Port, CC1101_CS_Pin}; |  | ||||||
| 
 |  | ||||||
|     gpio_init(&cc1101_g0_gpio, GpioModeInput); |  | ||||||
|     api_interrupt_add(cc1101_isr, InterruptTypeExternalInterrupt, NULL); |  | ||||||
|     // TODO open record
 |  | ||||||
|     GpioPin* cs_pin_record = &cs_pin; |  | ||||||
|     CC1101 cc1101(cs_pin_record); |  | ||||||
|     printf("[cc1101] init device\r\n"); |  | ||||||
| 
 |  | ||||||
|     uint8_t address = cc1101.Init(); |  | ||||||
|     if(address > 0) { |  | ||||||
|         printf("[cc1101] init done: %d\r\n", address); |  | ||||||
|     } else { |  | ||||||
|         printf("[cc1101] init fail\r\n"); |  | ||||||
|         return 255; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     cc1101.SpiStrobe(CC1101_SIDLE); |  | ||||||
| 
 |  | ||||||
|     // flp_config(&cc1101);
 |  | ||||||
|     tx_config(&cc1101); |  | ||||||
|     // setup_freq(&cc1101, &FREQ_LIST[4]);
 |  | ||||||
|     // enable_cc1101_irq();
 |  | ||||||
| 
 |  | ||||||
|     printf("init ok\r\n"); |  | ||||||
| 
 |  | ||||||
|     const int16_t RSSI_THRESHOLD = -60; |  | ||||||
| 
 |  | ||||||
|     // setup_freq(&cc1101, &FREQ_LIST[1]);
 |  | ||||||
| 
 |  | ||||||
|     cc1101.SetReceive(); |  | ||||||
| 
 |  | ||||||
|     AppEvent event; |  | ||||||
|     while(1) { |  | ||||||
|         osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 100); |  | ||||||
|         State* state = (State*)acquire_mutex_block(&state_mutex); |  | ||||||
| 
 |  | ||||||
|         if(event_status == osOK) { |  | ||||||
|             if(event.type == EventTypeKey) { |  | ||||||
|                 if(event.value.input.type == InputTypeShort && |  | ||||||
|                    event.value.input.key == InputKeyBack) { |  | ||||||
|                     printf("[cc1101] bye!\r\n"); |  | ||||||
| 
 |  | ||||||
|                     cc1101.SpiStrobe(CC1101_SIDLE); |  | ||||||
|                     cc1101.SpiStrobe(CC1101_SPWD); |  | ||||||
| 
 |  | ||||||
|                     printf("[cc1101] go to power down\r\n"); |  | ||||||
| 
 |  | ||||||
|                     // TODO remove all view_ports create by app
 |  | ||||||
|                     view_port_enabled_set(view_port, false); |  | ||||||
|                     return 255; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 if(event.value.input.type == InputTypeShort && |  | ||||||
|                    event.value.input.key == InputKeyDown) { |  | ||||||
|                     if(state->active_freq_idx > 0) { |  | ||||||
|                         state->active_freq_idx--; |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     FreqConfig conf = FREQ_LIST[state->active_freq_idx]; |  | ||||||
|                     state->active_freq = conf.band->base_freq + CHAN_SPA * conf.channel; |  | ||||||
|                     state->need_cc1101_conf = true; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 if(event.value.input.type == InputTypeShort && |  | ||||||
|                    event.value.input.key == InputKeyUp) { |  | ||||||
|                     if(state->active_freq_idx < (sizeof(FREQ_LIST) / sizeof(FREQ_LIST[0]) - 1)) { |  | ||||||
|                         state->active_freq_idx++; |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     FreqConfig conf = FREQ_LIST[state->active_freq_idx]; |  | ||||||
|                     state->active_freq = conf.band->base_freq + CHAN_SPA * conf.channel; |  | ||||||
|                     state->need_cc1101_conf = true; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 if(event.value.input.type == InputTypeShort && |  | ||||||
|                    event.value.input.key == InputKeyRight) { |  | ||||||
|                     /*
 |  | ||||||
|                     if(state->tx_level < (sizeof(TX_LEVELS) / sizeof(TX_LEVELS[0]) - 1)) { |  | ||||||
|                         state->tx_level++; |  | ||||||
|                     } else { |  | ||||||
|                         state->tx_level = 0; |  | ||||||
|                     } |  | ||||||
|                     */ |  | ||||||
| 
 |  | ||||||
|                     if(state->rf_band < RfBand3) { |  | ||||||
|                         state->rf_band = (RfBand)((uint8_t)state->rf_band + 1); |  | ||||||
|                     } else { |  | ||||||
|                         state->active_freq += 0.25; |  | ||||||
|                     } |  | ||||||
|                     state->need_cc1101_conf = true; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 if(event.value.input.type == InputTypeShort && |  | ||||||
|                    event.value.input.key == InputKeyLeft) { |  | ||||||
|                     /*
 |  | ||||||
|                     if(state->tx_level < (sizeof(TX_LEVELS) / sizeof(TX_LEVELS[0]) - 1)) { |  | ||||||
|                         state->tx_level++; |  | ||||||
|                     } else { |  | ||||||
|                         state->tx_level = 0; |  | ||||||
|                     } |  | ||||||
|                     */ |  | ||||||
| 
 |  | ||||||
|                     if(state->rf_band > RfBandIsolation) { |  | ||||||
|                         state->rf_band = (RfBand)((uint8_t)state->rf_band - 1); |  | ||||||
|                     } else { |  | ||||||
|                         state->active_freq -= 0.25; |  | ||||||
|                     } |  | ||||||
|                     state->need_cc1101_conf = true; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 if(event.value.input.key == InputKeyOk) { |  | ||||||
|                     if(event.value.input.type == InputTypePress) { |  | ||||||
|                         state->mode = ModeTx; |  | ||||||
|                         state->need_cc1101_conf = true; |  | ||||||
|                     } else if(event.value.input.type == InputTypeRelease) { |  | ||||||
|                         state->mode = ModeRx; |  | ||||||
|                         state->need_cc1101_conf = true; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(state->need_cc1101_conf) { |  | ||||||
|             if(state->mode == ModeRx) { |  | ||||||
|                 cc1101.SpiStrobe(CC1101_SIDLE); |  | ||||||
|                 gpio_init(&cc1101_g0_gpio, GpioModeInput); |  | ||||||
| 
 |  | ||||||
|                 setup_freq(&cc1101, state->active_freq); |  | ||||||
|                 cc1101.SetReceive(); |  | ||||||
| 
 |  | ||||||
|                 state->last_rssi = rx_rssi(&cc1101, &FREQ_LIST[state->active_freq_idx]); |  | ||||||
|             } else if(state->mode == ModeTx) { |  | ||||||
|                 cc1101.SpiStrobe(CC1101_SIDLE); |  | ||||||
| 
 |  | ||||||
|                 setup_freq(&cc1101, state->active_freq); |  | ||||||
|                 cc1101.SetTransmit(); |  | ||||||
|                 gpio_init(&cc1101_g0_gpio, GpioModeOutputPushPull); |  | ||||||
|                 gpio_write(&cc1101_g0_gpio, false); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             api_hal_rf_band_set(state->rf_band); |  | ||||||
| 
 |  | ||||||
|             state->need_cc1101_conf = false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(!state->need_cc1101_conf && state->mode == ModeRx) { |  | ||||||
|             // TOOD what about rssi offset
 |  | ||||||
|             state->last_rssi = rx_rssi(&cc1101, &FREQ_LIST[state->active_freq_idx]); |  | ||||||
| 
 |  | ||||||
|             api_hal_light_set(LightGreen, state->last_rssi > RSSI_THRESHOLD ? 0xFF : 0x00); |  | ||||||
|         } else if(!state->need_cc1101_conf && state->mode == ModeTx) { |  | ||||||
|             /*
 |  | ||||||
|             const uint8_t data = 0xA5; |  | ||||||
| 
 |  | ||||||
|             for(uint8_t i = 0; i < 8; i++) { |  | ||||||
|                 gpio_write(&cc1101_g0_gpio, (data & (1 << i)) > 0); |  | ||||||
|                 osDelay(1); |  | ||||||
|             } |  | ||||||
|             gpio_write(&cc1101_g0_gpio, false); |  | ||||||
|             */ |  | ||||||
| 
 |  | ||||||
|             /*
 |  | ||||||
|             // BELL UDB-Q022-0000
 |  | ||||||
|             const uint16_t HALF_PERIOD = 500; |  | ||||||
| 
 |  | ||||||
|             for(uint8_t n = 0; n < 4; n++) { |  | ||||||
|                 for(uint8_t i = 0; i < 4; i++) { |  | ||||||
|                     gpio_write(&cc1101_g0_gpio, true); |  | ||||||
|                     delay_us(3 * HALF_PERIOD); |  | ||||||
|                     gpio_write(&cc1101_g0_gpio, false); |  | ||||||
|                     delay_us(HALF_PERIOD); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 for(uint8_t i = 0; i < 40; i++) { |  | ||||||
|                     gpio_write(&cc1101_g0_gpio, true); |  | ||||||
|                     delay_us(HALF_PERIOD); |  | ||||||
|                     gpio_write(&cc1101_g0_gpio, false); |  | ||||||
|                     delay_us(HALF_PERIOD); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             */ |  | ||||||
| 
 |  | ||||||
|             // BELL ERA C61, static code
 |  | ||||||
|             const uint16_t ONE_ON = 150; |  | ||||||
|             const uint16_t ONE_OFF = 400; |  | ||||||
|             const uint16_t ZERO_ON = 420; |  | ||||||
|             const uint16_t ZERO_OFF = 130; |  | ||||||
| 
 |  | ||||||
|             const bool SEQ[] = {true,  true, false, false, true,  false, true,  false, true, |  | ||||||
|                                 false, true, true,  true,  false, true,  false, true,  true, |  | ||||||
|                                 true,  true, true,  false, true,  false, true}; |  | ||||||
| 
 |  | ||||||
|             for(uint8_t n = 0; n < 10; n++) { |  | ||||||
|                 for(uint8_t i = 0; i < sizeof(SEQ) / sizeof(SEQ[0]); i++) { |  | ||||||
|                     if(SEQ[i]) { |  | ||||||
|                         gpio_write(&cc1101_g0_gpio, false); |  | ||||||
|                         delay_us(ONE_ON); |  | ||||||
|                         gpio_write(&cc1101_g0_gpio, true); |  | ||||||
|                         delay_us(ONE_OFF); |  | ||||||
|                     } else { |  | ||||||
|                         gpio_write(&cc1101_g0_gpio, false); |  | ||||||
|                         delay_us(ZERO_ON); |  | ||||||
|                         gpio_write(&cc1101_g0_gpio, true); |  | ||||||
|                         delay_us(ZERO_OFF); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 osDelay(4); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             gpio_write(&cc1101_g0_gpio, false); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         release_mutex(&state_mutex, state); |  | ||||||
|         view_port_update(view_port); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| @ -1,485 +0,0 @@ | |||||||
| #include <furi.h> |  | ||||||
| #include <api-hal.h> |  | ||||||
| 
 |  | ||||||
| #include "cc1101-workaround/cc1101.h" |  | ||||||
| #include "spi.h" |  | ||||||
| #include <math.h> |  | ||||||
| 
 |  | ||||||
| // ******************************************************************************
 |  | ||||||
| #define WRITE_BURST 0x40 |  | ||||||
| #define READ_SINGLE 0x80 |  | ||||||
| #define READ_BURST 0xC0 |  | ||||||
| #define BYTES_IN_FIFO 0x7F //used to detect FIFO underflow or overflow
 |  | ||||||
| 
 |  | ||||||
| /*********************ss_pin as global variable****************************** */ |  | ||||||
| /*                         cc1101                                       */ |  | ||||||
| /******************************************************************************/ |  | ||||||
| GpioPin ss_pin; |  | ||||||
| 
 |  | ||||||
| CC1101::CC1101(GpioPin* ss_pin) { |  | ||||||
|     /*
 |  | ||||||
|     pinMode(gdo0_pin, OUTPUT); //GDO0 as asynchronous serial mode input
 |  | ||||||
|     pinMode(gdo2_pin, INPUT); //GDO2 as asynchronous serial mode output
 |  | ||||||
|     */ |  | ||||||
|     gpio_init(ss_pin, GpioModeOutputPushPull); |  | ||||||
|     this->ss_pin = ss_pin; |  | ||||||
| 
 |  | ||||||
|     // TODO open record
 |  | ||||||
|     this->miso_pin = MISO_PIN; |  | ||||||
|     this->miso_pin_record = &this->miso_pin; |  | ||||||
| } |  | ||||||
| //******************************************************************************
 |  | ||||||
| //SpiInit
 |  | ||||||
| /******************************************************************************/ |  | ||||||
| extern SPI_HandleTypeDef SPI_R; |  | ||||||
| void CC1101::SpiInit(void) { |  | ||||||
|     //initialize spi pins
 |  | ||||||
| 
 |  | ||||||
|     //Enable spi master, MSB, SPI mode 0, FOSC/4
 |  | ||||||
|     SpiMode(0); |  | ||||||
| 
 |  | ||||||
|     CC1101_SPI_Reconfigure(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void CC1101::SpiEnd(void) { |  | ||||||
|     /*
 |  | ||||||
|     SPCR = ((0<<SPE) |                  // SPI Enable
 |  | ||||||
|         (0<<SPIE)|                      // SPI Interupt Enable
 |  | ||||||
|         (0<<DORD)|                      // Data Order (0:MSB first / 1:LSB first)
 |  | ||||||
|         (1<<MSTR)|                      // Master/Slave select
 |  | ||||||
|         (0<<SPR1)|(0<<SPR0)|        // SPI Clock Rate ( 0 0 = osc/4; 0 1 = osc/16; 1 0 = osc/64; 1 1= 0sc/128)
 |  | ||||||
|         (0<<CPOL)|                  // Clock Polarity (0:SCK low / 1:SCK hi when idle)
 |  | ||||||
|         (0<<CPHA));                     // Clock Phase (0:leading / 1:trailing edge sampling)
 |  | ||||||
| 
 |  | ||||||
|     //SPSR =  (0<<SPI2X);                   // Double Clock Rate
 |  | ||||||
|     */ |  | ||||||
| } |  | ||||||
| /******************************************************************************
 |  | ||||||
| Function: SpiMode |  | ||||||
|  *INPUT        :        config               mode |  | ||||||
|                (0<<CPOL) | (0 << CPHA)       0 |  | ||||||
|                (0<<CPOL) | (1 << CPHA)       1 |  | ||||||
|                (1<<CPOL) | (0 << CPHA)       2 |  | ||||||
|                (1<<CPOL) | (1 << CPHA)       3 |  | ||||||
| *OUTPUT       :none |  | ||||||
| ******************************************************************************/ |  | ||||||
| void CC1101::SpiMode(uint8_t config) { |  | ||||||
|     /*
 |  | ||||||
|   uint8_t tmp; |  | ||||||
|   // enable SPI master with configuration byte specified
 |  | ||||||
|   SPCR = 0; |  | ||||||
|   SPCR = (config & 0x7F) | (1<<SPE) | (1<<MSTR); |  | ||||||
|   tmp = SPSR; |  | ||||||
|   tmp = SPDR; |  | ||||||
|   */ |  | ||||||
| } |  | ||||||
| /****************************************************************
 |  | ||||||
| *FUNCTION NAME:SpiTransfer |  | ||||||
| *FUNCTION     :spi transfer |  | ||||||
| *INPUT        :value: data to send |  | ||||||
| *OUTPUT       :data to receive |  | ||||||
| ****************************************************************/ |  | ||||||
| uint8_t CC1101::SpiTransfer(uint8_t value) { |  | ||||||
|     uint8_t buf[1] = {value}; |  | ||||||
|     uint8_t rxbuf[1] = {0}; |  | ||||||
| 
 |  | ||||||
|     HAL_SPI_TransmitReceive(&SPI_R, buf, rxbuf, 1, HAL_MAX_DELAY); |  | ||||||
| 
 |  | ||||||
|     return rxbuf[0]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t last_status; |  | ||||||
| 
 |  | ||||||
| /****************************************************************
 |  | ||||||
| *FUNCTION NAME:SpiWriteReg |  | ||||||
| *FUNCTION     :CC1101 write data to register |  | ||||||
| *INPUT        :addr: register address; value: register value |  | ||||||
| *OUTPUT       :none |  | ||||||
| ****************************************************************/ |  | ||||||
| void CC1101::SpiWriteReg(uint8_t addr, uint8_t value) { |  | ||||||
|     gpio_write(ss_pin, false); |  | ||||||
|     while(gpio_read(this->miso_pin_record)) |  | ||||||
|         ; |  | ||||||
| 
 |  | ||||||
|     last_status = SpiTransfer(addr); |  | ||||||
|     last_status = SpiTransfer(value); |  | ||||||
|     gpio_write(ss_pin, true); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /****************************************************************
 |  | ||||||
| *FUNCTION NAME:SpiWriteBurstReg |  | ||||||
| *FUNCTION     :CC1101 write burst data to register |  | ||||||
| *INPUT        :addr: register address; buffer:register value array; num:number to write |  | ||||||
| *OUTPUT       :none |  | ||||||
| ****************************************************************/ |  | ||||||
| void CC1101::SpiWriteBurstReg(uint8_t addr, uint8_t* buffer, uint8_t num) { |  | ||||||
|     gpio_write(ss_pin, false); |  | ||||||
|     while(gpio_read(this->miso_pin_record)) |  | ||||||
|         ; |  | ||||||
|     last_status = SpiTransfer(addr | WRITE_BURST); |  | ||||||
|     for(uint8_t i = 0; i < num; i++) { |  | ||||||
|         last_status = SpiTransfer(buffer[i]); |  | ||||||
|     } |  | ||||||
|     gpio_write(ss_pin, true); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /****************************************************************
 |  | ||||||
| *FUNCTION NAME:SpiStrobe |  | ||||||
| *FUNCTION     :CC1101 Strobe |  | ||||||
| *INPUT        :strobe: command; //refer define in CC1101.h//
 |  | ||||||
| *OUTPUT       :none |  | ||||||
| ****************************************************************/ |  | ||||||
| void CC1101::SpiStrobe(uint8_t strobe) { |  | ||||||
|     gpio_write(ss_pin, false); |  | ||||||
|     while(gpio_read(this->miso_pin_record)) |  | ||||||
|         ; |  | ||||||
|     last_status = SpiTransfer(strobe); |  | ||||||
|     gpio_write(ss_pin, true); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /****************************************************************
 |  | ||||||
| *FUNCTION NAME:SpiReadReg |  | ||||||
| *FUNCTION     :CC1101 read data from register |  | ||||||
| *INPUT        :addr: register address |  | ||||||
| *OUTPUT       :register value |  | ||||||
| ****************************************************************/ |  | ||||||
| uint8_t CC1101::SpiReadReg(uint8_t addr) { |  | ||||||
|     gpio_write(ss_pin, false); |  | ||||||
|     while(gpio_read(this->miso_pin_record)) |  | ||||||
|         ; |  | ||||||
|     last_status = SpiTransfer(addr | READ_SINGLE); |  | ||||||
|     uint8_t value = SpiTransfer(0); |  | ||||||
|     gpio_write(ss_pin, true); |  | ||||||
| 
 |  | ||||||
|     return value; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /****************************************************************
 |  | ||||||
| *FUNCTION NAME:SpiReadBurstReg |  | ||||||
| *FUNCTION     :CC1101 read burst data from register |  | ||||||
| *INPUT        :addr: register address; buffer:array to store register value; num: number to read |  | ||||||
| *OUTPUT       :none |  | ||||||
| ****************************************************************/ |  | ||||||
| void CC1101::SpiReadBurstReg(uint8_t addr, uint8_t* buffer, uint8_t num) { |  | ||||||
|     gpio_write(ss_pin, false); |  | ||||||
|     while(gpio_read(this->miso_pin_record)) |  | ||||||
|         ; |  | ||||||
|     last_status = SpiTransfer(addr | READ_BURST); |  | ||||||
|     for(uint8_t i = 0; i < num; i++) { |  | ||||||
|         buffer[i] = SpiTransfer(0); |  | ||||||
|     } |  | ||||||
|     gpio_write(ss_pin, true); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /****************************************************************
 |  | ||||||
| *FUNCTION NAME:SpiReadStatus |  | ||||||
| *FUNCTION     :CC1101 read status register |  | ||||||
| *INPUT        :addr: register address |  | ||||||
| *OUTPUT       :status value |  | ||||||
| ****************************************************************/ |  | ||||||
| uint8_t CC1101::SpiReadStatus(uint8_t addr) { |  | ||||||
|     gpio_write(ss_pin, false); |  | ||||||
|     while(gpio_read(this->miso_pin_record)) |  | ||||||
|         ; |  | ||||||
|     last_status = SpiTransfer(addr | READ_BURST); |  | ||||||
|     uint8_t value = SpiTransfer(0); |  | ||||||
|     gpio_write(ss_pin, true); |  | ||||||
| 
 |  | ||||||
|     return value; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /****************************************************************
 |  | ||||||
| *FUNCTION NAME:Reset |  | ||||||
| *FUNCTION     :CC1101 reset //details refer datasheet of CC1101/CC1100//
 |  | ||||||
| *INPUT        :none |  | ||||||
| *OUTPUT       :none |  | ||||||
| ****************************************************************/ |  | ||||||
| void CC1101::Reset(void) { |  | ||||||
|     gpio_write(ss_pin, false); |  | ||||||
|     delay(1); |  | ||||||
|     gpio_write(ss_pin, true); |  | ||||||
|     delay(1); |  | ||||||
|     gpio_write(ss_pin, false); |  | ||||||
|     while(gpio_read(this->miso_pin_record)) |  | ||||||
|         ; |  | ||||||
|     last_status = SpiTransfer(CC1101_SRES); |  | ||||||
|     while(gpio_read(this->miso_pin_record)) |  | ||||||
|         ; |  | ||||||
|     gpio_write(ss_pin, true); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool CC1101::SpiSetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb) { |  | ||||||
|     if((msb > 7) || (lsb > 7) || (lsb > msb)) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     uint8_t current_value = SpiReadReg(reg); |  | ||||||
|     uint8_t mask = ~((0b11111111 << (msb + 1)) | (0b11111111 >> (8 - lsb))); |  | ||||||
|     uint8_t new_value = (current_value & ~mask) | (value & mask); |  | ||||||
|     SpiWriteReg(reg, new_value); |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /****************************************************************
 |  | ||||||
| *FUNCTION NAME:Init |  | ||||||
| *FUNCTION     :CC1101 initialization |  | ||||||
| *INPUT        :none |  | ||||||
| *OUTPUT       :none |  | ||||||
| ****************************************************************/ |  | ||||||
| uint8_t CC1101::Init(void) { |  | ||||||
| #ifdef CC1101_DEBUG |  | ||||||
|     printf("Init SPI...\r\n"); |  | ||||||
| #endif |  | ||||||
|     SpiInit(); //spi initialization
 |  | ||||||
|     gpio_write(ss_pin, true); |  | ||||||
| // gpio_write(SCK_PIN, true);
 |  | ||||||
| // gpio_write(MOSI_PIN, false);
 |  | ||||||
| #ifdef CC1101_DEBUG |  | ||||||
|     printf("Reset CC1101...\r\n"); |  | ||||||
| #endif |  | ||||||
|     Reset(); // CC1101 reset
 |  | ||||||
| 
 |  | ||||||
|     osDelay(150); |  | ||||||
| 
 |  | ||||||
|     uint8_t partnum __attribute__((unused)); |  | ||||||
|     uint8_t version; |  | ||||||
|     partnum = SpiReadStatus(CC1101_PARTNUM); |  | ||||||
|     version = SpiReadStatus(CC1101_VERSION); |  | ||||||
| 
 |  | ||||||
| #ifdef CC1101_DEBUG |  | ||||||
| 
 |  | ||||||
|     printf("Partnum:0x%02X, Version:0x%02X\n", partnum, version); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifdef CC1101_DEBUG |  | ||||||
|     printf("Init CC1101..."); |  | ||||||
| #endif |  | ||||||
|     // RegConfigSettings(); //CC1101 register config
 |  | ||||||
| 
 |  | ||||||
| #ifdef CC1101_DEBUG |  | ||||||
|     printf("Done!\r\n"); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|     return version; |  | ||||||
| } |  | ||||||
| /****************************************************************
 |  | ||||||
| *FUNCTION NAME:SetMod |  | ||||||
| *FUNCTION     :CC1101 modulation type |  | ||||||
| *INPUT        :byte mode |  | ||||||
| *OUTPUT       :none |  | ||||||
| ****************************************************************/ |  | ||||||
| void CC1101::SetMod(uint8_t mode) { |  | ||||||
|     SpiWriteReg(CC1101_MDMCFG2, mode); //no sync/preamble; ASK/OOK only support up to -1dbm
 |  | ||||||
|     if((mode | 0x30) == ASK) { |  | ||||||
|         SpiWriteReg(CC1101_FREND0, 0x11); //use first up to PATABLE(0)
 |  | ||||||
|         uint8_t PaTabel[8] = {0x00, POWER, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |  | ||||||
|         SpiWriteBurstReg(CC1101_PATABLE, PaTabel, 8); //CC1101 PATABLE config
 |  | ||||||
|     } else { |  | ||||||
|         SpiWriteReg(CC1101_FREND0, 0x10); //use first up to PATABLE(0)
 |  | ||||||
|         uint8_t PaTabel[8] = {POWER, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |  | ||||||
|         SpiWriteBurstReg(CC1101_PATABLE, PaTabel, 8); //CC1101 PATABLE config
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| #ifdef CC1101_DEBUG |  | ||||||
|     switch(mode | 0x30) { |  | ||||||
|     case GFSK: { |  | ||||||
|         printf("CC1101 Modulation: GFSK"); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|     case MSK: { |  | ||||||
|         printf("CC1101 Modulation: MSK"); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|     case ASK: { |  | ||||||
|         printf("CC1101 Modulation: ASK/OOK"); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|     case FSK2: { |  | ||||||
|         printf("CC1101 Modulation: 2-FSK"); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|     case FSK4: { |  | ||||||
|         printf("CC1101 Modulation: 4-FSK"); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|     default: //default to GFSK
 |  | ||||||
|     { |  | ||||||
|         printf("Modulation mode not supported"); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     printf("\r\n"); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
| /****************************************************************
 |  | ||||||
| *FUNCTION NAME:RegConfigSettings |  | ||||||
| *FUNCTION     :CC1101 register config //details refer datasheet of CC1101/CC1100//
 |  | ||||||
| *INPUT        :none |  | ||||||
| *OUTPUT       :none |  | ||||||
| ****************************************************************/ |  | ||||||
| void CC1101::RegConfigSettings(void) { |  | ||||||
|     SpiWriteReg(CC1101_FSCTRL1, 0x06); //IF frequency
 |  | ||||||
|     SpiWriteReg(CC1101_FSCTRL0, 0x00); //frequency offset before synthesizer
 |  | ||||||
| 
 |  | ||||||
|     SpiWriteReg(CC1101_MDMCFG4, 0xCC); // RX filter bandwidth 100k(0xcc)
 |  | ||||||
|     SpiWriteReg( |  | ||||||
|         CC1101_MDMCFG3, 0x43); //datarate config 512kBaud  for the purpose of fast rssi measurement
 |  | ||||||
|     SpiWriteReg(CC1101_MDMCFG1, 0x21); //FEC preamble etc. last 2 bits for channel spacing
 |  | ||||||
|     SpiWriteReg(CC1101_MDMCFG0, 0xF8); //100khz channel spacing
 |  | ||||||
|     //CC1101_CHANNR moved to SetChannel func
 |  | ||||||
| 
 |  | ||||||
|     //SpiWriteReg(CC1101_DEVIATN,  0x47);
 |  | ||||||
|     SpiWriteReg( |  | ||||||
|         CC1101_MCSM0, 0x18); // calibrate when going from IDLE to RX or TX ; 149 - 155 μs timeout
 |  | ||||||
|     SpiWriteReg(CC1101_FOCCFG, 0x16); //frequency compensation
 |  | ||||||
|     //SpiWriteReg(CC1101_BSCFG,    0x1C);   //bit synchronization config
 |  | ||||||
|     SpiWriteReg(CC1101_AGCCTRL2, 0x43); |  | ||||||
|     SpiWriteReg(CC1101_AGCCTRL1, 0x49); |  | ||||||
|     SpiWriteReg(CC1101_AGCCTRL0, 0x91); |  | ||||||
|     //freq synthesizer calibration
 |  | ||||||
|     SpiWriteReg(CC1101_FSCAL3, 0xEA); |  | ||||||
|     SpiWriteReg(CC1101_FSCAL2, 0x2A); |  | ||||||
|     SpiWriteReg(CC1101_FSCAL1, 0x00); |  | ||||||
|     SpiWriteReg(CC1101_FSCAL0, 0x1F); |  | ||||||
|     SpiWriteReg(CC1101_TEST2, 0x81); |  | ||||||
|     SpiWriteReg(CC1101_TEST1, 0x35); |  | ||||||
|     SpiWriteReg(CC1101_TEST0, 0x0B); //should be 0x0B for lower than 430.6MHz and 0x09 for higher
 |  | ||||||
| 
 |  | ||||||
|     //SpiWriteReg(CC1101_FREND1,   0x56);
 |  | ||||||
| 
 |  | ||||||
|     //SpiWriteReg(CC1101_IOCFG2,   0x0B);   //serial clock.synchronous to the data in synchronous serial mode
 |  | ||||||
|     //SpiWriteReg(CC1101_IOCFG0,   0x06);   //asserts when sync word has been sent/received, and de-asserts at the end of the packet
 |  | ||||||
|     SpiWriteReg(CC1101_IOCFG2, 0x0D); //data output pin for asynchronous mode
 |  | ||||||
|     SpiWriteReg( |  | ||||||
|         CC1101_IOCFG0, |  | ||||||
|         0x2E); //High impedance (3-state), GDO0 configed as data input for asynchronous mode
 |  | ||||||
|     //SpiWriteReg(CC1101_PKTCTRL0, 0x05);       //whitening off;CRC Enable;variable length packets, packet length configured by the first byte after sync word
 |  | ||||||
|     SpiWriteReg( |  | ||||||
|         CC1101_PKTCTRL0, 0x33); //whitening off; asynchronous serial mode; CRC diable;reserved
 |  | ||||||
|     //SpiWriteReg(CC1101_PKTLEN,   0x3D);   //61 bytes max length
 |  | ||||||
|     SpiWriteReg( |  | ||||||
|         CC1101_FIFOTHR, |  | ||||||
|         0x47); //Adc_retention enabled for RX filter bandwidth less than 325KHz; defalut fifo threthold.
 |  | ||||||
| } |  | ||||||
| /****************************************************************
 |  | ||||||
|  *FUNCTION NAME:SetFreq |  | ||||||
|  *FUNCTION     :SetFreq |  | ||||||
|  *INPUT        :Freq2, Freq1, Freq0 |  | ||||||
|  *OUTPUT       :none |  | ||||||
|  ****************************************************************/ |  | ||||||
| void CC1101::SetFreq(uint8_t freq2, uint8_t freq1, uint8_t freq0) { |  | ||||||
|     SpiWriteReg(CC1101_FREQ2, freq2); |  | ||||||
|     SpiWriteReg(CC1101_FREQ1, freq1); |  | ||||||
|     SpiWriteReg(CC1101_FREQ0, freq0); |  | ||||||
| } |  | ||||||
| /****************************************************************
 |  | ||||||
|  *FUNCTION NAME:SetChannel |  | ||||||
|  *FUNCTION     :SetChannel |  | ||||||
|  *INPUT        :int channel |  | ||||||
|  *OUTPUT       :none |  | ||||||
|  ****************************************************************/ |  | ||||||
| void CC1101::SetChannel(int channel) { |  | ||||||
| #ifdef CC1101_DEBUG |  | ||||||
|     printf("Set CC1101 channel to: %d \n", channel); |  | ||||||
| #endif |  | ||||||
|     SpiWriteReg(CC1101_CHANNR, (uint8_t)channel); //related to channel numbers
 |  | ||||||
| } |  | ||||||
| /****************************************************************
 |  | ||||||
|  *FUNCTION NAME:SetReceive |  | ||||||
|  *FUNCTION     :SetReceive |  | ||||||
|  *INPUT        :none |  | ||||||
|  *OUTPUT       :none |  | ||||||
|  ****************************************************************/ |  | ||||||
| void CC1101::SetReceive(void) { |  | ||||||
|     SpiStrobe(CC1101_SRX); |  | ||||||
|     while(SpiReadStatus(CC1101_MARCSTATE) ^ CC1101_STATUS_RX) { |  | ||||||
|         // delay(1);
 |  | ||||||
|         // printf("wait status\r\n");
 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| /****************************************************************
 |  | ||||||
|  *FUNCTION NAME:SetTransmit |  | ||||||
|  *FUNCTION     : |  | ||||||
|  *INPUT        :none |  | ||||||
|  *OUTPUT       :none |  | ||||||
|  ****************************************************************/ |  | ||||||
| void CC1101::SetTransmit(void) { |  | ||||||
|     SpiStrobe(CC1101_STX); |  | ||||||
|     while(SpiReadStatus(CC1101_MARCSTATE) ^ CC1101_STATUS_TX) |  | ||||||
|         ; |  | ||||||
| } |  | ||||||
| //cc1101 cc1101;
 |  | ||||||
| 
 |  | ||||||
| bool CC1101::setRxBandwidth(float bandwidth) { |  | ||||||
|     if(bandwidth < 58.0 || bandwidth > 821.0) return false; |  | ||||||
| 
 |  | ||||||
|     // set mode to standby
 |  | ||||||
|     SpiStrobe(CC1101_SIDLE); |  | ||||||
| 
 |  | ||||||
|     // calculate exponent and mantissa values
 |  | ||||||
|     for(int8_t e = 3; e >= 0; e--) { |  | ||||||
|         for(int8_t m = 3; m >= 0; m--) { |  | ||||||
|             float point = (F_OSC) / (8 * (m + 4) * ((uint32_t)1 << e)); |  | ||||||
|             if(fabs((bandwidth * 1000.0) - point) <= 1000) { |  | ||||||
|                 // set Rx channel filter bandwidth
 |  | ||||||
|                 SpiSetRegValue(CC1101_MDMCFG4, (e << 6) | (m << 4), 7, 4); |  | ||||||
| 
 |  | ||||||
|                 return true; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void getExpMant( |  | ||||||
|     float target, |  | ||||||
|     uint16_t mantOffset, |  | ||||||
|     uint8_t divExp, |  | ||||||
|     uint8_t expMax, |  | ||||||
|     uint8_t& exp, |  | ||||||
|     uint8_t& mant) { |  | ||||||
|     // get table origin point (exp = 0, mant = 0)
 |  | ||||||
|     float origin = (mantOffset * F_OSC) / ((uint32_t)1 << divExp); |  | ||||||
| 
 |  | ||||||
|     // iterate over possible exponent values
 |  | ||||||
|     for(int8_t e = expMax; e >= 0; e--) { |  | ||||||
|         // get table column start value (exp = e, mant = 0);
 |  | ||||||
|         float intervalStart = ((uint32_t)1 << e) * origin; |  | ||||||
| 
 |  | ||||||
|         // check if target value is in this column
 |  | ||||||
|         if(target >= intervalStart) { |  | ||||||
|             // save exponent value
 |  | ||||||
|             exp = e; |  | ||||||
| 
 |  | ||||||
|             // calculate size of step between table rows
 |  | ||||||
|             float stepSize = intervalStart / (float)mantOffset; |  | ||||||
| 
 |  | ||||||
|             // get target point position (exp = e, mant = m)
 |  | ||||||
|             mant = ((target - intervalStart) / stepSize); |  | ||||||
| 
 |  | ||||||
|             // we only need the first match, terminate
 |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool CC1101::setBitRate(float bitrate) { |  | ||||||
|     if(bitrate < 0.6 || bitrate > 500.0) return false; |  | ||||||
| 
 |  | ||||||
|     // set mode to standby
 |  | ||||||
|     SpiStrobe(CC1101_SIDLE); |  | ||||||
| 
 |  | ||||||
|     // calculate exponent and mantissa values
 |  | ||||||
|     uint8_t e = 0; |  | ||||||
|     uint8_t m = 0; |  | ||||||
|     getExpMant(bitrate * 1000.0, 256, 28, 14, e, m); |  | ||||||
| 
 |  | ||||||
|     // set bit rate value
 |  | ||||||
|     SpiSetRegValue(CC1101_MDMCFG4, e, 3, 0); |  | ||||||
|     SpiSetRegValue(CC1101_MDMCFG3, m, 7, 0); |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| @ -1,174 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| #define F_OSC 26e6 |  | ||||||
| 
 |  | ||||||
| /*******************************debug mode*************************************/ |  | ||||||
| // #define     CC1101_DEBUG 1
 |  | ||||||
| 
 |  | ||||||
| //******************************CC1101 defines ********************************
 |  | ||||||
| //******************************config registers  *****************************
 |  | ||||||
| #define CC1101_IOCFG2 0x00 //GDO2 output pin configration
 |  | ||||||
| #define CC1101_IOCFG1 0x01 // GDO1 output pin configuration
 |  | ||||||
| #define CC1101_IOCFG0 0x02 // GDO0 output pin configuration
 |  | ||||||
| #define CC1101_FIFOTHR 0x03 // RX FIFO and TX FIFO thresholds
 |  | ||||||
| #define CC1101_SYNC1 0x04 // Sync word, high INT8U
 |  | ||||||
| #define CC1101_SYNC0 0x05 // Sync word, low INT8U
 |  | ||||||
| #define CC1101_PKTLEN 0x06 // Packet length
 |  | ||||||
| #define CC1101_PKTCTRL1 0x07 // Packet automation control
 |  | ||||||
| #define CC1101_PKTCTRL0 0x08 // Packet automation control
 |  | ||||||
| #define CC1101_ADDR 0x09 // Device address
 |  | ||||||
| #define CC1101_CHANNR 0x0A // Channel number
 |  | ||||||
| #define CC1101_FSCTRL1 0x0B // Frequency synthesizer control
 |  | ||||||
| #define CC1101_FSCTRL0 0x0C // Frequency synthesizer control
 |  | ||||||
| #define CC1101_FREQ2 0x0D // Frequency control word, high INT8U
 |  | ||||||
| #define CC1101_FREQ1 0x0E // Frequency control word, middle INT8U
 |  | ||||||
| #define CC1101_FREQ0 0x0F // Frequency control word, low INT8U
 |  | ||||||
| #define CC1101_MDMCFG4 0x10 // Modem configuration
 |  | ||||||
| #define CC1101_MDMCFG3 0x11 // Modem configuration
 |  | ||||||
| #define CC1101_MDMCFG2 0x12 // Modem configuration
 |  | ||||||
| #define CC1101_MDMCFG1 0x13 // Modem configuration
 |  | ||||||
| #define CC1101_MDMCFG0 0x14 // Modem configuration
 |  | ||||||
| #define CC1101_DEVIATN 0x15 // Modem deviation setting
 |  | ||||||
| #define CC1101_MCSM2 0x16 // Main Radio Control State Machine configuration
 |  | ||||||
| #define CC1101_MCSM1 0x17 // Main Radio Control State Machine configuration
 |  | ||||||
| #define CC1101_MCSM0 0x18 // Main Radio Control State Machine configuration
 |  | ||||||
| #define CC1101_FOCCFG 0x19 // Frequency Offset Compensation configuration
 |  | ||||||
| #define CC1101_BSCFG 0x1A // Bit Synchronization configuration
 |  | ||||||
| #define CC1101_AGCCTRL2 0x1B // AGC control
 |  | ||||||
| #define CC1101_AGCCTRL1 0x1C // AGC control
 |  | ||||||
| #define CC1101_AGCCTRL0 0x1D // AGC control
 |  | ||||||
| #define CC1101_WOREVT1 0x1E // High INT8U Event 0 timeout
 |  | ||||||
| #define CC1101_WOREVT0 0x1F // Low INT8U Event 0 timeout
 |  | ||||||
| #define CC1101_WORCTRL 0x20 // Wake On Radio control
 |  | ||||||
| #define CC1101_FREND1 0x21 // Front end RX configuration
 |  | ||||||
| #define CC1101_FREND0 0x22 // Front end TX configuration
 |  | ||||||
| #define CC1101_FSCAL3 0x23 // Frequency synthesizer calibration
 |  | ||||||
| #define CC1101_FSCAL2 0x24 // Frequency synthesizer calibration
 |  | ||||||
| #define CC1101_FSCAL1 0x25 // Frequency synthesizer calibration
 |  | ||||||
| #define CC1101_FSCAL0 0x26 // Frequency synthesizer calibration
 |  | ||||||
| #define CC1101_RCCTRL1 0x27 // RC oscillator configuration
 |  | ||||||
| #define CC1101_RCCTRL0 0x28 // RC oscillator configuration
 |  | ||||||
| #define CC1101_FSTEST 0x29 // Frequency synthesizer calibration control
 |  | ||||||
| #define CC1101_PTEST 0x2A // Production test
 |  | ||||||
| #define CC1101_AGCTEST 0x2B // AGC test
 |  | ||||||
| #define CC1101_TEST2 0x2C // Various test settings
 |  | ||||||
| #define CC1101_TEST1 0x2D // Various test settings
 |  | ||||||
| #define CC1101_TEST0 0x2E // Various test settings
 |  | ||||||
| 
 |  | ||||||
| //*********************CC1101 Strobe commands  *********************************
 |  | ||||||
| #define CC1101_SRES 0x30 // Reset chip.
 |  | ||||||
| 
 |  | ||||||
| // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
 |  | ||||||
| // If in RX/TX: Go to a wait state where only the synthesizer is
 |  | ||||||
| // running (for quick RX / TX turnaround).
 |  | ||||||
| #define CC1101_SFSTXON 0x31 |  | ||||||
| 
 |  | ||||||
| #define CC1101_SXOFF 0x32 // Turn off crystal oscillator.
 |  | ||||||
| 
 |  | ||||||
| // Calibrate frequency synthesizer and turn it off
 |  | ||||||
| // (enables quick start).
 |  | ||||||
| #define CC1101_SCAL 0x33 |  | ||||||
| 
 |  | ||||||
| // Enable RX. Perform calibration first if coming from IDLE and
 |  | ||||||
| // MCSM0.FS_AUTOCAL=1.
 |  | ||||||
| #define CC1101_SRX 0x34 |  | ||||||
| 
 |  | ||||||
| // In IDLE state: Enable TX. Perform calibration first if
 |  | ||||||
| // MCSM0.FS_AUTOCAL=1. If in RX state and CCA is enabled:
 |  | ||||||
| // Only go to TX if channel is clear.
 |  | ||||||
| #define CC1101_STX 0x35 |  | ||||||
| 
 |  | ||||||
| // Exit RX / TX, turn off frequency synthesizer and exit
 |  | ||||||
| // Wake-On-Radio mode if applicable.
 |  | ||||||
| #define CC1101_SIDLE 0x36 |  | ||||||
| 
 |  | ||||||
| #define CC1101_SAFC 0x37 // Perform AFC adjustment of the frequency synthesizer
 |  | ||||||
| #define CC1101_SWOR 0x38 // Start automatic RX polling sequence (Wake-on-Radio)
 |  | ||||||
| #define CC1101_SPWD 0x39 // Enter power down mode when CSn goes high.
 |  | ||||||
| #define CC1101_SFRX 0x3A // Flush the RX FIFO buffer.
 |  | ||||||
| #define CC1101_SFTX 0x3B // Flush the TX FIFO buffer.
 |  | ||||||
| #define CC1101_SWORRST 0x3C // Reset real time clock.
 |  | ||||||
| 
 |  | ||||||
| // No operation. May be used to pad strobe commands to two
 |  | ||||||
| // INT8Us for simpler software.
 |  | ||||||
| #define CC1101_SNOP 0x3D |  | ||||||
| 
 |  | ||||||
| //**************************CC1101 STATUS REGSITER ****************************
 |  | ||||||
| //use burst read to access
 |  | ||||||
| #define CC1101_PARTNUM 0x30 |  | ||||||
| #define CC1101_VERSION 0x31 |  | ||||||
| #define CC1101_FREQEST 0x32 |  | ||||||
| #define CC1101_LQI 0x33 |  | ||||||
| #define CC1101_RSSI 0x34 |  | ||||||
| #define CC1101_MARCSTATE 0x35 |  | ||||||
| #define CC1101_WORTIME1 0x36 |  | ||||||
| #define CC1101_WORTIME0 0x37 |  | ||||||
| #define CC1101_PKTSTATUS 0x38 |  | ||||||
| #define CC1101_VCO_VC_DAC 0x39 |  | ||||||
| #define CC1101_TXBYTES 0x3A |  | ||||||
| #define CC1101_RXBYTES 0x3B |  | ||||||
| #define CC1101_RCCTRL1_STATUS 0x3C |  | ||||||
| #define CC1101_RCCTRL_STATUS 0x3D |  | ||||||
| /****************************cc1101 status ***********************************/ |  | ||||||
| #define CC1101_STATUS_RX 0x0D |  | ||||||
| #define CC1101_STATUS_TX 0x13 |  | ||||||
| 
 |  | ||||||
| //***********************CC1101 PATABLE,TXFIFO,RXFIFO**************************
 |  | ||||||
| #define CC1101_PATABLE 0x3E |  | ||||||
| #define CC1101_TXFIFO 0x3F |  | ||||||
| #define CC1101_RXFIFO 0x3F |  | ||||||
| 
 |  | ||||||
| //******************************* pins ****************************************
 |  | ||||||
| // #define SCK_PIN   13
 |  | ||||||
| // #define MISO_PIN  12
 |  | ||||||
| // #define MOSI_PIN  11
 |  | ||||||
| // #define SS_PIN    10
 |  | ||||||
| // #define GDO0	8	//pin assignment
 |  | ||||||
| // #define GDO2	9
 |  | ||||||
| //*****************************CC1101 Config**********************************
 |  | ||||||
| //no  pa ramping, output power to 10dBm
 |  | ||||||
| #define POWER 0xC0 //output power to maximum
 |  | ||||||
| //modulation
 |  | ||||||
| #define FSK2 0x00 |  | ||||||
| #define GFSK 0x10 |  | ||||||
| #define ASK 0x30 |  | ||||||
| #define FSK4 0x40 |  | ||||||
| #define MSK 0x70 |  | ||||||
| //******************************** class **************************************//
 |  | ||||||
| class CC1101 { |  | ||||||
| private: |  | ||||||
|     GpioPin* ss_pin; |  | ||||||
|     GpioPin miso_pin; |  | ||||||
|     GpioPin* miso_pin_record; |  | ||||||
|     GpioPin* gdo0_pin; |  | ||||||
|     GpioPin* gdo2_pin; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     void SpiMode(uint8_t config); |  | ||||||
|     uint8_t SpiTransfer(uint8_t value); |  | ||||||
|     void Reset(void); |  | ||||||
|     void SpiWriteBurstReg(uint8_t addr, uint8_t* buffer, uint8_t num); |  | ||||||
|     uint8_t SpiReadReg(uint8_t addr); |  | ||||||
|     void RegConfigSettings(void); |  | ||||||
| 
 |  | ||||||
| public: |  | ||||||
|     CC1101(GpioPin* ss_pin); |  | ||||||
| 
 |  | ||||||
|     void SpiWriteReg(uint8_t addr, uint8_t value); |  | ||||||
|     bool SpiSetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb); |  | ||||||
|     void SpiReadBurstReg(uint8_t addr, uint8_t* buffer, uint8_t num); |  | ||||||
|     void SpiInit(void); |  | ||||||
|     void SpiEnd(void); |  | ||||||
|     void SetMod(uint8_t mode); |  | ||||||
|     void SetFreq(uint8_t Freq2, uint8_t Freq1, uint8_t Freq0); |  | ||||||
|     uint8_t Init(void); |  | ||||||
|     void SpiStrobe(uint8_t strobe); |  | ||||||
|     uint8_t SpiReadStatus(uint8_t addr); |  | ||||||
|     void SetReceive(void); |  | ||||||
|     void SetTransmit(void); |  | ||||||
|     void SetChannel(int channel); |  | ||||||
|     bool setRxBandwidth(float bandwidth); |  | ||||||
|     bool setBitRate(float bitrate); |  | ||||||
| }; |  | ||||||
| @ -34,6 +34,7 @@ void canvas_free(Canvas* canvas) { | |||||||
| 
 | 
 | ||||||
| void canvas_reset(Canvas* canvas) { | void canvas_reset(Canvas* canvas) { | ||||||
|     furi_assert(canvas); |     furi_assert(canvas); | ||||||
|  |     canvas_clear(canvas); | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,122 +1,66 @@ | |||||||
| #include "u8g2/u8g2.h" | #include "u8g2/u8g2.h" | ||||||
| #include <furi.h> |  | ||||||
| #include <api-hal.h> | #include <api-hal.h> | ||||||
|  | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #include <main.h> | static ApiHalSpiDevice* u8g2_periphery_display = NULL; | ||||||
| 
 |  | ||||||
| extern SPI_HandleTypeDef SPI_D; |  | ||||||
| 
 |  | ||||||
| // TODO: fix log
 |  | ||||||
| #ifdef DEBUG |  | ||||||
| #undef DEBUG |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { | uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { | ||||||
|     switch(msg) { |     switch(msg) { | ||||||
|     //Initialize SPI peripheral
 |  | ||||||
|     case U8X8_MSG_GPIO_AND_DELAY_INIT: |     case U8X8_MSG_GPIO_AND_DELAY_INIT: | ||||||
|         /* HAL initialization contains all what we need so we can skip this part. */ |         /* HAL initialization contains all what we need so we can skip this part. */ | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     //Function which implements a delay, arg_int contains the amount of ms
 |  | ||||||
|     case U8X8_MSG_DELAY_MILLI: |     case U8X8_MSG_DELAY_MILLI: | ||||||
|         osDelay(arg_int); |         osDelay(arg_int); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     //Function which delays 10us
 |  | ||||||
|     case U8X8_MSG_DELAY_10MICRO: |     case U8X8_MSG_DELAY_10MICRO: | ||||||
|         delay_us(10); |         delay_us(10); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     //Function which delays 100ns
 |  | ||||||
|     case U8X8_MSG_DELAY_100NANO: |     case U8X8_MSG_DELAY_100NANO: | ||||||
|         asm("nop"); |         asm("nop"); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     // Function to define the logic level of the RESET line
 |  | ||||||
|     case U8X8_MSG_GPIO_RESET: |     case U8X8_MSG_GPIO_RESET: | ||||||
| #ifdef DEBUG |         hal_gpio_write(&gpio_display_rst, arg_int); | ||||||
|         printf("[u8g2] rst %d\n", arg_int); |         break; | ||||||
| #endif | 
 | ||||||
| 
 |     default: | ||||||
|         // TODO change it to FuriRecord pin
 |         return 0; | ||||||
|         HAL_GPIO_WritePin( |     } | ||||||
|             DISPLAY_RST_GPIO_Port, DISPLAY_RST_Pin, arg_int ? GPIO_PIN_SET : GPIO_PIN_RESET); | 
 | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { | ||||||
|  |     switch(msg) { | ||||||
|  |     case U8X8_MSG_BYTE_SEND: | ||||||
|  |         api_hal_spi_bus_tx(u8g2_periphery_display->bus, (uint8_t*)arg_ptr, arg_int, 10000); | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case U8X8_MSG_BYTE_SET_DC: | ||||||
|  |         hal_gpio_write(&gpio_display_di, arg_int); | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case U8X8_MSG_BYTE_INIT: | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case U8X8_MSG_BYTE_START_TRANSFER: | ||||||
|  |         furi_assert(u8g2_periphery_display == NULL); | ||||||
|  |         u8g2_periphery_display = | ||||||
|  |             (ApiHalSpiDevice*)api_hal_spi_device_get(ApiHalSpiDeviceIdDisplay); | ||||||
|  |         hal_gpio_write(u8g2_periphery_display->chip_select, false); | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case U8X8_MSG_BYTE_END_TRANSFER: | ||||||
|  |         furi_assert(u8g2_periphery_display); | ||||||
|  |         hal_gpio_write(u8g2_periphery_display->chip_select, true); | ||||||
|  |         api_hal_spi_device_return(u8g2_periphery_display); | ||||||
|  |         u8g2_periphery_display = NULL; | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     default: |     default: | ||||||
| #ifdef DEBUG |  | ||||||
|         printf("[u8g2] unknown io %d\n", msg); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|         return 0; //A message was received which is not implemented, return 0 to indicate an error
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return 1; // command processed successfully.
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { |  | ||||||
|     switch(msg) { |  | ||||||
|     case U8X8_MSG_BYTE_SEND: |  | ||||||
| #ifdef DEBUG |  | ||||||
|         printf("[u8g2] send %d bytes %02X\n", arg_int, ((uint8_t*)arg_ptr)[0]); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|         // TODO change it to FuriRecord SPI
 |  | ||||||
|         HAL_SPI_Transmit(&SPI_D, (uint8_t*)arg_ptr, arg_int, 10000); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     case U8X8_MSG_BYTE_SET_DC: |  | ||||||
| #ifdef DEBUG |  | ||||||
|         printf("[u8g2] dc %d\n", arg_int); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|         // TODO change it to FuriRecord pin
 |  | ||||||
|         HAL_GPIO_WritePin( |  | ||||||
|             DISPLAY_DI_GPIO_Port, DISPLAY_DI_Pin, arg_int ? GPIO_PIN_SET : GPIO_PIN_RESET); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     case U8X8_MSG_BYTE_INIT: |  | ||||||
| #ifdef DEBUG |  | ||||||
|         printf("[u8g2] init\r\n"); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|         // TODO change it to FuriRecord pin
 |  | ||||||
|         HAL_GPIO_WritePin(DISPLAY_CS_GPIO_Port, DISPLAY_CS_Pin, GPIO_PIN_RESET); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     case U8X8_MSG_BYTE_START_TRANSFER: |  | ||||||
| #ifdef DEBUG |  | ||||||
|         printf("[u8g2] start\r\n"); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|         // TODO: SPI manager
 |  | ||||||
|         api_hal_spi_lock_device(&display_spi); |  | ||||||
| 
 |  | ||||||
|         // TODO change it to FuriRecord pin
 |  | ||||||
|         HAL_GPIO_WritePin(DISPLAY_CS_GPIO_Port, DISPLAY_CS_Pin, GPIO_PIN_RESET); |  | ||||||
|         asm("nop"); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     case U8X8_MSG_BYTE_END_TRANSFER: |  | ||||||
| #ifdef DEBUG |  | ||||||
|         printf("[u8g2] end\r\n"); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|         asm("nop"); |  | ||||||
|         // TODO change it to FuriRecord pin
 |  | ||||||
|         HAL_GPIO_WritePin(DISPLAY_CS_GPIO_Port, DISPLAY_CS_Pin, GPIO_PIN_SET); |  | ||||||
| 
 |  | ||||||
|         // TODO: SPI manager
 |  | ||||||
|         api_hal_spi_unlock_device(&display_spi); |  | ||||||
| 
 |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     default: |  | ||||||
| #ifdef DEBUG |  | ||||||
|         printf("[u8g2] unknown xfer %d\n", msg); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -37,12 +37,12 @@ static void render_callback(Canvas* canvas, void* ctx) { | |||||||
| 
 | 
 | ||||||
|     canvas_draw_str(canvas, 2, 24, state->on ? "Reading" : "Emulating"); |     canvas_draw_str(canvas, 2, 24, state->on ? "Reading" : "Emulating"); | ||||||
| 
 | 
 | ||||||
|     char buf[14]; |     char buf[30]; | ||||||
| 
 | 
 | ||||||
|     sprintf(buf, "%d kHz", (int)state->freq_khz); |     snprintf(buf, sizeof(buf), "%d kHz", (int)state->freq_khz); | ||||||
|     canvas_draw_str(canvas, 2, 36, buf); |     canvas_draw_str(canvas, 2, 36, buf); | ||||||
| 
 | 
 | ||||||
|     sprintf(buf, "%02d:%010ld", state->customer_id, state->em_data); |     snprintf(buf, sizeof(buf), "%02d:%010ld", state->customer_id, state->em_data); | ||||||
|     canvas_draw_str(canvas, 2, 45, buf); |     canvas_draw_str(canvas, 2, 45, buf); | ||||||
| 
 | 
 | ||||||
|     release_mutex((ValueMutex*)ctx, state); |     release_mutex((ValueMutex*)ctx, state); | ||||||
|  | |||||||
| @ -244,7 +244,7 @@ ReturnCode nfc_worker_trx( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_worker_exchange(NfcWorker* nfc_worker, rfalNfcDevice* nfc_device) { | void nfc_worker_exchange(NfcWorker* nfc_worker, rfalNfcDevice* nfc_device) { | ||||||
|     ReturnCode err; |     ReturnCode err = ERR_NONE; | ||||||
|     uint8_t* rxData; |     uint8_t* rxData; | ||||||
|     uint16_t* rcvLen; |     uint16_t* rcvLen; | ||||||
|     uint8_t txBuf[100]; |     uint8_t txBuf[100]; | ||||||
|  | |||||||
| @ -849,4 +849,4 @@ int32_t sd_filesystem(void* p) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,13 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "../subghz-event.h" |  | ||||||
| 
 |  | ||||||
| class SubghzApp; |  | ||||||
| 
 |  | ||||||
| class SubghzScene { |  | ||||||
| public: |  | ||||||
|     virtual void on_enter(SubghzApp* app) = 0; |  | ||||||
|     virtual bool on_event(SubghzApp* app, SubghzEvent* event) = 0; |  | ||||||
|     virtual void on_exit(SubghzApp* app) = 0; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
| }; |  | ||||||
| @ -1,48 +0,0 @@ | |||||||
| #include "subghz-scene-spectrum-settings.h" |  | ||||||
| #include "../subghz-app.h" |  | ||||||
| #include "../subghz-view-manager.h" |  | ||||||
| #include "../subghz-event.h" |  | ||||||
| #include <callback-connector.h> |  | ||||||
| 
 |  | ||||||
| void SubghzSceneSpectrumSettings::on_enter(SubghzApp* app) { |  | ||||||
|     SubghzAppViewManager* view_manager = app->get_view_manager(); |  | ||||||
|     SubghzViewSpectrumSettings* spectrum_settings = view_manager->get_spectrum_settings(); |  | ||||||
| 
 |  | ||||||
|     auto callback = cbc::obtain_connector(this, &SubghzSceneSpectrumSettings::ok_callback); |  | ||||||
|     spectrum_settings->set_ok_callback(callback, app); |  | ||||||
|     spectrum_settings->set_start_freq(433); |  | ||||||
| 
 |  | ||||||
|     view_manager->switch_to(SubghzAppViewManager::ViewType::SpectrumSettings); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool SubghzSceneSpectrumSettings::on_event(SubghzApp* app, SubghzEvent* event) { |  | ||||||
|     bool consumed = false; |  | ||||||
| 
 |  | ||||||
|     if(event->type == SubghzEvent::Type::NextScene) { |  | ||||||
|         // save data
 |  | ||||||
|         // uint32_t start_freq = app->get_view_manager()->get_spectrum_settings()->get_start_freq();
 |  | ||||||
|         // app->get_spectrum_analyzer()->set_start_freq(start_freq);
 |  | ||||||
| 
 |  | ||||||
|         // switch to next scene
 |  | ||||||
|         // app->switch_to_next_scene(SubghzApp::Scene::SceneSpectrumAnalyze);
 |  | ||||||
|         consumed = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return consumed; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SubghzSceneSpectrumSettings::on_exit(SubghzApp* app) { |  | ||||||
|     SubghzAppViewManager* view_manager = app->get_view_manager(); |  | ||||||
|     SubghzViewSpectrumSettings* spectrum_settings = view_manager->get_spectrum_settings(); |  | ||||||
| 
 |  | ||||||
|     spectrum_settings->set_ok_callback(nullptr, nullptr); |  | ||||||
|     spectrum_settings->set_start_freq(0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SubghzSceneSpectrumSettings::ok_callback(void* context) { |  | ||||||
|     SubghzApp* app = static_cast<SubghzApp*>(context); |  | ||||||
|     SubghzEvent event; |  | ||||||
| 
 |  | ||||||
|     event.type = SubghzEvent::Type::NextScene; |  | ||||||
|     app->get_view_manager()->send_event(&event); |  | ||||||
| } |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "subghz-scene-generic.h" |  | ||||||
| 
 |  | ||||||
| class SubghzSceneSpectrumSettings : public SubghzScene { |  | ||||||
| public: |  | ||||||
|     void on_enter(SubghzApp* app) final; |  | ||||||
|     bool on_event(SubghzApp* app, SubghzEvent* event) final; |  | ||||||
|     void on_exit(SubghzApp* app) final; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     void ok_callback(void* context); |  | ||||||
| }; |  | ||||||
| @ -1,67 +0,0 @@ | |||||||
| #include "subghz-scene-start.h" |  | ||||||
| #include "../subghz-app.h" |  | ||||||
| #include "../subghz-view-manager.h" |  | ||||||
| #include "../subghz-event.h" |  | ||||||
| #include <callback-connector.h> |  | ||||||
| 
 |  | ||||||
| typedef enum { |  | ||||||
|     SubmenuIndexSpectrumAnalyzer, |  | ||||||
|     SubmenuIndexFrequencyScanner, |  | ||||||
|     SubmenuIndexSignalAnalyzer, |  | ||||||
|     SubmenuIndexSignalTransmitter, |  | ||||||
|     SubmenuIndexApplications, |  | ||||||
| } SubmenuIndex; |  | ||||||
| 
 |  | ||||||
| void SubghzSceneStart::on_enter(SubghzApp* app) { |  | ||||||
|     SubghzAppViewManager* view_manager = app->get_view_manager(); |  | ||||||
|     Submenu* submenu = view_manager->get_submenu(); |  | ||||||
|     auto callback = cbc::obtain_connector(this, &SubghzSceneStart::submenu_callback); |  | ||||||
| 
 |  | ||||||
|     submenu_add_item(submenu, "Spectrum Analyzer", SubmenuIndexSpectrumAnalyzer, callback, app); |  | ||||||
|     submenu_add_item(submenu, "Frequency Scanner", SubmenuIndexFrequencyScanner, callback, app); |  | ||||||
|     submenu_add_item(submenu, "Signal Analyzer", SubmenuIndexSignalAnalyzer, callback, app); |  | ||||||
|     submenu_add_item(submenu, "Signal Transmitter", SubmenuIndexSignalTransmitter, callback, app); |  | ||||||
|     submenu_add_item(submenu, "Applications", SubmenuIndexApplications, callback, app); |  | ||||||
| 
 |  | ||||||
|     view_manager->switch_to(SubghzAppViewManager::ViewType::Submenu); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool SubghzSceneStart::on_event(SubghzApp* app, SubghzEvent* event) { |  | ||||||
|     bool consumed = false; |  | ||||||
| 
 |  | ||||||
|     if(event->type == SubghzEvent::Type::MenuSelected) { |  | ||||||
|         switch(event->payload.menu_index) { |  | ||||||
|         case SubmenuIndexSpectrumAnalyzer: |  | ||||||
|             app->switch_to_next_scene(SubghzApp::Scene::SceneSpectrumSettings); |  | ||||||
|             break; |  | ||||||
|         case SubmenuIndexFrequencyScanner: |  | ||||||
|             break; |  | ||||||
|         case SubmenuIndexSignalAnalyzer: |  | ||||||
|             break; |  | ||||||
|         case SubmenuIndexSignalTransmitter: |  | ||||||
|             break; |  | ||||||
|         case SubmenuIndexApplications: |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         consumed = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return consumed; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SubghzSceneStart::on_exit(SubghzApp* app) { |  | ||||||
|     SubghzAppViewManager* view_manager = app->get_view_manager(); |  | ||||||
|     Submenu* submenu = view_manager->get_submenu(); |  | ||||||
| 
 |  | ||||||
|     submenu_clean(submenu); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SubghzSceneStart::submenu_callback(void* context, uint32_t index) { |  | ||||||
|     SubghzApp* app = static_cast<SubghzApp*>(context); |  | ||||||
|     SubghzEvent event; |  | ||||||
| 
 |  | ||||||
|     event.type = SubghzEvent::Type::MenuSelected; |  | ||||||
|     event.payload.menu_index = index; |  | ||||||
| 
 |  | ||||||
|     app->get_view_manager()->send_event(&event); |  | ||||||
| } |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "subghz-scene-generic.h" |  | ||||||
| 
 |  | ||||||
| class SubghzSceneStart : public SubghzScene { |  | ||||||
| public: |  | ||||||
|     void on_enter(SubghzApp* app) final; |  | ||||||
|     bool on_event(SubghzApp* app, SubghzEvent* event) final; |  | ||||||
|     void on_exit(SubghzApp* app) final; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     void submenu_callback(void* context, uint32_t index); |  | ||||||
| }; |  | ||||||
| @ -1,90 +0,0 @@ | |||||||
| #include "subghz-app.h" |  | ||||||
| #include <api-hal-power.h> |  | ||||||
| #include <stdarg.h> |  | ||||||
| 
 |  | ||||||
| void SubghzApp::run(void) { |  | ||||||
|     SubghzEvent event; |  | ||||||
|     bool consumed; |  | ||||||
|     bool exit = false; |  | ||||||
| 
 |  | ||||||
|     scenes[current_scene]->on_enter(this); |  | ||||||
| 
 |  | ||||||
|     while(!exit) { |  | ||||||
|         view.receive_event(&event); |  | ||||||
| 
 |  | ||||||
|         consumed = scenes[current_scene]->on_event(this, &event); |  | ||||||
| 
 |  | ||||||
|         if(!consumed) { |  | ||||||
|             if(event.type == SubghzEvent::Type::Back) { |  | ||||||
|                 exit = switch_to_previous_scene(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     scenes[current_scene]->on_exit(this); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| SubghzApp::SubghzApp() { |  | ||||||
|     api_hal_power_insomnia_enter(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| SubghzApp::~SubghzApp() { |  | ||||||
|     api_hal_power_insomnia_exit(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| SubghzAppViewManager* SubghzApp::get_view_manager() { |  | ||||||
|     return &view; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SubghzApp::switch_to_next_scene(Scene next_scene) { |  | ||||||
|     previous_scenes_list.push_front(current_scene); |  | ||||||
| 
 |  | ||||||
|     if(next_scene != Scene::SceneExit) { |  | ||||||
|         scenes[current_scene]->on_exit(this); |  | ||||||
|         current_scene = next_scene; |  | ||||||
|         scenes[current_scene]->on_enter(this); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SubghzApp::search_and_switch_to_previous_scene(std::initializer_list<Scene> scenes_list) { |  | ||||||
|     Scene previous_scene = Scene::SceneStart; |  | ||||||
|     bool scene_found = false; |  | ||||||
| 
 |  | ||||||
|     while(!scene_found) { |  | ||||||
|         previous_scene = get_previous_scene(); |  | ||||||
|         for(Scene element : scenes_list) { |  | ||||||
|             if(previous_scene == element || previous_scene == Scene::SceneStart) { |  | ||||||
|                 scene_found = true; |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     scenes[current_scene]->on_exit(this); |  | ||||||
|     current_scene = previous_scene; |  | ||||||
|     scenes[current_scene]->on_enter(this); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool SubghzApp::switch_to_previous_scene(uint8_t count) { |  | ||||||
|     Scene previous_scene = Scene::SceneStart; |  | ||||||
| 
 |  | ||||||
|     for(uint8_t i = 0; i < count; i++) { |  | ||||||
|         previous_scene = get_previous_scene(); |  | ||||||
|         if(previous_scene == Scene::SceneExit) break; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(previous_scene == Scene::SceneExit) { |  | ||||||
|         return true; |  | ||||||
|     } else { |  | ||||||
|         scenes[current_scene]->on_exit(this); |  | ||||||
|         current_scene = previous_scene; |  | ||||||
|         scenes[current_scene]->on_enter(this); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| SubghzApp::Scene SubghzApp::get_previous_scene() { |  | ||||||
|     Scene scene = previous_scenes_list.front(); |  | ||||||
|     previous_scenes_list.pop_front(); |  | ||||||
|     return scene; |  | ||||||
| } |  | ||||||
| @ -1,37 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <map> |  | ||||||
| #include <list> |  | ||||||
| #include "subghz-view-manager.h" |  | ||||||
| 
 |  | ||||||
| #include "scene/subghz-scene-start.h" |  | ||||||
| #include "scene/subghz-scene-spectrum-settings.h" |  | ||||||
| 
 |  | ||||||
| class SubghzApp { |  | ||||||
| public: |  | ||||||
|     void run(void); |  | ||||||
| 
 |  | ||||||
|     SubghzApp(); |  | ||||||
|     ~SubghzApp(); |  | ||||||
| 
 |  | ||||||
|     enum class Scene : uint8_t { |  | ||||||
|         SceneExit, |  | ||||||
|         SceneStart, |  | ||||||
|         SceneSpectrumSettings, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     SubghzAppViewManager* get_view_manager(); |  | ||||||
|     void switch_to_next_scene(Scene index); |  | ||||||
|     void search_and_switch_to_previous_scene(std::initializer_list<Scene> scenes_list); |  | ||||||
|     bool switch_to_previous_scene(uint8_t count = 1); |  | ||||||
|     Scene get_previous_scene(); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     std::list<Scene> previous_scenes_list = {Scene::SceneExit}; |  | ||||||
|     Scene current_scene = Scene::SceneStart; |  | ||||||
|     SubghzAppViewManager view; |  | ||||||
| 
 |  | ||||||
|     std::map<Scene, SubghzScene*> scenes = { |  | ||||||
|         {Scene::SceneStart, new SubghzSceneStart()}, |  | ||||||
|         {Scene::SceneSpectrumSettings, new SubghzSceneSpectrumSettings()}, |  | ||||||
|     }; |  | ||||||
| }; |  | ||||||
| @ -1,21 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <stdint.h> |  | ||||||
| 
 |  | ||||||
| class SubghzEvent { |  | ||||||
| public: |  | ||||||
|     // events enum
 |  | ||||||
|     enum class Type : uint8_t { |  | ||||||
|         Tick, |  | ||||||
|         Back, |  | ||||||
|         MenuSelected, |  | ||||||
|         NextScene, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     // payload
 |  | ||||||
|     union { |  | ||||||
|         uint32_t menu_index; |  | ||||||
|     } payload; |  | ||||||
| 
 |  | ||||||
|     // event type
 |  | ||||||
|     Type type; |  | ||||||
| }; |  | ||||||
| @ -1,81 +0,0 @@ | |||||||
| #include "subghz-view-manager.h" |  | ||||||
| #include "subghz-event.h" |  | ||||||
| #include <callback-connector.h> |  | ||||||
| 
 |  | ||||||
| SubghzAppViewManager::SubghzAppViewManager() { |  | ||||||
|     event_queue = osMessageQueueNew(10, sizeof(SubghzEvent), NULL); |  | ||||||
| 
 |  | ||||||
|     view_dispatcher = view_dispatcher_alloc(); |  | ||||||
|     auto callback = cbc::obtain_connector(this, &SubghzAppViewManager::previous_view_callback); |  | ||||||
| 
 |  | ||||||
|     // allocate views
 |  | ||||||
|     submenu = submenu_alloc(); |  | ||||||
|     view_dispatcher_add_view( |  | ||||||
|         view_dispatcher, |  | ||||||
|         static_cast<uint32_t>(SubghzAppViewManager::ViewType::Submenu), |  | ||||||
|         submenu_get_view(submenu)); |  | ||||||
| 
 |  | ||||||
|     spectrum_settings = new SubghzViewSpectrumSettings(); |  | ||||||
|     view_dispatcher_add_view( |  | ||||||
|         view_dispatcher, |  | ||||||
|         static_cast<uint32_t>(SubghzAppViewManager::ViewType::SpectrumSettings), |  | ||||||
|         spectrum_settings->get_view()); |  | ||||||
| 
 |  | ||||||
|     gui = static_cast<Gui*>(furi_record_open("gui")); |  | ||||||
|     view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); |  | ||||||
| 
 |  | ||||||
|     // set previous view callback for all views
 |  | ||||||
|     view_set_previous_callback(submenu_get_view(submenu), callback); |  | ||||||
|     view_set_previous_callback(spectrum_settings->get_view(), callback); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| SubghzAppViewManager::~SubghzAppViewManager() { |  | ||||||
|     // remove views
 |  | ||||||
|     view_dispatcher_remove_view( |  | ||||||
|         view_dispatcher, static_cast<uint32_t>(SubghzAppViewManager::ViewType::Submenu)); |  | ||||||
|     view_dispatcher_remove_view( |  | ||||||
|         view_dispatcher, static_cast<uint32_t>(SubghzAppViewManager::ViewType::SpectrumSettings)); |  | ||||||
| 
 |  | ||||||
|     // free view modules
 |  | ||||||
|     submenu_free(submenu); |  | ||||||
|     free(spectrum_settings); |  | ||||||
| 
 |  | ||||||
|     // free dispatcher
 |  | ||||||
|     view_dispatcher_free(view_dispatcher); |  | ||||||
| 
 |  | ||||||
|     // free event queue
 |  | ||||||
|     osMessageQueueDelete(event_queue); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SubghzAppViewManager::switch_to(ViewType type) { |  | ||||||
|     view_dispatcher_switch_to_view(view_dispatcher, static_cast<uint32_t>(type)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Submenu* SubghzAppViewManager::get_submenu() { |  | ||||||
|     return submenu; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| SubghzViewSpectrumSettings* SubghzAppViewManager::get_spectrum_settings() { |  | ||||||
|     return spectrum_settings; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SubghzAppViewManager::receive_event(SubghzEvent* event) { |  | ||||||
|     if(osMessageQueueGet(event_queue, event, NULL, 100) != osOK) { |  | ||||||
|         event->type = SubghzEvent::Type::Tick; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SubghzAppViewManager::send_event(SubghzEvent* event) { |  | ||||||
|     osStatus_t result = osMessageQueuePut(event_queue, event, 0, 0); |  | ||||||
|     furi_check(result == osOK); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint32_t SubghzAppViewManager::previous_view_callback(void* context) { |  | ||||||
|     if(event_queue != NULL) { |  | ||||||
|         SubghzEvent event; |  | ||||||
|         event.type = SubghzEvent::Type::Back; |  | ||||||
|         send_event(&event); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return VIEW_IGNORE; |  | ||||||
| } |  | ||||||
| @ -1,37 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <furi.h> |  | ||||||
| #include <gui/view_dispatcher.h> |  | ||||||
| #include <gui/modules/submenu.h> |  | ||||||
| #include "subghz-event.h" |  | ||||||
| #include "view/subghz-view-spectrum-settings.h" |  | ||||||
| 
 |  | ||||||
| class SubghzAppViewManager { |  | ||||||
| public: |  | ||||||
|     enum class ViewType : uint8_t { |  | ||||||
|         Submenu, |  | ||||||
|         SpectrumSettings, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     osMessageQueueId_t event_queue; |  | ||||||
| 
 |  | ||||||
|     SubghzAppViewManager(); |  | ||||||
|     ~SubghzAppViewManager(); |  | ||||||
| 
 |  | ||||||
|     void switch_to(ViewType type); |  | ||||||
| 
 |  | ||||||
|     void receive_event(SubghzEvent* event); |  | ||||||
|     void send_event(SubghzEvent* event); |  | ||||||
| 
 |  | ||||||
|     Submenu* get_submenu(); |  | ||||||
|     SubghzViewSpectrumSettings* get_spectrum_settings(); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     ViewDispatcher* view_dispatcher; |  | ||||||
|     Gui* gui; |  | ||||||
| 
 |  | ||||||
|     uint32_t previous_view_callback(void* context); |  | ||||||
| 
 |  | ||||||
|     // view elements
 |  | ||||||
|     Submenu* submenu; |  | ||||||
|     SubghzViewSpectrumSettings* spectrum_settings; |  | ||||||
| }; |  | ||||||
							
								
								
									
										98
									
								
								applications/subghz/subghz.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								applications/subghz/subghz.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | |||||||
|  | #include "subghz_i.h" | ||||||
|  | 
 | ||||||
|  | osThreadId subghz_thread_id = NULL; | ||||||
|  | 
 | ||||||
|  | void subghz_menu_callback(void* context, uint32_t index) { | ||||||
|  |     furi_assert(context); | ||||||
|  | 
 | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  | 
 | ||||||
|  |     if(index == 0) { | ||||||
|  |         view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTestBasic); | ||||||
|  |     } else if(index == 1) { | ||||||
|  |         view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTestPacket); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t subghz_exit(void* context) { | ||||||
|  |     osThreadResume(subghz_thread_id); | ||||||
|  |     return VIEW_NONE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SubGhz* subghz_alloc() { | ||||||
|  |     SubGhz* subghz = furi_alloc(sizeof(SubGhz)); | ||||||
|  | 
 | ||||||
|  |     // Thread id
 | ||||||
|  |     subghz_thread_id = osThreadGetId(); | ||||||
|  | 
 | ||||||
|  |     // GUI
 | ||||||
|  |     subghz->gui = furi_record_open("gui"); | ||||||
|  | 
 | ||||||
|  |     // View Dispatcher
 | ||||||
|  |     subghz->view_dispatcher = view_dispatcher_alloc(); | ||||||
|  |     view_dispatcher_attach_to_gui( | ||||||
|  |         subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen); | ||||||
|  | 
 | ||||||
|  |     // Menu
 | ||||||
|  |     subghz->submenu = submenu_alloc(); | ||||||
|  |     submenu_add_item(subghz->submenu, "Basic Test", 0, subghz_menu_callback, subghz); | ||||||
|  |     submenu_add_item(subghz->submenu, "Packet Test", 1, subghz_menu_callback, subghz); | ||||||
|  |     View* submenu_view = submenu_get_view(subghz->submenu); | ||||||
|  |     view_set_previous_callback(submenu_view, subghz_exit); | ||||||
|  |     view_dispatcher_add_view(subghz->view_dispatcher, SubGhzViewMenu, submenu_view); | ||||||
|  | 
 | ||||||
|  |     // Basic Test Module
 | ||||||
|  |     subghz->subghz_test_basic = subghz_test_basic_alloc(); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         subghz->view_dispatcher, | ||||||
|  |         SubGhzViewTestBasic, | ||||||
|  |         subghz_test_basic_get_view(subghz->subghz_test_basic)); | ||||||
|  | 
 | ||||||
|  |     // Packet Test
 | ||||||
|  |     subghz->subghz_test_packet = subghz_test_packet_alloc(); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         subghz->view_dispatcher, | ||||||
|  |         SubGhzViewTestPacket, | ||||||
|  |         subghz_test_packet_get_view(subghz->subghz_test_packet)); | ||||||
|  | 
 | ||||||
|  |     // Switch to menu
 | ||||||
|  |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu); | ||||||
|  | 
 | ||||||
|  |     return subghz; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_free(SubGhz* subghz) { | ||||||
|  |     furi_assert(subghz); | ||||||
|  | 
 | ||||||
|  |     // Packet Test
 | ||||||
|  |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTestPacket); | ||||||
|  |     subghz_test_packet_free(subghz->subghz_test_packet); | ||||||
|  | 
 | ||||||
|  |     // Basic Test
 | ||||||
|  |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTestBasic); | ||||||
|  |     subghz_test_basic_free(subghz->subghz_test_basic); | ||||||
|  | 
 | ||||||
|  |     // Submenu
 | ||||||
|  |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewMenu); | ||||||
|  |     submenu_free(subghz->submenu); | ||||||
|  | 
 | ||||||
|  |     // View Dispatcher
 | ||||||
|  |     view_dispatcher_free(subghz->view_dispatcher); | ||||||
|  | 
 | ||||||
|  |     // GUI
 | ||||||
|  |     furi_record_close("gui"); | ||||||
|  |     subghz->gui = NULL; | ||||||
|  | 
 | ||||||
|  |     // The rest
 | ||||||
|  |     free(subghz); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t subghz_app(void* context) { | ||||||
|  |     SubGhz* subghz = subghz_alloc(); | ||||||
|  | 
 | ||||||
|  |     osThreadSuspend(subghz_thread_id); | ||||||
|  | 
 | ||||||
|  |     subghz_free(subghz); | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
| @ -1,10 +0,0 @@ | |||||||
| #include "subghz-app.h" |  | ||||||
| 
 |  | ||||||
| // app enter function
 |  | ||||||
| extern "C" int32_t app_subghz(void* p) { |  | ||||||
|     SubghzApp* app = new SubghzApp(); |  | ||||||
|     app->run(); |  | ||||||
|     delete app; |  | ||||||
| 
 |  | ||||||
|     return 255; |  | ||||||
| } |  | ||||||
							
								
								
									
										3
									
								
								applications/subghz/subghz.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								applications/subghz/subghz.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhz SubGhz; | ||||||
							
								
								
									
										44
									
								
								applications/subghz/subghz_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								applications/subghz/subghz_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "subghz.h" | ||||||
|  | #include "subghz_test_basic.h" | ||||||
|  | #include "subghz_test_packet.h" | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | #include <gui/gui.h> | ||||||
|  | #include <gui/view_dispatcher.h> | ||||||
|  | #include <gui/modules/submenu.h> | ||||||
|  | 
 | ||||||
|  | static const uint32_t subghz_frequencies[] = { | ||||||
|  |     301000000, | ||||||
|  |     315000000, | ||||||
|  |     346000000, | ||||||
|  |     385000000, | ||||||
|  |     433920000, | ||||||
|  |     438900000, | ||||||
|  |     463000000, | ||||||
|  |     781000000, | ||||||
|  |     868000000, | ||||||
|  |     915000000, | ||||||
|  |     925000000, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const uint32_t subghz_frequencies_count = sizeof(subghz_frequencies) / sizeof(uint32_t); | ||||||
|  | 
 | ||||||
|  | struct SubGhz { | ||||||
|  |     Gui* gui; | ||||||
|  | 
 | ||||||
|  |     ViewDispatcher* view_dispatcher; | ||||||
|  | 
 | ||||||
|  |     Submenu* submenu; | ||||||
|  | 
 | ||||||
|  |     SubghzTestBasic* subghz_test_basic; | ||||||
|  | 
 | ||||||
|  |     SubghzTestPacket* subghz_test_packet; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     SubGhzViewMenu, | ||||||
|  |     SubGhzViewTestBasic, | ||||||
|  |     SubGhzViewTestPacket, | ||||||
|  | } SubGhzView; | ||||||
							
								
								
									
										203
									
								
								applications/subghz/subghz_test_basic.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								applications/subghz/subghz_test_basic.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,203 @@ | |||||||
|  | #include "subghz_test_basic.h" | ||||||
|  | #include "subghz_i.h" | ||||||
|  | 
 | ||||||
|  | #include <math.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include <api-hal.h> | ||||||
|  | #include <input/input.h> | ||||||
|  | 
 | ||||||
|  | struct SubghzTestBasic { | ||||||
|  |     View* view; | ||||||
|  |     osTimerId timer; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     SubghzTestBasicModelStatusRx, | ||||||
|  |     SubghzTestBasicModelStatusTx, | ||||||
|  | } SubghzTestBasicModelStatus; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t frequency; | ||||||
|  |     uint32_t real_frequency; | ||||||
|  |     ApiHalSubGhzPath path; | ||||||
|  |     float rssi; | ||||||
|  |     SubghzTestBasicModelStatus status; | ||||||
|  | } SubghzTestBasicModel; | ||||||
|  | 
 | ||||||
|  | void subghz_test_basic_draw(Canvas* canvas, SubghzTestBasicModel* model) { | ||||||
|  |     char buffer[64]; | ||||||
|  | 
 | ||||||
|  |     canvas_set_color(canvas, ColorBlack); | ||||||
|  |     canvas_set_font(canvas, FontPrimary); | ||||||
|  |     canvas_draw_str(canvas, 2, 12, "CC1101 Basic Test"); | ||||||
|  | 
 | ||||||
|  |     canvas_set_font(canvas, FontSecondary); | ||||||
|  |     // Frequency
 | ||||||
|  |     snprintf( | ||||||
|  |         buffer, | ||||||
|  |         sizeof(buffer), | ||||||
|  |         "Freq: %03ld.%03ld.%03ld Hz", | ||||||
|  |         model->real_frequency / 1000000 % 1000, | ||||||
|  |         model->real_frequency / 1000 % 1000, | ||||||
|  |         model->real_frequency % 1000); | ||||||
|  |     canvas_draw_str(canvas, 2, 24, buffer); | ||||||
|  |     // Path
 | ||||||
|  |     char* path_name = "Unknown"; | ||||||
|  |     if(model->path == ApiHalSubGhzPathIsolate) { | ||||||
|  |         path_name = "isolate"; | ||||||
|  |     } else if(model->path == ApiHalSubGhzPath1) { | ||||||
|  |         path_name = "433MHz"; | ||||||
|  |     } else if(model->path == ApiHalSubGhzPath2) { | ||||||
|  |         path_name = "315MHz"; | ||||||
|  |     } else if(model->path == ApiHalSubGhzPath3) { | ||||||
|  |         path_name = "868MHz"; | ||||||
|  |     } | ||||||
|  |     snprintf(buffer, sizeof(buffer), "Path: %d - %s", model->path, path_name); | ||||||
|  |     canvas_draw_str(canvas, 2, 36, buffer); | ||||||
|  |     if(model->status == SubghzTestBasicModelStatusRx) { | ||||||
|  |         snprintf( | ||||||
|  |             buffer, | ||||||
|  |             sizeof(buffer), | ||||||
|  |             "RSSI: %ld.%ld dBm", | ||||||
|  |             (int32_t)(model->rssi), | ||||||
|  |             (int32_t)fabs(model->rssi * 10) % 10); | ||||||
|  |         canvas_draw_str(canvas, 2, 48, buffer); | ||||||
|  |     } else { | ||||||
|  |         canvas_draw_str(canvas, 2, 48, "TX"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_test_basic_input(InputEvent* event, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubghzTestBasic* subghz_test_basic = context; | ||||||
|  | 
 | ||||||
|  |     if(event->key == InputKeyBack) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_test_basic->view, (SubghzTestBasicModel * model) { | ||||||
|  |             osTimerStop(subghz_test_basic->timer); | ||||||
|  |             api_hal_subghz_idle(); | ||||||
|  | 
 | ||||||
|  |             if(event->type == InputTypeShort) { | ||||||
|  |                 if(event->key == InputKeyLeft) { | ||||||
|  |                     if(model->frequency > 0) model->frequency--; | ||||||
|  |                 } else if(event->key == InputKeyRight) { | ||||||
|  |                     if(model->frequency < subghz_frequencies_count - 1) model->frequency++; | ||||||
|  |                 } else if(event->key == InputKeyDown) { | ||||||
|  |                     if(model->path > 0) model->path--; | ||||||
|  |                 } else if(event->key == InputKeyUp) { | ||||||
|  |                     if(model->path < ApiHalSubGhzPath3) model->path++; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 model->real_frequency = | ||||||
|  |                     api_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); | ||||||
|  |                 api_hal_subghz_set_path(model->path); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(event->key == InputKeyOk) { | ||||||
|  |                 if(event->type == InputTypePress) { | ||||||
|  |                     model->status = SubghzTestBasicModelStatusTx; | ||||||
|  |                 } else if(event->type == InputTypeRelease) { | ||||||
|  |                     model->status = SubghzTestBasicModelStatusRx; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(model->status == SubghzTestBasicModelStatusRx) { | ||||||
|  |                 gpio_init(&cc1101_g0_gpio, GpioModeInput); | ||||||
|  |                 api_hal_subghz_rx(); | ||||||
|  |                 osTimerStart(subghz_test_basic->timer, 1024 / 4); | ||||||
|  |             } else { | ||||||
|  |                 gpio_init(&cc1101_g0_gpio, GpioModeOutputPushPull); | ||||||
|  |                 gpio_write(&cc1101_g0_gpio, false); | ||||||
|  |                 api_hal_subghz_tx(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_test_basic_enter(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubghzTestBasic* subghz_test_basic = context; | ||||||
|  | 
 | ||||||
|  |     api_hal_subghz_reset(); | ||||||
|  |     api_hal_subghz_load_preset(ApiHalSubGhzPresetOokAsync); | ||||||
|  | 
 | ||||||
|  |     gpio_init(&cc1101_g0_gpio, GpioModeInput); | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_test_basic->view, (SubghzTestBasicModel * model) { | ||||||
|  |             model->frequency = 4; // 433
 | ||||||
|  |             model->real_frequency = | ||||||
|  |                 api_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); | ||||||
|  |             model->path = ApiHalSubGhzPathIsolate; // isolate
 | ||||||
|  |             model->rssi = 0.0f; | ||||||
|  |             model->status = SubghzTestBasicModelStatusRx; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     api_hal_subghz_rx(); | ||||||
|  | 
 | ||||||
|  |     osTimerStart(subghz_test_basic->timer, 1024 / 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_test_basic_exit(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubghzTestBasic* subghz_test_basic = context; | ||||||
|  | 
 | ||||||
|  |     osTimerStop(subghz_test_basic->timer); | ||||||
|  | 
 | ||||||
|  |     // Reinitialize IC to default state
 | ||||||
|  |     api_hal_subghz_init(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_test_basic_rssi_timer_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubghzTestBasic* subghz_test_basic = context; | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_test_basic->view, (SubghzTestBasicModel * model) { | ||||||
|  |             model->rssi = api_hal_subghz_get_rssi(); | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t subghz_test_basic_back(void* context) { | ||||||
|  |     return SubGhzViewMenu; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SubghzTestBasic* subghz_test_basic_alloc() { | ||||||
|  |     SubghzTestBasic* subghz_test_basic = furi_alloc(sizeof(SubghzTestBasic)); | ||||||
|  | 
 | ||||||
|  |     // View allocation and configuration
 | ||||||
|  |     subghz_test_basic->view = view_alloc(); | ||||||
|  |     view_allocate_model( | ||||||
|  |         subghz_test_basic->view, ViewModelTypeLockFree, sizeof(SubghzTestBasicModel)); | ||||||
|  |     view_set_context(subghz_test_basic->view, subghz_test_basic); | ||||||
|  |     view_set_draw_callback(subghz_test_basic->view, (ViewDrawCallback)subghz_test_basic_draw); | ||||||
|  |     view_set_input_callback(subghz_test_basic->view, subghz_test_basic_input); | ||||||
|  |     view_set_enter_callback(subghz_test_basic->view, subghz_test_basic_enter); | ||||||
|  |     view_set_exit_callback(subghz_test_basic->view, subghz_test_basic_exit); | ||||||
|  |     view_set_previous_callback(subghz_test_basic->view, subghz_test_basic_back); | ||||||
|  | 
 | ||||||
|  |     subghz_test_basic->timer = osTimerNew( | ||||||
|  |         subghz_test_basic_rssi_timer_callback, osTimerPeriodic, subghz_test_basic, NULL); | ||||||
|  | 
 | ||||||
|  |     return subghz_test_basic; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_test_basic_free(SubghzTestBasic* subghz_test_basic) { | ||||||
|  |     furi_assert(subghz_test_basic); | ||||||
|  |     osTimerDelete(subghz_test_basic->timer); | ||||||
|  |     view_free(subghz_test_basic->view); | ||||||
|  |     free(subghz_test_basic); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* subghz_test_basic_get_view(SubghzTestBasic* subghz_test_basic) { | ||||||
|  |     furi_assert(subghz_test_basic); | ||||||
|  |     return subghz_test_basic->view; | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								applications/subghz/subghz_test_basic.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								applications/subghz/subghz_test_basic.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/view.h> | ||||||
|  | 
 | ||||||
|  | typedef struct SubghzTestBasic SubghzTestBasic; | ||||||
|  | 
 | ||||||
|  | SubghzTestBasic* subghz_test_basic_alloc(); | ||||||
|  | 
 | ||||||
|  | void subghz_test_basic_free(SubghzTestBasic* subghz_test_basic); | ||||||
|  | 
 | ||||||
|  | View* subghz_test_basic_get_view(SubghzTestBasic* subghz_test_basic); | ||||||
							
								
								
									
										210
									
								
								applications/subghz/subghz_test_packet.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								applications/subghz/subghz_test_packet.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,210 @@ | |||||||
|  | #include "subghz_test_packet.h" | ||||||
|  | #include "subghz_i.h" | ||||||
|  | 
 | ||||||
|  | #include <math.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include <api-hal.h> | ||||||
|  | #include <input/input.h> | ||||||
|  | 
 | ||||||
|  | static const uint8_t subghz_test_packet_data[] = { | ||||||
|  |     0x30, // 48bytes to transmit
 | ||||||
|  |     'F',  'L', 'I', 'P', 'P', 'E', 'R', ' ', 'T', 'E', 'S', 'T', ' ', 'P', 'A', 'C', | ||||||
|  |     'K',  'E', 'T', ' ', 'D', 'A', 'T', 'A', ' ', 'A', 'N', 'D', ' ', 'P', 'A', 'D', | ||||||
|  |     'F',  'L', 'I', 'P', 'P', 'E', 'R', ' ', 'T', 'E', 'S', 'T', ' ', 'P', 'A', 'C', | ||||||
|  | 
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubghzTestPacket { | ||||||
|  |     View* view; | ||||||
|  |     osTimerId timer; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     SubghzTestPacketModelStatusRx, | ||||||
|  |     SubghzTestPacketModelStatusTx, | ||||||
|  | } SubghzTestPacketModelStatus; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t frequency; | ||||||
|  |     uint32_t real_frequency; | ||||||
|  |     ApiHalSubGhzPath path; | ||||||
|  |     float rssi; | ||||||
|  |     SubghzTestPacketModelStatus status; | ||||||
|  | } SubghzTestPacketModel; | ||||||
|  | 
 | ||||||
|  | void subghz_test_packet_draw(Canvas* canvas, SubghzTestPacketModel* model) { | ||||||
|  |     char buffer[64]; | ||||||
|  | 
 | ||||||
|  |     canvas_set_color(canvas, ColorBlack); | ||||||
|  |     canvas_set_font(canvas, FontPrimary); | ||||||
|  |     canvas_draw_str(canvas, 2, 12, "CC1101 Packet Test"); | ||||||
|  | 
 | ||||||
|  |     canvas_set_font(canvas, FontSecondary); | ||||||
|  |     // Frequency
 | ||||||
|  |     snprintf( | ||||||
|  |         buffer, | ||||||
|  |         sizeof(buffer), | ||||||
|  |         "Freq: %03ld.%03ld.%03ld Hz", | ||||||
|  |         model->real_frequency / 1000000 % 1000, | ||||||
|  |         model->real_frequency / 1000 % 1000, | ||||||
|  |         model->real_frequency % 1000); | ||||||
|  |     canvas_draw_str(canvas, 2, 24, buffer); | ||||||
|  |     // Path
 | ||||||
|  |     char* path_name = "Unknown"; | ||||||
|  |     if(model->path == ApiHalSubGhzPathIsolate) { | ||||||
|  |         path_name = "isolate"; | ||||||
|  |     } else if(model->path == ApiHalSubGhzPath1) { | ||||||
|  |         path_name = "433MHz"; | ||||||
|  |     } else if(model->path == ApiHalSubGhzPath2) { | ||||||
|  |         path_name = "315MHz"; | ||||||
|  |     } else if(model->path == ApiHalSubGhzPath3) { | ||||||
|  |         path_name = "868MHz"; | ||||||
|  |     } | ||||||
|  |     snprintf(buffer, sizeof(buffer), "Path: %d - %s", model->path, path_name); | ||||||
|  |     canvas_draw_str(canvas, 2, 36, buffer); | ||||||
|  |     if(model->status == SubghzTestPacketModelStatusRx) { | ||||||
|  |         snprintf( | ||||||
|  |             buffer, | ||||||
|  |             sizeof(buffer), | ||||||
|  |             "RSSI: %ld.%ld dBm", | ||||||
|  |             (int32_t)(model->rssi), | ||||||
|  |             (int32_t)fabs(model->rssi * 10) % 10); | ||||||
|  |         canvas_draw_str(canvas, 2, 48, buffer); | ||||||
|  |     } else { | ||||||
|  |         canvas_draw_str(canvas, 2, 48, "TX"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_test_packet_input(InputEvent* event, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubghzTestPacket* subghz_test_packet = context; | ||||||
|  | 
 | ||||||
|  |     if(event->key == InputKeyBack) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_test_packet->view, (SubghzTestPacketModel * model) { | ||||||
|  |             osTimerStop(subghz_test_packet->timer); | ||||||
|  |             api_hal_subghz_idle(); | ||||||
|  | 
 | ||||||
|  |             if(event->type == InputTypeShort) { | ||||||
|  |                 if(event->key == InputKeyLeft) { | ||||||
|  |                     if(model->frequency > 0) model->frequency--; | ||||||
|  |                 } else if(event->key == InputKeyRight) { | ||||||
|  |                     if(model->frequency < subghz_frequencies_count - 1) model->frequency++; | ||||||
|  |                 } else if(event->key == InputKeyDown) { | ||||||
|  |                     if(model->path > 0) model->path--; | ||||||
|  |                 } else if(event->key == InputKeyUp) { | ||||||
|  |                     if(model->path < ApiHalSubGhzPath3) model->path++; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 model->real_frequency = | ||||||
|  |                     api_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); | ||||||
|  |                 api_hal_subghz_set_path(model->path); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(event->key == InputKeyOk) { | ||||||
|  |                 if(event->type == InputTypePress) { | ||||||
|  |                     model->status = SubghzTestPacketModelStatusTx; | ||||||
|  |                 } else if(event->type == InputTypeRelease) { | ||||||
|  |                     model->status = SubghzTestPacketModelStatusRx; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(model->status == SubghzTestPacketModelStatusRx) { | ||||||
|  |                 api_hal_subghz_rx(); | ||||||
|  |                 osTimerStart(subghz_test_packet->timer, 1024 / 4); | ||||||
|  |             } else { | ||||||
|  |                 api_hal_subghz_write_packet( | ||||||
|  |                     subghz_test_packet_data, sizeof(subghz_test_packet_data)); | ||||||
|  |                 api_hal_subghz_tx(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_test_packet_enter(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubghzTestPacket* subghz_test_packet = context; | ||||||
|  | 
 | ||||||
|  |     api_hal_subghz_reset(); | ||||||
|  |     api_hal_subghz_load_preset(ApiHalSubGhzPreset2FskPacket); | ||||||
|  | 
 | ||||||
|  |     gpio_init(&cc1101_g0_gpio, GpioModeInput); | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_test_packet->view, (SubghzTestPacketModel * model) { | ||||||
|  |             model->frequency = 4; // 433
 | ||||||
|  |             model->real_frequency = | ||||||
|  |                 api_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); | ||||||
|  |             model->path = ApiHalSubGhzPathIsolate; // isolate
 | ||||||
|  |             model->rssi = 0.0f; | ||||||
|  |             model->status = SubghzTestPacketModelStatusRx; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     api_hal_subghz_rx(); | ||||||
|  | 
 | ||||||
|  |     osTimerStart(subghz_test_packet->timer, 1024 / 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_test_packet_exit(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubghzTestPacket* subghz_test_packet = context; | ||||||
|  | 
 | ||||||
|  |     osTimerStop(subghz_test_packet->timer); | ||||||
|  | 
 | ||||||
|  |     // Reinitialize IC to default state
 | ||||||
|  |     api_hal_subghz_init(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_test_packet_rssi_timer_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubghzTestPacket* subghz_test_packet = context; | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_test_packet->view, (SubghzTestPacketModel * model) { | ||||||
|  |             model->rssi = api_hal_subghz_get_rssi(); | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t subghz_test_packet_back(void* context) { | ||||||
|  |     return SubGhzViewMenu; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SubghzTestPacket* subghz_test_packet_alloc() { | ||||||
|  |     SubghzTestPacket* subghz_test_packet = furi_alloc(sizeof(SubghzTestPacket)); | ||||||
|  | 
 | ||||||
|  |     // View allocation and configuration
 | ||||||
|  |     subghz_test_packet->view = view_alloc(); | ||||||
|  |     view_allocate_model( | ||||||
|  |         subghz_test_packet->view, ViewModelTypeLockFree, sizeof(SubghzTestPacketModel)); | ||||||
|  |     view_set_context(subghz_test_packet->view, subghz_test_packet); | ||||||
|  |     view_set_draw_callback(subghz_test_packet->view, (ViewDrawCallback)subghz_test_packet_draw); | ||||||
|  |     view_set_input_callback(subghz_test_packet->view, subghz_test_packet_input); | ||||||
|  |     view_set_enter_callback(subghz_test_packet->view, subghz_test_packet_enter); | ||||||
|  |     view_set_exit_callback(subghz_test_packet->view, subghz_test_packet_exit); | ||||||
|  |     view_set_previous_callback(subghz_test_packet->view, subghz_test_packet_back); | ||||||
|  | 
 | ||||||
|  |     subghz_test_packet->timer = osTimerNew( | ||||||
|  |         subghz_test_packet_rssi_timer_callback, osTimerPeriodic, subghz_test_packet, NULL); | ||||||
|  | 
 | ||||||
|  |     return subghz_test_packet; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_test_packet_free(SubghzTestPacket* subghz_test_packet) { | ||||||
|  |     furi_assert(subghz_test_packet); | ||||||
|  |     osTimerDelete(subghz_test_packet->timer); | ||||||
|  |     view_free(subghz_test_packet->view); | ||||||
|  |     free(subghz_test_packet); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* subghz_test_packet_get_view(SubghzTestPacket* subghz_test_packet) { | ||||||
|  |     furi_assert(subghz_test_packet); | ||||||
|  |     return subghz_test_packet->view; | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								applications/subghz/subghz_test_packet.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								applications/subghz/subghz_test_packet.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/view.h> | ||||||
|  | 
 | ||||||
|  | typedef struct SubghzTestPacket SubghzTestPacket; | ||||||
|  | 
 | ||||||
|  | SubghzTestPacket* subghz_test_packet_alloc(); | ||||||
|  | 
 | ||||||
|  | void subghz_test_packet_free(SubghzTestPacket* subghz_test_packet); | ||||||
|  | 
 | ||||||
|  | View* subghz_test_packet_get_view(SubghzTestPacket* subghz_test_packet); | ||||||
| @ -1,95 +0,0 @@ | |||||||
| #include "subghz-view-spectrum-settings.h" |  | ||||||
| #include <callback-connector.h> |  | ||||||
| 
 |  | ||||||
| struct SpectrumSettingsModel { |  | ||||||
|     uint32_t start_freq; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /***************************************************************************************/ |  | ||||||
| 
 |  | ||||||
| static void draw_callback(Canvas* canvas, void* _model) { |  | ||||||
|     SpectrumSettingsModel* model = static_cast<SpectrumSettingsModel*>(_model); |  | ||||||
|     const uint8_t str_size = 64; |  | ||||||
|     char str_buffer[str_size]; |  | ||||||
| 
 |  | ||||||
|     canvas_clear(canvas); |  | ||||||
|     snprintf(str_buffer, str_size, "Start freq < %ld > MHz", model->start_freq); |  | ||||||
|     canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, str_buffer); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static bool input_callback(InputEvent* event, void* context) { |  | ||||||
|     SubghzViewSpectrumSettings* _this = static_cast<SubghzViewSpectrumSettings*>(context); |  | ||||||
| 
 |  | ||||||
|     bool consumed = false; |  | ||||||
| 
 |  | ||||||
|     // Process key presses only
 |  | ||||||
|     if(event->type == InputTypeShort) { |  | ||||||
|         if(event->key == InputKeyOk) { |  | ||||||
|             _this->call_ok_callback(); |  | ||||||
|             consumed = true; |  | ||||||
|         } else if(event->key == InputKeyLeft) { |  | ||||||
|             with_view_model_cpp(_this->get_view(), SpectrumSettingsModel, model, { |  | ||||||
|                 model->start_freq--; |  | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
|             consumed = true; |  | ||||||
|         } else if(event->key == InputKeyRight) { |  | ||||||
|             with_view_model_cpp(_this->get_view(), SpectrumSettingsModel, model, { |  | ||||||
|                 model->start_freq++; |  | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
|             consumed = true; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return consumed; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /***************************************************************************************/ |  | ||||||
| 
 |  | ||||||
| View* SubghzViewSpectrumSettings::get_view() { |  | ||||||
|     return view; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SubghzViewSpectrumSettings::set_ok_callback(OkCallback callback, void* context) { |  | ||||||
|     ok_callback = callback; |  | ||||||
|     ok_callback_context = context; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SubghzViewSpectrumSettings::call_ok_callback() { |  | ||||||
|     if(ok_callback != nullptr) { |  | ||||||
|         ok_callback(ok_callback_context); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SubghzViewSpectrumSettings::set_start_freq(uint32_t start_freq) { |  | ||||||
|     with_view_model_cpp(view, SpectrumSettingsModel, model, { |  | ||||||
|         model->start_freq = start_freq; |  | ||||||
|         return true; |  | ||||||
|     }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint32_t SubghzViewSpectrumSettings::get_start_freq() { |  | ||||||
|     uint32_t result; |  | ||||||
| 
 |  | ||||||
|     with_view_model_cpp(view, SpectrumSettingsModel, model, { |  | ||||||
|         result = model->start_freq; |  | ||||||
|         return false; |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| SubghzViewSpectrumSettings::SubghzViewSpectrumSettings() { |  | ||||||
|     view = view_alloc(); |  | ||||||
|     view_set_context(view, this); |  | ||||||
|     view_allocate_model(view, ViewModelTypeLocking, sizeof(SpectrumSettingsModel)); |  | ||||||
| 
 |  | ||||||
|     view_set_draw_callback(view, draw_callback); |  | ||||||
| 
 |  | ||||||
|     view_set_input_callback(view, input_callback); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| SubghzViewSpectrumSettings::~SubghzViewSpectrumSettings() { |  | ||||||
|     view_free(view); |  | ||||||
| } |  | ||||||
| @ -1,25 +0,0 @@ | |||||||
| #include <gui/view.h> |  | ||||||
| 
 |  | ||||||
| class SubghzViewSpectrumSettings { |  | ||||||
| public: |  | ||||||
|     SubghzViewSpectrumSettings(); |  | ||||||
|     ~SubghzViewSpectrumSettings(); |  | ||||||
| 
 |  | ||||||
|     View* get_view(); |  | ||||||
| 
 |  | ||||||
|     // ok callback methods
 |  | ||||||
|     typedef void (*OkCallback)(void* context); |  | ||||||
|     void set_ok_callback(OkCallback callback, void* context); |  | ||||||
|     void call_ok_callback(); |  | ||||||
| 
 |  | ||||||
|     // model data getters/setters
 |  | ||||||
|     void set_start_freq(uint32_t start_freq); |  | ||||||
|     uint32_t get_start_freq(); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     View* view; |  | ||||||
| 
 |  | ||||||
|     // ok callback data
 |  | ||||||
|     OkCallback ok_callback = nullptr; |  | ||||||
|     void* ok_callback_context = nullptr; |  | ||||||
| }; |  | ||||||
| @ -55,7 +55,7 @@ flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME | |||||||
| # | # | ||||||
| # Note that there is a pretty wide band where things are | # Note that there is a pretty wide band where things are | ||||||
| # more or less stable, see http://openocd.zylin.com/#/c/3366/ | # more or less stable, see http://openocd.zylin.com/#/c/3366/ | ||||||
| adapter speed 8000 | adapter speed 24000 | ||||||
| 
 | 
 | ||||||
| adapter srst delay 100 | adapter srst delay 100 | ||||||
| if {[using_jtag]} { | if {[using_jtag]} { | ||||||
| @ -77,12 +77,12 @@ $_TARGETNAME configure -event reset-init { | |||||||
|     mmw 0x58004000 0x00000102 0  ;# FLASH_ACR |= PRFTBE | 2(Latency) |     mmw 0x58004000 0x00000102 0  ;# FLASH_ACR |= PRFTBE | 2(Latency) | ||||||
|     mmw 0x58000000 0x00000091 0  ;# RCC_CR = MSI_ON | MSI Range 24 MHz |     mmw 0x58000000 0x00000091 0  ;# RCC_CR = MSI_ON | MSI Range 24 MHz | ||||||
|     # Boost JTAG frequency |     # Boost JTAG frequency | ||||||
|     adapter speed 8000 |     adapter speed 24000 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| $_TARGETNAME configure -event reset-start { | $_TARGETNAME configure -event reset-start { | ||||||
|     # Reset clock is MSI (4 MHz) |     # Reset clock is MSI (4 MHz) | ||||||
|     adapter speed 8000 |     adapter speed 24000 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| $_TARGETNAME configure -event examine-end { | $_TARGETNAME configure -event examine-end { | ||||||
|  | |||||||
| @ -1,23 +1,98 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /** Sub-GHz band type */ | /** Radio Presets */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     RfBandIsolation = 0, |     ApiHalSubGhzPresetOokAsync,     /** OOK, asynchronous */ | ||||||
|     RfBand1 = 1, |     ApiHalSubGhzPreset2FskPacket,   /** 2FSK, 115kBaud, variable packet length */ | ||||||
|     RfBand2 = 2, | } ApiHalSubGhzPreset; | ||||||
|     RfBand3 = 3 |  | ||||||
| } RfBand; |  | ||||||
| 
 | 
 | ||||||
| /**
 | /**  Switchable Radio Paths */ | ||||||
|  * Set Sub-GHz band | typedef enum { | ||||||
|  * @param band RfBand |     ApiHalSubGhzPathIsolate,        /** Isolate Radio from antenna */ | ||||||
|  |     ApiHalSubGhzPath1,              /** Path 1: SW1RF1-SW2RF2, LCLCL */ | ||||||
|  |     ApiHalSubGhzPath2,              /** Path 2: SW1RF2-SW2RF1, LCLCLCL */ | ||||||
|  |     ApiHalSubGhzPath3,              /** Path 3: SW1RF3-SW2RF3, LCLC */ | ||||||
|  | } ApiHalSubGhzPath; | ||||||
|  | 
 | ||||||
|  | /** Initialize and switch to power save mode
 | ||||||
|  |  * Used by internal API-HAL initalization routine | ||||||
|  |  * Can be used to reinitialize device to safe state and send it to sleep | ||||||
|  */ |  */ | ||||||
| void api_hal_rf_band_set(RfBand band); | void api_hal_subghz_init(); | ||||||
|  | 
 | ||||||
|  | /** Dump info to stdout */ | ||||||
|  | void api_hal_subghz_dump_state(); | ||||||
|  | 
 | ||||||
|  | /** Load registers from preset by preset name 
 | ||||||
|  |  * @param preset to load | ||||||
|  |  */ | ||||||
|  | void api_hal_subghz_load_preset(ApiHalSubGhzPreset preset); | ||||||
|  | 
 | ||||||
|  | /** Load registers
 | ||||||
|  |  * @param register-value pairs array, terminated with {0,0} | ||||||
|  |  */ | ||||||
|  | void api_hal_subghz_load_registers(const uint8_t data[][2]); | ||||||
|  | 
 | ||||||
|  | /** Load PATABLE
 | ||||||
|  |  * @param data, 8 uint8_t values | ||||||
|  |  */ | ||||||
|  | void api_hal_subghz_load_patable(const uint8_t data[8]); | ||||||
|  | 
 | ||||||
|  | /** Write packet to FIFO
 | ||||||
|  |  * @param data, bytes array | ||||||
|  |  * @param size, size | ||||||
|  |  */ | ||||||
|  | void api_hal_subghz_write_packet(const uint8_t* data, uint8_t size); | ||||||
|  | 
 | ||||||
|  | /** Read packet from FIFO
 | ||||||
|  |  * @param data, pointer | ||||||
|  |  * @param size, size | ||||||
|  |  */ | ||||||
|  | void api_hal_subghz_read_packet(uint8_t* data, uint8_t size); | ||||||
|  | 
 | ||||||
|  | /** Shutdown
 | ||||||
|  |  * Issue spwd command | ||||||
|  |  * @warning registers content will be lost | ||||||
|  |  */ | ||||||
|  | void api_hal_subghz_shutdown(); | ||||||
|  | 
 | ||||||
|  | /** Reset
 | ||||||
|  |  * Issue reset command | ||||||
|  |  * @warning registers content will be lost | ||||||
|  |  */ | ||||||
|  | void api_hal_subghz_reset(); | ||||||
|  | 
 | ||||||
|  | /** Switch to Idle */ | ||||||
|  | void api_hal_subghz_idle(); | ||||||
|  | 
 | ||||||
|  | /** Switch to Recieve */ | ||||||
|  | void api_hal_subghz_rx(); | ||||||
|  | 
 | ||||||
|  | /** Switch to Transmit */ | ||||||
|  | void api_hal_subghz_tx(); | ||||||
|  | 
 | ||||||
|  | /** Get RSSI value in dBm */ | ||||||
|  | float api_hal_subghz_get_rssi(); | ||||||
|  | 
 | ||||||
|  | /** Set frequency
 | ||||||
|  |  * @param frequency in herz | ||||||
|  |  * @return real frequency in herz | ||||||
|  |  */ | ||||||
|  | uint32_t api_hal_subghz_set_frequency(uint32_t value); | ||||||
|  | 
 | ||||||
|  | /** Set path
 | ||||||
|  |  * @param radio path to use | ||||||
|  |  */ | ||||||
|  | void api_hal_subghz_set_path(ApiHalSubGhzPath path); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -1,153 +1,103 @@ | |||||||
| /* USER CODE BEGIN Header */ | #pragma once | ||||||
| /**
 |  | ||||||
|   ****************************************************************************** |  | ||||||
|   * @file           : main.h |  | ||||||
|   * @brief          : Header for main.c file. |  | ||||||
|   *                   This file contains the common defines of the application. |  | ||||||
|   ****************************************************************************** |  | ||||||
|   * @attention |  | ||||||
|   * |  | ||||||
|   * <h2><center>© Copyright (c) 2020 STMicroelectronics. |  | ||||||
|   * All rights reserved.</center></h2> |  | ||||||
|   * |  | ||||||
|   * This software component is licensed by ST under Ultimate Liberty license |  | ||||||
|   * SLA0044, the "License"; You may not use this file except in compliance with |  | ||||||
|   * the License. You may obtain a copy of the License at: |  | ||||||
|   *                             www.st.com/SLA0044 |  | ||||||
|   * |  | ||||||
|   ****************************************************************************** |  | ||||||
|   */ |  | ||||||
| /* USER CODE END Header */ |  | ||||||
| 
 |  | ||||||
| /* Define to prevent recursive inclusion -------------------------------------*/ |  | ||||||
| #ifndef __MAIN_H |  | ||||||
| #define __MAIN_H |  | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /* Includes ------------------------------------------------------------------*/ |  | ||||||
| #include "stm32wbxx_hal.h" | #include "stm32wbxx_hal.h" | ||||||
| 
 | 
 | ||||||
| /* Private includes ----------------------------------------------------------*/ |  | ||||||
| /* USER CODE BEGIN Includes */ |  | ||||||
| 
 |  | ||||||
| /* USER CODE END Includes */ |  | ||||||
| 
 |  | ||||||
| /* Exported types ------------------------------------------------------------*/ |  | ||||||
| /* USER CODE BEGIN ET */ |  | ||||||
| 
 |  | ||||||
| /* USER CODE END ET */ |  | ||||||
| 
 |  | ||||||
| /* Exported constants --------------------------------------------------------*/ |  | ||||||
| /* USER CODE BEGIN EC */ |  | ||||||
| 
 |  | ||||||
| /* USER CODE END EC */ |  | ||||||
| 
 |  | ||||||
| /* Exported macro ------------------------------------------------------------*/ |  | ||||||
| /* USER CODE BEGIN EM */ |  | ||||||
| 
 |  | ||||||
| /* USER CODE END EM */ |  | ||||||
| 
 |  | ||||||
| /* Exported functions prototypes ---------------------------------------------*/ |  | ||||||
| void Error_Handler(void); | void Error_Handler(void); | ||||||
| 
 | 
 | ||||||
| /* USER CODE BEGIN EFP */ |  | ||||||
| 
 |  | ||||||
| /* USER CODE END EFP */ |  | ||||||
| 
 |  | ||||||
| /* Private defines -----------------------------------------------------------*/ |  | ||||||
| #define BUTTON_BACK_Pin GPIO_PIN_13 |  | ||||||
| #define BUTTON_BACK_GPIO_Port GPIOC |  | ||||||
| #define BUTTON_BACK_EXTI_IRQn EXTI15_10_IRQn | #define BUTTON_BACK_EXTI_IRQn EXTI15_10_IRQn | ||||||
| #define QUARTZ_32MHZ_IN_Pin GPIO_PIN_14 | #define BUTTON_BACK_GPIO_Port GPIOC | ||||||
| #define QUARTZ_32MHZ_IN_GPIO_Port GPIOC | #define BUTTON_BACK_Pin GPIO_PIN_13 | ||||||
| #define QUARTZ_32MHZ_OUT_Pin GPIO_PIN_15 |  | ||||||
| #define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC |  | ||||||
| #define BUTTON_OK_Pin GPIO_PIN_3 |  | ||||||
| #define BUTTON_OK_GPIO_Port GPIOH |  | ||||||
| #define BUTTON_OK_EXTI_IRQn EXTI3_IRQn |  | ||||||
| #define SPEAKER_Pin GPIO_PIN_8 |  | ||||||
| #define SPEAKER_GPIO_Port GPIOB |  | ||||||
| #define IR_TX_Pin GPIO_PIN_9 |  | ||||||
| #define IR_TX_GPIO_Port GPIOB |  | ||||||
| #define PC0_Pin GPIO_PIN_0 |  | ||||||
| #define PC0_GPIO_Port GPIOC |  | ||||||
| #define PC1_Pin GPIO_PIN_1 |  | ||||||
| #define PC1_GPIO_Port GPIOC |  | ||||||
| #define PC3_Pin GPIO_PIN_3 |  | ||||||
| #define PC3_GPIO_Port GPIOC |  | ||||||
| #define IR_RX_Pin GPIO_PIN_0 |  | ||||||
| #define IR_RX_GPIO_Port GPIOA |  | ||||||
| #define LED_RED_Pin GPIO_PIN_1 |  | ||||||
| #define LED_RED_GPIO_Port GPIOA |  | ||||||
| #define LED_GREEN_Pin GPIO_PIN_2 |  | ||||||
| #define LED_GREEN_GPIO_Port GPIOA |  | ||||||
| #define LED_BLUE_Pin GPIO_PIN_3 |  | ||||||
| #define LED_BLUE_GPIO_Port GPIOA |  | ||||||
| #define PA4_Pin GPIO_PIN_4 |  | ||||||
| #define PA4_GPIO_Port GPIOA |  | ||||||
| #define SPI_R_SCK_Pin GPIO_PIN_5 |  | ||||||
| #define SPI_R_SCK_GPIO_Port GPIOA |  | ||||||
| #define PA6_Pin GPIO_PIN_6 |  | ||||||
| #define PA6_GPIO_Port GPIOA |  | ||||||
| #define PA7_Pin GPIO_PIN_7 |  | ||||||
| #define PA7_GPIO_Port GPIOA |  | ||||||
| #define RFID_PULL_Pin GPIO_PIN_8 |  | ||||||
| #define RFID_PULL_GPIO_Port GPIOA |  | ||||||
| #define RFID_PULL_EXTI_IRQn EXTI9_5_IRQn |  | ||||||
| #define CC1101_G0_Pin GPIO_PIN_4 |  | ||||||
| #define CC1101_G0_GPIO_Port GPIOC |  | ||||||
| #define RFID_RF_IN_Pin GPIO_PIN_5 |  | ||||||
| #define RFID_RF_IN_GPIO_Port GPIOC |  | ||||||
| #define PB2_Pin GPIO_PIN_2 |  | ||||||
| #define PB2_GPIO_Port GPIOB |  | ||||||
| #define BUTTON_UP_Pin GPIO_PIN_10 |  | ||||||
| #define BUTTON_UP_GPIO_Port GPIOB |  | ||||||
| #define BUTTON_UP_EXTI_IRQn EXTI15_10_IRQn |  | ||||||
| #define BUTTON_LEFT_Pin GPIO_PIN_11 |  | ||||||
| #define BUTTON_LEFT_GPIO_Port GPIOB |  | ||||||
| #define BUTTON_LEFT_EXTI_IRQn EXTI15_10_IRQn |  | ||||||
| #define DISPLAY_RST_Pin GPIO_PIN_0 |  | ||||||
| #define DISPLAY_RST_GPIO_Port GPIOB |  | ||||||
| #define BUTTON_DOWN_Pin GPIO_PIN_1 |  | ||||||
| #define BUTTON_DOWN_GPIO_Port GPIOB |  | ||||||
| #define BUTTON_DOWN_EXTI_IRQn EXTI1_IRQn | #define BUTTON_DOWN_EXTI_IRQn EXTI1_IRQn | ||||||
| #define NFC_CS_Pin GPIO_PIN_4 | #define BUTTON_DOWN_GPIO_Port GPIOB | ||||||
| #define NFC_CS_GPIO_Port GPIOE | #define BUTTON_DOWN_Pin GPIO_PIN_1 | ||||||
| #define BUTTON_RIGHT_Pin GPIO_PIN_12 | #define BUTTON_LEFT_EXTI_IRQn EXTI15_10_IRQn | ||||||
| #define BUTTON_RIGHT_GPIO_Port GPIOB | #define BUTTON_LEFT_GPIO_Port GPIOB | ||||||
|  | #define BUTTON_LEFT_Pin GPIO_PIN_11 | ||||||
|  | #define BUTTON_OK_EXTI_IRQn EXTI3_IRQn | ||||||
|  | #define BUTTON_OK_GPIO_Port GPIOH | ||||||
|  | #define BUTTON_OK_Pin GPIO_PIN_3 | ||||||
| #define BUTTON_RIGHT_EXTI_IRQn EXTI15_10_IRQn | #define BUTTON_RIGHT_EXTI_IRQn EXTI15_10_IRQn | ||||||
| #define RFID_OUT_Pin GPIO_PIN_13 | #define BUTTON_RIGHT_GPIO_Port GPIOB | ||||||
| #define RFID_OUT_GPIO_Port GPIOB | #define BUTTON_RIGHT_Pin GPIO_PIN_12 | ||||||
| #define iBTN_Pin GPIO_PIN_14 | #define BUTTON_UP_EXTI_IRQn EXTI15_10_IRQn | ||||||
| #define iBTN_GPIO_Port GPIOB | #define BUTTON_UP_GPIO_Port GPIOB | ||||||
| #define SPI_D_MOSI_Pin GPIO_PIN_15 | #define BUTTON_UP_Pin GPIO_PIN_10 | ||||||
| #define SPI_D_MOSI_GPIO_Port GPIOB |  | ||||||
| #define DISPLAY_DI_Pin GPIO_PIN_6 |  | ||||||
| #define DISPLAY_DI_GPIO_Port GPIOC |  | ||||||
| #define DISPLAY_BACKLIGHT_Pin GPIO_PIN_15 |  | ||||||
| #define DISPLAY_BACKLIGHT_GPIO_Port GPIOA |  | ||||||
| #define PC10_Pin GPIO_PIN_10 |  | ||||||
| #define PC10_GPIO_Port GPIOC |  | ||||||
| #define DISPLAY_CS_Pin GPIO_PIN_11 |  | ||||||
| #define DISPLAY_CS_GPIO_Port GPIOC |  | ||||||
| #define SD_CS_Pin GPIO_PIN_12 |  | ||||||
| #define SD_CS_GPIO_Port GPIOC |  | ||||||
| #define CC1101_CS_Pin GPIO_PIN_0 |  | ||||||
| #define CC1101_CS_GPIO_Port GPIOD | #define CC1101_CS_GPIO_Port GPIOD | ||||||
| #define SPI_D_SCK_Pin GPIO_PIN_1 | #define CC1101_CS_Pin GPIO_PIN_0 | ||||||
| #define SPI_D_SCK_GPIO_Port GPIOD | #define CC1101_G0_GPIO_Port GPIOC | ||||||
| #define PB3_Pin GPIO_PIN_3 | #define CC1101_G0_Pin GPIO_PIN_4 | ||||||
|  | #define DISPLAY_BACKLIGHT_GPIO_Port GPIOA | ||||||
|  | #define DISPLAY_BACKLIGHT_Pin GPIO_PIN_15 | ||||||
|  | #define DISPLAY_CS_GPIO_Port GPIOC | ||||||
|  | #define DISPLAY_CS_Pin GPIO_PIN_11 | ||||||
|  | #define DISPLAY_DI_GPIO_Port GPIOC | ||||||
|  | #define DISPLAY_DI_Pin GPIO_PIN_6 | ||||||
|  | #define DISPLAY_RST_GPIO_Port GPIOB | ||||||
|  | #define DISPLAY_RST_Pin GPIO_PIN_0 | ||||||
|  | #define IR_RX_GPIO_Port GPIOA | ||||||
|  | #define IR_RX_Pin GPIO_PIN_0 | ||||||
|  | #define IR_TX_GPIO_Port GPIOB | ||||||
|  | #define IR_TX_Pin GPIO_PIN_9 | ||||||
|  | #define LED_BLUE_GPIO_Port GPIOA | ||||||
|  | #define LED_BLUE_Pin GPIO_PIN_3 | ||||||
|  | #define LED_GREEN_GPIO_Port GPIOA | ||||||
|  | #define LED_GREEN_Pin GPIO_PIN_2 | ||||||
|  | #define LED_RED_GPIO_Port GPIOA | ||||||
|  | #define LED_RED_Pin GPIO_PIN_1 | ||||||
|  | #define NFC_CS_GPIO_Port GPIOE | ||||||
|  | #define NFC_CS_Pin GPIO_PIN_4 | ||||||
|  | #define PA4_GPIO_Port GPIOA | ||||||
|  | #define PA4_Pin GPIO_PIN_4 | ||||||
|  | #define PA6_GPIO_Port GPIOA | ||||||
|  | #define PA6_Pin GPIO_PIN_6 | ||||||
|  | #define PA7_GPIO_Port GPIOA | ||||||
|  | #define PA7_Pin GPIO_PIN_7 | ||||||
|  | #define PB2_GPIO_Port GPIOB | ||||||
|  | #define PB2_Pin GPIO_PIN_2 | ||||||
| #define PB3_GPIO_Port GPIOB | #define PB3_GPIO_Port GPIOB | ||||||
| #define SPI_R_MISO_Pin GPIO_PIN_4 | #define PB3_Pin GPIO_PIN_3 | ||||||
| #define SPI_R_MISO_GPIO_Port GPIOB | #define PC0_GPIO_Port GPIOC | ||||||
| #define SPI_R_MOSI_Pin GPIO_PIN_5 | #define PC0_Pin GPIO_PIN_0 | ||||||
| #define SPI_R_MOSI_GPIO_Port GPIOB | #define PC10_GPIO_Port GPIOC | ||||||
| /* USER CODE BEGIN Private defines */ | #define PC10_Pin GPIO_PIN_10 | ||||||
|  | #define PC1_GPIO_Port GPIOC | ||||||
|  | #define PC1_Pin GPIO_PIN_1 | ||||||
|  | #define PC3_GPIO_Port GPIOC | ||||||
|  | #define PC3_Pin GPIO_PIN_3 | ||||||
|  | #define QUARTZ_32MHZ_IN_GPIO_Port GPIOC | ||||||
|  | #define QUARTZ_32MHZ_IN_Pin GPIO_PIN_14 | ||||||
|  | #define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC | ||||||
|  | #define QUARTZ_32MHZ_OUT_Pin GPIO_PIN_15 | ||||||
|  | #define RFID_OUT_GPIO_Port GPIOB | ||||||
|  | #define RFID_OUT_Pin GPIO_PIN_13 | ||||||
|  | #define RFID_PULL_EXTI_IRQn EXTI9_5_IRQn | ||||||
|  | #define RFID_PULL_GPIO_Port GPIOA | ||||||
|  | #define RFID_PULL_Pin GPIO_PIN_8 | ||||||
|  | #define RFID_RF_IN_GPIO_Port GPIOC | ||||||
|  | #define RFID_RF_IN_Pin GPIO_PIN_5 | ||||||
|  | #define SD_CS_GPIO_Port GPIOC | ||||||
|  | #define SD_CS_Pin GPIO_PIN_12 | ||||||
|  | #define SPEAKER_GPIO_Port GPIOB | ||||||
|  | #define SPEAKER_Pin GPIO_PIN_8 | ||||||
|  | #define iBTN_GPIO_Port GPIOB | ||||||
|  | #define iBTN_Pin GPIO_PIN_14 | ||||||
| 
 | 
 | ||||||
| #define MISO_PIN GpioPin{.port = SPI_R_MISO_GPIO_Port, .pin = SPI_R_MISO_Pin} | #define SPI_D_MISO_GPIO_Port GPIOC | ||||||
|  | #define SPI_D_MISO_Pin GPIO_PIN_2 | ||||||
|  | #define SPI_D_MOSI_GPIO_Port GPIOB | ||||||
|  | #define SPI_D_MOSI_Pin GPIO_PIN_15 | ||||||
|  | #define SPI_D_SCK_GPIO_Port GPIOD | ||||||
|  | #define SPI_D_SCK_Pin GPIO_PIN_1 | ||||||
|  | #define SPI_R_MISO_GPIO_Port GPIOB | ||||||
|  | #define SPI_R_MISO_Pin GPIO_PIN_4 | ||||||
|  | #define SPI_R_MOSI_GPIO_Port GPIOB | ||||||
|  | #define SPI_R_MOSI_Pin GPIO_PIN_5 | ||||||
|  | #define SPI_R_SCK_GPIO_Port GPIOA | ||||||
|  | #define SPI_R_SCK_Pin GPIO_PIN_5 | ||||||
| 
 | 
 | ||||||
| #define SPI_R hspi1 | #define SPI_R hspi1 | ||||||
| #define SPI_D hspi2 | #define SPI_D hspi2 | ||||||
| @ -183,12 +133,6 @@ extern TIM_HandleTypeDef htim16; | |||||||
| #define VIBRO_Pin GPIO_PIN_10 | #define VIBRO_Pin GPIO_PIN_10 | ||||||
| #define VIBRO_GPIO_Port GPIOC | #define VIBRO_GPIO_Port GPIOC | ||||||
| 
 | 
 | ||||||
| /* USER CODE END Private defines */ |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 |  | ||||||
| #endif /* __MAIN_H */ |  | ||||||
| 
 |  | ||||||
| /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ |  | ||||||
|  | |||||||
| @ -23,5 +23,6 @@ void delay_us(float microseconds) { | |||||||
| void delay(float milliseconds) { | void delay(float milliseconds) { | ||||||
|     uint32_t ticks = milliseconds / (1000.0f / osKernelGetTickFreq()); |     uint32_t ticks = milliseconds / (1000.0f / osKernelGetTickFreq()); | ||||||
|     osStatus_t result = osDelay(ticks); |     osStatus_t result = osDelay(ticks); | ||||||
|  |     (void)result; | ||||||
|     assert(result == osOK); |     assert(result == osOK); | ||||||
| } | } | ||||||
| @ -4,35 +4,41 @@ | |||||||
| 
 | 
 | ||||||
| const InputPin input_pins[] = { | const InputPin input_pins[] = { | ||||||
|     {.port = BUTTON_UP_GPIO_Port, .pin = BUTTON_UP_Pin, .key = InputKeyUp, .inverted = true}, |     {.port = BUTTON_UP_GPIO_Port, .pin = BUTTON_UP_Pin, .key = InputKeyUp, .inverted = true}, | ||||||
|     {.port = BUTTON_DOWN_GPIO_Port, .pin = BUTTON_DOWN_Pin, .key = InputKeyDown, .inverted = true}, |     {.port = BUTTON_DOWN_GPIO_Port, | ||||||
|  |      .pin = BUTTON_DOWN_Pin, | ||||||
|  |      .key = InputKeyDown, | ||||||
|  |      .inverted = true}, | ||||||
|     {.port = BUTTON_RIGHT_GPIO_Port, |     {.port = BUTTON_RIGHT_GPIO_Port, | ||||||
|      .pin = BUTTON_RIGHT_Pin, |      .pin = BUTTON_RIGHT_Pin, | ||||||
|      .key = InputKeyRight, |      .key = InputKeyRight, | ||||||
|      .inverted = true}, |      .inverted = true}, | ||||||
|     {.port = BUTTON_LEFT_GPIO_Port, .pin = BUTTON_LEFT_Pin, .key = InputKeyLeft, .inverted = true}, |     {.port = BUTTON_LEFT_GPIO_Port, | ||||||
|  |      .pin = BUTTON_LEFT_Pin, | ||||||
|  |      .key = InputKeyLeft, | ||||||
|  |      .inverted = true}, | ||||||
|     {.port = BUTTON_OK_GPIO_Port, .pin = BUTTON_OK_Pin, .key = InputKeyOk, .inverted = false}, |     {.port = BUTTON_OK_GPIO_Port, .pin = BUTTON_OK_Pin, .key = InputKeyOk, .inverted = false}, | ||||||
|     {.port = BUTTON_BACK_GPIO_Port, .pin = BUTTON_BACK_Pin, .key = InputKeyBack, .inverted = true}, |     {.port = BUTTON_BACK_GPIO_Port, | ||||||
|  |      .pin = BUTTON_BACK_Pin, | ||||||
|  |      .key = InputKeyBack, | ||||||
|  |      .inverted = true}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin); | const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin); | ||||||
| 
 | 
 | ||||||
| const GpioPin led_gpio[3] = { |  | ||||||
|     {LED_RED_GPIO_Port, LED_RED_Pin}, |  | ||||||
|     {LED_GREEN_GPIO_Port, LED_GREEN_Pin}, |  | ||||||
|     {LED_BLUE_GPIO_Port, LED_BLUE_Pin}}; |  | ||||||
| 
 |  | ||||||
| const GpioPin backlight_gpio = {DISPLAY_BACKLIGHT_GPIO_Port, DISPLAY_BACKLIGHT_Pin}; |  | ||||||
| const GpioPin sd_cs_gpio = {SD_CS_GPIO_Port, SD_CS_Pin}; |  | ||||||
| const GpioPin vibro_gpio = {VIBRO_GPIO_Port, VIBRO_Pin}; | const GpioPin vibro_gpio = {VIBRO_GPIO_Port, VIBRO_Pin}; | ||||||
| const GpioPin ibutton_gpio = {iBTN_GPIO_Port, iBTN_Pin}; | const GpioPin ibutton_gpio = {iBTN_GPIO_Port, iBTN_Pin}; | ||||||
| const GpioPin cc1101_g0_gpio = {CC1101_G0_GPIO_Port, CC1101_G0_Pin}; | const GpioPin cc1101_g0_gpio = {CC1101_G0_GPIO_Port, CC1101_G0_Pin}; | ||||||
| 
 | 
 | ||||||
| // external gpio's
 | const GpioPin gpio_subghz_cs = { .port=CC1101_CS_GPIO_Port, .pin=CC1101_CS_Pin }; | ||||||
| const GpioPin ext_pc0_gpio = {GPIOC, GPIO_PIN_0}; | const GpioPin gpio_display_cs = { .port=DISPLAY_CS_GPIO_Port, .pin=DISPLAY_CS_Pin }; | ||||||
| const GpioPin ext_pc1_gpio = {GPIOC, GPIO_PIN_1}; | const GpioPin gpio_display_rst = { .port=DISPLAY_RST_GPIO_Port, .pin=DISPLAY_RST_Pin }; | ||||||
| const GpioPin ext_pc3_gpio = {GPIOC, GPIO_PIN_3}; | const GpioPin gpio_display_di = { .port=DISPLAY_DI_GPIO_Port, .pin=DISPLAY_DI_Pin }; | ||||||
| const GpioPin ext_pb2_gpio = {GPIOB, GPIO_PIN_2}; | const GpioPin gpio_sdcard_cs = { .port=SD_CS_GPIO_Port, .pin=SD_CS_Pin }; | ||||||
| const GpioPin ext_pb3_gpio = {GPIOB, GPIO_PIN_3}; | const GpioPin gpio_nfc_cs = { .port=NFC_CS_GPIO_Port, .pin=NFC_CS_Pin }; | ||||||
| const GpioPin ext_pa4_gpio = {GPIOA, GPIO_PIN_4}; | 
 | ||||||
| const GpioPin ext_pa6_gpio = {GPIOA, GPIO_PIN_6}; | const GpioPin gpio_spi_d_miso = { .port=SPI_D_MISO_GPIO_Port, .pin=SPI_D_MISO_Pin }; | ||||||
| const GpioPin ext_pa7_gpio = {GPIOA, GPIO_PIN_7}; | const GpioPin gpio_spi_d_mosi = { .port=SPI_D_MOSI_GPIO_Port, .pin=SPI_D_MOSI_Pin }; | ||||||
|  | const GpioPin gpio_spi_d_sck = { .port=SPI_D_SCK_GPIO_Port, .pin=SPI_D_SCK_Pin }; | ||||||
|  | const GpioPin gpio_spi_r_miso = { .port=SPI_R_MISO_GPIO_Port, .pin=SPI_R_MISO_Pin }; | ||||||
|  | const GpioPin gpio_spi_r_mosi = { .port=SPI_R_MOSI_GPIO_Port, .pin=SPI_R_MOSI_Pin }; | ||||||
|  | const GpioPin gpio_spi_r_sck = { .port=SPI_R_SCK_GPIO_Port, .pin=SPI_R_SCK_Pin }; | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ extern "C" { | |||||||
| #define POWER_I2C_SDA_GPIO_Port GPIOA | #define POWER_I2C_SDA_GPIO_Port GPIOA | ||||||
| 
 | 
 | ||||||
| #define POWER_I2C I2C1 | #define POWER_I2C I2C1 | ||||||
| /* Timing register value is computed with the STM32CubeMX Tool,
 | /** Timing register value is computed with the STM32CubeMX Tool,
 | ||||||
|   * Fast Mode @100kHz with I2CCLK = 64 MHz, |   * Fast Mode @100kHz with I2CCLK = 64 MHz, | ||||||
|   * rise time = 0ns, fall time = 0ns |   * rise time = 0ns, fall time = 0ns | ||||||
|   */ |   */ | ||||||
| @ -53,20 +53,27 @@ typedef struct { | |||||||
| extern const InputPin input_pins[]; | extern const InputPin input_pins[]; | ||||||
| extern const size_t input_pins_count; | extern const size_t input_pins_count; | ||||||
| 
 | 
 | ||||||
| extern const GpioPin sd_cs_gpio; |  | ||||||
| extern const GpioPin vibro_gpio; | extern const GpioPin vibro_gpio; | ||||||
| extern const GpioPin ibutton_gpio; | extern const GpioPin ibutton_gpio; | ||||||
| extern const GpioPin cc1101_g0_gpio; | extern const GpioPin cc1101_g0_gpio; | ||||||
| 
 | 
 | ||||||
| // external gpio's
 | extern const GpioPin gpio_subghz_cs; | ||||||
| extern const GpioPin ext_pc0_gpio; | extern const GpioPin gpio_display_cs; | ||||||
| extern const GpioPin ext_pc1_gpio; | 
 | ||||||
| extern const GpioPin ext_pc3_gpio; | extern const GpioPin gpio_subghz_cs; | ||||||
| extern const GpioPin ext_pb2_gpio; | extern const GpioPin gpio_display_cs; | ||||||
| extern const GpioPin ext_pb3_gpio; | extern const GpioPin gpio_display_rst; | ||||||
| extern const GpioPin ext_pa4_gpio; | extern const GpioPin gpio_display_di; | ||||||
| extern const GpioPin ext_pa6_gpio; | extern const GpioPin gpio_sdcard_cs; | ||||||
| extern const GpioPin ext_pa7_gpio; | extern const GpioPin gpio_nfc_cs; | ||||||
|  | 
 | ||||||
|  | extern const GpioPin gpio_spi_d_miso; | ||||||
|  | extern const GpioPin gpio_spi_d_mosi; | ||||||
|  | extern const GpioPin gpio_spi_d_sck; | ||||||
|  | extern const GpioPin gpio_spi_r_miso; | ||||||
|  | extern const GpioPin gpio_spi_r_mosi; | ||||||
|  | extern const GpioPin gpio_spi_r_sck; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  | |||||||
| @ -16,25 +16,21 @@ bool hal_sd_detect(void) { | |||||||
|     bool result = false; |     bool result = false; | ||||||
| 
 | 
 | ||||||
|     // TODO open record
 |     // TODO open record
 | ||||||
|     const GpioPin* sd_cs_record = &sd_cs_gpio; |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSdCard); | ||||||
| 
 |  | ||||||
|     // TODO: SPI manager
 |  | ||||||
|     api_hal_spi_lock(sd_fast_spi.spi); |  | ||||||
| 
 | 
 | ||||||
|     // configure pin as input
 |     // configure pin as input
 | ||||||
|     gpio_init_ex(sd_cs_record, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); |     gpio_init_ex(device->chip_select, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); | ||||||
|     delay(1); |     delay(1); | ||||||
| 
 | 
 | ||||||
|     // if gpio_read == 0 return true else return false
 |     // if gpio_read == 0 return true else return false
 | ||||||
|     result = !gpio_read(sd_cs_record); |     result = !gpio_read(device->chip_select); | ||||||
| 
 | 
 | ||||||
|     // configure pin back
 |     // configure pin back
 | ||||||
|     gpio_init_ex(sd_cs_record, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); |     gpio_init_ex(device->chip_select, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); | ||||||
|     gpio_write(sd_cs_record, 1); |     gpio_write(device->chip_select, 1); | ||||||
|     delay(1); |     delay(1); | ||||||
| 
 | 
 | ||||||
|     // TODO: SPI manager
 |     api_hal_spi_device_return(device); | ||||||
|     api_hal_spi_unlock(sd_fast_spi.spi); |  | ||||||
| 
 | 
 | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| @ -1,14 +1,89 @@ | |||||||
| #include "main.h" | #include <api-hal-spi-config.h> | ||||||
| #include "api-hal-spi-config.h" | #include <api-hal-resources.h> | ||||||
| 
 | 
 | ||||||
| extern SPI_HandleTypeDef SPI_R; | extern SPI_HandleTypeDef SPI_R; | ||||||
| extern SPI_HandleTypeDef SPI_D; | extern SPI_HandleTypeDef SPI_D; | ||||||
| 
 | 
 | ||||||
|  | const SPI_InitTypeDef api_hal_spi_config_nfc = { | ||||||
|  |     .Mode = SPI_MODE_MASTER, | ||||||
|  |     .Direction = SPI_DIRECTION_2LINES, | ||||||
|  |     .DataSize = SPI_DATASIZE_8BIT, | ||||||
|  |     .CLKPolarity = SPI_POLARITY_LOW, | ||||||
|  |     .CLKPhase = SPI_PHASE_2EDGE, | ||||||
|  |     .NSS = SPI_NSS_SOFT, | ||||||
|  |     .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8, | ||||||
|  |     .FirstBit = SPI_FIRSTBIT_MSB, | ||||||
|  |     .TIMode = SPI_TIMODE_DISABLE, | ||||||
|  |     .CRCCalculation = SPI_CRCCALCULATION_DISABLE, | ||||||
|  |     .CRCPolynomial = 7, | ||||||
|  |     .CRCLength = SPI_CRC_LENGTH_DATASIZE, | ||||||
|  |     .NSSPMode = SPI_NSS_PULSE_DISABLE, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SPI_InitTypeDef api_hal_spi_config_subghz = { | ||||||
|  |     .Mode = SPI_MODE_MASTER, | ||||||
|  |     .Direction = SPI_DIRECTION_2LINES, | ||||||
|  |     .DataSize = SPI_DATASIZE_8BIT, | ||||||
|  |     .CLKPolarity = SPI_POLARITY_LOW, | ||||||
|  |     .CLKPhase = SPI_PHASE_1EDGE, | ||||||
|  |     .NSS = SPI_NSS_SOFT, | ||||||
|  |     .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64, | ||||||
|  |     .FirstBit = SPI_FIRSTBIT_MSB, | ||||||
|  |     .TIMode = SPI_TIMODE_DISABLE, | ||||||
|  |     .CRCCalculation = SPI_CRCCALCULATION_DISABLE, | ||||||
|  |     .CRCPolynomial = 7, | ||||||
|  |     .CRCLength = SPI_CRC_LENGTH_DATASIZE, | ||||||
|  |     .NSSPMode = SPI_NSS_PULSE_DISABLE, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SPI_InitTypeDef api_hal_spi_config_display = { | ||||||
|  |     .Mode = SPI_MODE_MASTER, | ||||||
|  |     .Direction = SPI_DIRECTION_2LINES, | ||||||
|  |     .DataSize = SPI_DATASIZE_8BIT, | ||||||
|  |     .CLKPolarity = SPI_POLARITY_LOW, | ||||||
|  |     .CLKPhase = SPI_PHASE_1EDGE, | ||||||
|  |     .NSS = SPI_NSS_SOFT, | ||||||
|  |     .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16, | ||||||
|  |     .FirstBit = SPI_FIRSTBIT_MSB, | ||||||
|  |     .TIMode = SPI_TIMODE_DISABLE, | ||||||
|  |     .CRCCalculation = SPI_CRCCALCULATION_DISABLE, | ||||||
|  |     .CRCPolynomial = 7, | ||||||
|  |     .CRCLength = SPI_CRC_LENGTH_DATASIZE, | ||||||
|  |     .NSSPMode = SPI_NSS_PULSE_ENABLE, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | osMutexId_t spi_mutex_d = NULL; | ||||||
|  | osMutexId_t spi_mutex_r = NULL; | ||||||
|  | 
 | ||||||
|  | const ApiHalSpiBus spi_r = { | ||||||
|  |     .spi=&SPI_R, | ||||||
|  |     .mutex=&spi_mutex_r, | ||||||
|  |     .miso=&gpio_spi_r_miso, | ||||||
|  |     .mosi=&gpio_spi_r_mosi, | ||||||
|  |     .clk=&gpio_spi_r_sck, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const ApiHalSpiBus spi_d = { | ||||||
|  |     .spi=&SPI_D, | ||||||
|  |     .mutex=&spi_mutex_d, | ||||||
|  |     .miso=&gpio_spi_d_miso, | ||||||
|  |     .mosi=&gpio_spi_d_mosi, | ||||||
|  |     .clk=&gpio_spi_d_sck, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const ApiHalSpiDevice api_hal_spi_devices[ApiHalSpiDeviceIdMax] = { | ||||||
|  |     { .bus=&spi_r, .config=&api_hal_spi_config_subghz, .chip_select=&gpio_subghz_cs, }, | ||||||
|  |     { .bus=&spi_d, .config=&api_hal_spi_config_display, .chip_select=&gpio_display_cs, }, | ||||||
|  |     { .bus=&spi_d, .config=NULL, .chip_select=&gpio_sdcard_cs, }, | ||||||
|  |     { .bus=&spi_r, .config=&api_hal_spi_config_nfc, .chip_select=&gpio_nfc_cs }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * SD Card in fast mode (after init) |  * SD Card in fast mode (after init) | ||||||
|  */ |  */ | ||||||
| const SPIDevice sd_fast_spi = { | const SPIDevice sd_fast_spi = { | ||||||
|     .spi = &SPI_D, |     .bus= &spi_d, | ||||||
|     .config = { |     .config = { | ||||||
|         .Mode = SPI_MODE_MASTER, |         .Mode = SPI_MODE_MASTER, | ||||||
|         .Direction = SPI_DIRECTION_2LINES, |         .Direction = SPI_DIRECTION_2LINES, | ||||||
| @ -29,7 +104,7 @@ const SPIDevice sd_fast_spi = { | |||||||
|  * SD Card in slow mode (before init) |  * SD Card in slow mode (before init) | ||||||
|  */ |  */ | ||||||
| const SPIDevice sd_slow_spi = { | const SPIDevice sd_slow_spi = { | ||||||
|     .spi = &SPI_D, |     .bus= &spi_d, | ||||||
|     .config = { |     .config = { | ||||||
|         .Mode = SPI_MODE_MASTER, |         .Mode = SPI_MODE_MASTER, | ||||||
|         .Direction = SPI_DIRECTION_2LINES, |         .Direction = SPI_DIRECTION_2LINES, | ||||||
| @ -45,24 +120,3 @@ const SPIDevice sd_slow_spi = { | |||||||
|         .CRCLength = SPI_CRC_LENGTH_DATASIZE, |         .CRCLength = SPI_CRC_LENGTH_DATASIZE, | ||||||
|         .NSSPMode = SPI_NSS_PULSE_ENABLE, |         .NSSPMode = SPI_NSS_PULSE_ENABLE, | ||||||
|     }}; |     }}; | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Display |  | ||||||
|  */ |  | ||||||
| const SPIDevice display_spi = { |  | ||||||
|     .spi = &SPI_D, |  | ||||||
|     .config = { |  | ||||||
|         .Mode = SPI_MODE_MASTER, |  | ||||||
|         .Direction = SPI_DIRECTION_2LINES, |  | ||||||
|         .DataSize = SPI_DATASIZE_8BIT, |  | ||||||
|         .CLKPolarity = SPI_POLARITY_LOW, |  | ||||||
|         .CLKPhase = SPI_PHASE_1EDGE, |  | ||||||
|         .NSS = SPI_NSS_SOFT, |  | ||||||
|         .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16, |  | ||||||
|         .FirstBit = SPI_FIRSTBIT_MSB, |  | ||||||
|         .TIMode = SPI_TIMODE_DISABLE, |  | ||||||
|         .CRCCalculation = SPI_CRCCALCULATION_DISABLE, |  | ||||||
|         .CRCPolynomial = 7, |  | ||||||
|         .CRCLength = SPI_CRC_LENGTH_DATASIZE, |  | ||||||
|         .NSSPMode = SPI_NSS_PULSE_ENABLE, |  | ||||||
|     }}; |  | ||||||
|  | |||||||
| @ -1,17 +1,66 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <api-hal-gpio.h> | ||||||
|  | #include <cmsis_os2.h> | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | extern const SPI_InitTypeDef api_hal_spi_config_nfc; | ||||||
|  | extern const SPI_InitTypeDef api_hal_spi_config_subghz; | ||||||
|  | extern const SPI_InitTypeDef api_hal_spi_config_display; | ||||||
|  | 
 | ||||||
|  | /** API HAL SPI BUS handler
 | ||||||
|  |  * Structure content may change at some point | ||||||
|  |  */ | ||||||
| typedef struct { | typedef struct { | ||||||
|     SPI_HandleTypeDef* spi; |     const SPI_HandleTypeDef* spi; | ||||||
|  |     const osMutexId_t* mutex; | ||||||
|  |     const GpioPin* miso; | ||||||
|  |     const GpioPin* mosi; | ||||||
|  |     const GpioPin* clk; | ||||||
|  | } ApiHalSpiBus; | ||||||
|  | 
 | ||||||
|  | /** API HAL SPI Device handler
 | ||||||
|  |  * Structure content may change at some point | ||||||
|  |  */ | ||||||
|  | typedef struct { | ||||||
|  |     const ApiHalSpiBus* bus; | ||||||
|  |     const SPI_InitTypeDef* config; | ||||||
|  |     const GpioPin* chip_select; | ||||||
|  | } ApiHalSpiDevice; | ||||||
|  | 
 | ||||||
|  | /** API HAL SPI Standard Device IDs */ | ||||||
|  | typedef enum { | ||||||
|  |     ApiHalSpiDeviceIdSubGhz,    /** SubGhz: CC1101, non-standard SPI usage */ | ||||||
|  |     ApiHalSpiDeviceIdDisplay,   /** Display: ERC12864, only have MOSI */ | ||||||
|  |     ApiHalSpiDeviceIdSdCard,    /** SDCARD: no default bus config, bus must explicitly be configured */ | ||||||
|  |     ApiHalSpiDeviceIdNfc,       /** NFC: ST25R3916, pretty standard, but RFAL makes it complex */ | ||||||
|  | 
 | ||||||
|  |     ApiHalSpiDeviceIdMax,       /** Service Value, do not use */ | ||||||
|  | } ApiHalSpiDeviceId; | ||||||
|  | 
 | ||||||
|  | /** Api Hal Spi Bus R
 | ||||||
|  |  * CC1101, Nfc | ||||||
|  |  */ | ||||||
|  | extern const ApiHalSpiBus spi_r; | ||||||
|  | 
 | ||||||
|  | /** Api Hal Spi Bus D
 | ||||||
|  |  * Display, SdCard | ||||||
|  |  */ | ||||||
|  | extern const ApiHalSpiBus spi_d; | ||||||
|  | 
 | ||||||
|  | /** Api Hal Spi devices */ | ||||||
|  | extern const ApiHalSpiDevice api_hal_spi_devices[ApiHalSpiDeviceIdMax]; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     const ApiHalSpiBus* bus; | ||||||
|     const SPI_InitTypeDef config; |     const SPI_InitTypeDef config; | ||||||
| } SPIDevice; | } SPIDevice; | ||||||
| 
 | 
 | ||||||
| extern const SPIDevice sd_fast_spi; | extern const SPIDevice sd_fast_spi; | ||||||
| extern const SPIDevice sd_slow_spi; | extern const SPIDevice sd_slow_spi; | ||||||
| extern const SPIDevice display_spi; |  | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,36 +1,167 @@ | |||||||
| #include "api-hal-spi.h" | #include "api-hal-spi.h" | ||||||
| #include <cmsis_os2.h> | #include <api-hal-resources.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | #include <spi.h> | ||||||
|  | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| osMutexId_t spi_mutex_r; |  | ||||||
| osMutexId_t spi_mutex_d; |  | ||||||
| 
 | 
 | ||||||
| extern SPI_HandleTypeDef SPI_R; |  | ||||||
| extern SPI_HandleTypeDef SPI_D; |  | ||||||
| extern void Enable_SPI(SPI_HandleTypeDef* spi); | extern void Enable_SPI(SPI_HandleTypeDef* spi); | ||||||
| 
 | 
 | ||||||
| void api_hal_spi_init() { | void api_hal_spi_init() { | ||||||
|     spi_mutex_r = osMutexNew(NULL); |     // Spi structure is const, but mutex is not
 | ||||||
|     spi_mutex_d = osMutexNew(NULL); |     // Need some hell-ish casting to make it work
 | ||||||
|  |     *(osMutexId_t*)spi_r.mutex = osMutexNew(NULL); | ||||||
|  |     *(osMutexId_t*)spi_d.mutex = osMutexNew(NULL); | ||||||
|  |     // 
 | ||||||
|  |     for (size_t i=0; i<ApiHalSpiDeviceIdMax; ++i) { | ||||||
|  |         hal_gpio_init( | ||||||
|  |             api_hal_spi_devices[i].chip_select, | ||||||
|  |             GpioModeOutputPushPull, | ||||||
|  |             GpioPullNo, | ||||||
|  |             GpioSpeedVeryHigh | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_spi_bus_lock(const ApiHalSpiBus* bus) { | ||||||
|  |     furi_assert(bus); | ||||||
|  |     if (bus->mutex) { | ||||||
|  |         osMutexAcquire(*bus->mutex, osWaitForever); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_spi_bus_unlock(const ApiHalSpiBus* bus) { | ||||||
|  |     furi_assert(bus); | ||||||
|  |     if (bus->mutex) { | ||||||
|  |         osMutexRelease(*bus->mutex); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool api_hal_spi_bus_rx(const ApiHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) { | ||||||
|  |     furi_assert(bus); | ||||||
|  |     furi_assert(buffer); | ||||||
|  |     furi_assert(size > 0); | ||||||
|  | 
 | ||||||
|  |     HAL_StatusTypeDef ret = HAL_SPI_Receive((SPI_HandleTypeDef *)bus->spi, buffer, size, HAL_MAX_DELAY); | ||||||
|  | 
 | ||||||
|  |     return ret == HAL_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool api_hal_spi_bus_tx(const ApiHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) { | ||||||
|  |     furi_assert(bus); | ||||||
|  |     furi_assert(buffer); | ||||||
|  |     furi_assert(size > 0); | ||||||
|  | 
 | ||||||
|  |     HAL_StatusTypeDef ret = HAL_SPI_Transmit((SPI_HandleTypeDef *)bus->spi, buffer, size, HAL_MAX_DELAY); | ||||||
|  | 
 | ||||||
|  |     return ret == HAL_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool api_hal_spi_bus_trx(const ApiHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) { | ||||||
|  |     furi_assert(bus); | ||||||
|  |     furi_assert(tx_buffer); | ||||||
|  |     furi_assert(rx_buffer); | ||||||
|  |     furi_assert(size > 0); | ||||||
|  | 
 | ||||||
|  |     HAL_StatusTypeDef ret = HAL_SPI_TransmitReceive((SPI_HandleTypeDef *)bus->spi, tx_buffer, rx_buffer, size, HAL_MAX_DELAY); | ||||||
|  | 
 | ||||||
|  |     return ret == HAL_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const ApiHalSpiDevice* api_hal_spi_device_get(ApiHalSpiDeviceId device_id) { | ||||||
|  |     furi_assert(device_id < ApiHalSpiDeviceIdMax); | ||||||
|  | 
 | ||||||
|  |     const ApiHalSpiDevice* device = &api_hal_spi_devices[device_id]; | ||||||
|  |     assert(device); | ||||||
|  |     api_hal_spi_bus_lock(device->bus); | ||||||
|  | 
 | ||||||
|  |     if (device->config) { | ||||||
|  |         memcpy((SPI_InitTypeDef*)&device->bus->spi->Init, device->config, sizeof(SPI_InitTypeDef)); | ||||||
|  |         if(HAL_SPI_Init((SPI_HandleTypeDef *)device->bus->spi) != HAL_OK) { | ||||||
|  |             Error_Handler(); | ||||||
|  |         } | ||||||
|  |         Enable_SPI((SPI_HandleTypeDef *)device->bus->spi); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return device; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_spi_device_return(const ApiHalSpiDevice* device) { | ||||||
|  |     api_hal_spi_bus_unlock(device->bus); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool api_hal_spi_device_rx(const ApiHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout) { | ||||||
|  |     furi_assert(device); | ||||||
|  |     furi_assert(buffer); | ||||||
|  |     furi_assert(size > 0); | ||||||
|  | 
 | ||||||
|  |     if (device->chip_select) { | ||||||
|  |         hal_gpio_write(device->chip_select, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool ret = api_hal_spi_bus_rx(device->bus, buffer, size, HAL_MAX_DELAY); | ||||||
|  | 
 | ||||||
|  |     if (device->chip_select) { | ||||||
|  |         hal_gpio_write(device->chip_select, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool api_hal_spi_device_tx(const ApiHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout) { | ||||||
|  |     furi_assert(device); | ||||||
|  |     furi_assert(buffer); | ||||||
|  |     furi_assert(size > 0); | ||||||
|  | 
 | ||||||
|  |     if (device->chip_select) { | ||||||
|  |         hal_gpio_write(device->chip_select, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool ret = api_hal_spi_bus_tx(device->bus, buffer, size, HAL_MAX_DELAY); | ||||||
|  | 
 | ||||||
|  |     if (device->chip_select) { | ||||||
|  |         hal_gpio_write(device->chip_select, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool api_hal_spi_device_trx(const ApiHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) { | ||||||
|  |     furi_assert(device); | ||||||
|  |     furi_assert(tx_buffer); | ||||||
|  |     furi_assert(rx_buffer); | ||||||
|  |     furi_assert(size > 0); | ||||||
|  | 
 | ||||||
|  |     if (device->chip_select) { | ||||||
|  |         hal_gpio_write(device->chip_select, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool ret = api_hal_spi_bus_trx(device->bus, tx_buffer, rx_buffer, size, HAL_MAX_DELAY); | ||||||
|  | 
 | ||||||
|  |     if (device->chip_select) { | ||||||
|  |         hal_gpio_write(device->chip_select, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void api_hal_spi_apply_config(const SPIDevice* device) { | void api_hal_spi_apply_config(const SPIDevice* device) { | ||||||
|     osKernelLock(); |     osKernelLock(); | ||||||
| 
 | 
 | ||||||
|     memcpy(&device->spi->Init, &device->config, sizeof(SPI_InitTypeDef)); |     memcpy((SPI_InitTypeDef*)&device->bus->spi->Init, &device->config, sizeof(SPI_InitTypeDef)); | ||||||
| 
 | 
 | ||||||
|     if(HAL_SPI_Init(device->spi) != HAL_OK) { |     if(HAL_SPI_Init((SPI_HandleTypeDef*)device->bus->spi) != HAL_OK) { | ||||||
|         Error_Handler(); |         Error_Handler(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Enable_SPI(device->spi); |     Enable_SPI((SPI_HandleTypeDef*)device->bus->spi); | ||||||
| 
 | 
 | ||||||
|     osKernelUnlock(); |     osKernelUnlock(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool api_hal_spi_config_are_actual(const SPIDevice* device) { | bool api_hal_spi_config_are_actual(const SPIDevice* device) { | ||||||
|     return (memcmp(&device->config, &device->spi->Init, sizeof(SPI_InitTypeDef)) == 0); |     return (memcmp(&device->config, &device->bus->spi->Init, sizeof(SPI_InitTypeDef)) == 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void api_hal_spi_config_device(const SPIDevice* device) { | void api_hal_spi_config_device(const SPIDevice* device) { | ||||||
| @ -39,31 +170,11 @@ void api_hal_spi_config_device(const SPIDevice* device) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void api_hal_spi_lock(SPI_HandleTypeDef* spi) { |  | ||||||
|     if(spi == &SPI_D) { |  | ||||||
|         osMutexAcquire(spi_mutex_d, osWaitForever); |  | ||||||
|     } else if(spi == &SPI_R) { |  | ||||||
|         osMutexAcquire(spi_mutex_r, osWaitForever); |  | ||||||
|     } else { |  | ||||||
|         Error_Handler(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void api_hal_spi_unlock(SPI_HandleTypeDef* spi) { |  | ||||||
|     if(spi == &SPI_D) { |  | ||||||
|         osMutexRelease(spi_mutex_d); |  | ||||||
|     } else if(spi == &SPI_R) { |  | ||||||
|         osMutexRelease(spi_mutex_r); |  | ||||||
|     } else { |  | ||||||
|         Error_Handler(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void api_hal_spi_lock_device(const SPIDevice* device) { | void api_hal_spi_lock_device(const SPIDevice* device) { | ||||||
|     api_hal_spi_lock(device->spi); |     api_hal_spi_bus_lock(device->bus); | ||||||
|     api_hal_spi_config_device(device); |     api_hal_spi_config_device(device); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void api_hal_spi_unlock_device(const SPIDevice* device) { | void api_hal_spi_unlock_device(const SPIDevice* device) { | ||||||
|     api_hal_spi_unlock(device->spi); |     api_hal_spi_bus_unlock(device->bus); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "main.h" | #include "main.h" | ||||||
| #include "api-hal-spi-config.h" | #include "api-hal-spi-config.h" | ||||||
|  | #include <api-hal-gpio.h> | ||||||
|  | #include <stdbool.h> | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| @ -11,15 +13,83 @@ extern "C" { | |||||||
|  */ |  */ | ||||||
| void api_hal_spi_init(); | void api_hal_spi_init(); | ||||||
| 
 | 
 | ||||||
| /**
 | /* Bus Level API */ | ||||||
|  * Lock SPI bus |  | ||||||
|  */ |  | ||||||
| void api_hal_spi_lock(SPI_HandleTypeDef* spi); |  | ||||||
| 
 | 
 | ||||||
| /**
 | /** Lock SPI bus
 | ||||||
|  * Unlock SPI bus |  * Takes bus mutex, if used | ||||||
|  */ |  */ | ||||||
| void api_hal_spi_unlock(SPI_HandleTypeDef* spi); | void api_hal_spi_bus_lock(const ApiHalSpiBus* bus); | ||||||
|  | 
 | ||||||
|  | /** Unlock SPI bus
 | ||||||
|  |  * Releases BUS mutex, if used | ||||||
|  |  */ | ||||||
|  | void api_hal_spi_bus_unlock(const ApiHalSpiBus* bus); | ||||||
|  | 
 | ||||||
|  | /** SPI Receive
 | ||||||
|  |  * @param bus - spi bus handler | ||||||
|  |  * @param buffer - receive buffer | ||||||
|  |  * @param size - transaction size | ||||||
|  |  * @param timeout - bus operation timeout in ms | ||||||
|  |  */ | ||||||
|  | bool api_hal_spi_bus_rx(const ApiHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout); | ||||||
|  | 
 | ||||||
|  | /** SPI Transmit
 | ||||||
|  |  * @param bus - spi bus handler | ||||||
|  |  * @param buffer - transmit buffer | ||||||
|  |  * @param size - transaction size | ||||||
|  |  * @param timeout - bus operation timeout in ms | ||||||
|  |  */ | ||||||
|  | bool api_hal_spi_bus_tx(const ApiHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout); | ||||||
|  | 
 | ||||||
|  | /** SPI Transmit and Receive
 | ||||||
|  |  * @param bus - spi bus handlere | ||||||
|  |  * @param tx_buffer - device handle | ||||||
|  |  * @param rx_buffer - device handle | ||||||
|  |  * @param size - transaction size | ||||||
|  |  * @param timeout - bus operation timeout in ms | ||||||
|  |  */ | ||||||
|  | bool api_hal_spi_bus_trx(const ApiHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout); | ||||||
|  | 
 | ||||||
|  | /* Device Level API */ | ||||||
|  | 
 | ||||||
|  | /** Get Device handle
 | ||||||
|  |  * And lock access to the corresponding SPI BUS | ||||||
|  |  * @param device_id - device identifier | ||||||
|  |  * @return device handle | ||||||
|  |  */ | ||||||
|  | const ApiHalSpiDevice* api_hal_spi_device_get(ApiHalSpiDeviceId device_id); | ||||||
|  | 
 | ||||||
|  | /** Return Device handle
 | ||||||
|  |  * And unlock access to the corresponding SPI BUS | ||||||
|  |  * @param device - device handle | ||||||
|  |  */ | ||||||
|  | void api_hal_spi_device_return(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** SPI Recieve
 | ||||||
|  |  * @param device - device handle | ||||||
|  |  * @param buffer - receive buffer | ||||||
|  |  * @param size - transaction size | ||||||
|  |  * @param timeout - bus operation timeout in ms | ||||||
|  |  */ | ||||||
|  | bool api_hal_spi_device_rx(const ApiHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout); | ||||||
|  | 
 | ||||||
|  | /** SPI Transmit
 | ||||||
|  |  * @param device - device handle | ||||||
|  |  * @param buffer - transmit buffer | ||||||
|  |  * @param size - transaction size | ||||||
|  |  * @param timeout - bus operation timeout in ms | ||||||
|  |  */ | ||||||
|  | bool api_hal_spi_device_tx(const ApiHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout); | ||||||
|  | 
 | ||||||
|  | /** SPI Transmit and Receive
 | ||||||
|  |  * @param device - device handle | ||||||
|  |  * @param tx_buffer - device handle | ||||||
|  |  * @param rx_buffer - device handle | ||||||
|  |  * @param size - transaction size | ||||||
|  |  * @param timeout - bus operation timeout in ms | ||||||
|  |  */ | ||||||
|  | bool api_hal_spi_device_trx(const ApiHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Lock SPI device bus and apply config if needed |  * Lock SPI device bus and apply config if needed | ||||||
|  | |||||||
| @ -1,5 +1,11 @@ | |||||||
| #include "api-hal-subghz.h" | #include "api-hal-subghz.h" | ||||||
|  | #include <api-hal-spi.h> | ||||||
|  | #include <cc1101.h> | ||||||
| 
 | 
 | ||||||
| void api_hal_rf_band_set(RfBand band) { | void api_hal_subghz_init() { | ||||||
|      |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
| } |     cc1101_init(device); | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_band_set(RfBand band) {} | ||||||
| @ -8,4 +8,5 @@ void api_hal_init() { | |||||||
|     api_hal_power_init(); |     api_hal_power_init(); | ||||||
|     api_hal_light_init(); |     api_hal_light_init(); | ||||||
|     api_hal_vibro_init(); |     api_hal_vibro_init(); | ||||||
|  |     api_hal_subghz_init(); | ||||||
| } | } | ||||||
| @ -1,155 +1,103 @@ | |||||||
| /* USER CODE BEGIN Header */ | #pragma once | ||||||
| /**
 |  | ||||||
|   ****************************************************************************** |  | ||||||
|   * @file           : main.h |  | ||||||
|   * @brief          : Header for main.c file. |  | ||||||
|   *                   This file contains the common defines of the application. |  | ||||||
|   ****************************************************************************** |  | ||||||
|   * @attention |  | ||||||
|   * |  | ||||||
|   * <h2><center>© Copyright (c) 2020 STMicroelectronics. |  | ||||||
|   * All rights reserved.</center></h2> |  | ||||||
|   * |  | ||||||
|   * This software component is licensed by ST under Ultimate Liberty license |  | ||||||
|   * SLA0044, the "License"; You may not use this file except in compliance with |  | ||||||
|   * the License. You may obtain a copy of the License at: |  | ||||||
|   *                             www.st.com/SLA0044 |  | ||||||
|   * |  | ||||||
|   ****************************************************************************** |  | ||||||
|   */ |  | ||||||
| /* USER CODE END Header */ |  | ||||||
| 
 |  | ||||||
| /* Define to prevent recursive inclusion -------------------------------------*/ |  | ||||||
| #ifndef __MAIN_H |  | ||||||
| #define __MAIN_H |  | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /* Includes ------------------------------------------------------------------*/ |  | ||||||
| #include "stm32wbxx_hal.h" | #include "stm32wbxx_hal.h" | ||||||
| 
 | 
 | ||||||
| /* Private includes ----------------------------------------------------------*/ |  | ||||||
| /* USER CODE BEGIN Includes */ |  | ||||||
| 
 |  | ||||||
| /* USER CODE END Includes */ |  | ||||||
| 
 |  | ||||||
| /* Exported types ------------------------------------------------------------*/ |  | ||||||
| /* USER CODE BEGIN ET */ |  | ||||||
| 
 |  | ||||||
| /* USER CODE END ET */ |  | ||||||
| 
 |  | ||||||
| /* Exported constants --------------------------------------------------------*/ |  | ||||||
| /* USER CODE BEGIN EC */ |  | ||||||
| 
 |  | ||||||
| /* USER CODE END EC */ |  | ||||||
| 
 |  | ||||||
| /* Exported macro ------------------------------------------------------------*/ |  | ||||||
| /* USER CODE BEGIN EM */ |  | ||||||
| 
 |  | ||||||
| /* USER CODE END EM */ |  | ||||||
| 
 |  | ||||||
| /* Exported functions prototypes ---------------------------------------------*/ |  | ||||||
| void Error_Handler(void); | void Error_Handler(void); | ||||||
| 
 | 
 | ||||||
| /* USER CODE BEGIN EFP */ |  | ||||||
| 
 |  | ||||||
| /* USER CODE END EFP */ |  | ||||||
| 
 |  | ||||||
| /* Private defines -----------------------------------------------------------*/ |  | ||||||
| #define BUTTON_BACK_Pin GPIO_PIN_13 |  | ||||||
| #define BUTTON_BACK_GPIO_Port GPIOC |  | ||||||
| #define BUTTON_BACK_EXTI_IRQn EXTI15_10_IRQn | #define BUTTON_BACK_EXTI_IRQn EXTI15_10_IRQn | ||||||
| #define QUARTZ_32MHZ_IN_Pin GPIO_PIN_14 | #define BUTTON_BACK_GPIO_Port GPIOC | ||||||
| #define QUARTZ_32MHZ_IN_GPIO_Port GPIOC | #define BUTTON_BACK_Pin GPIO_PIN_13 | ||||||
| #define QUARTZ_32MHZ_OUT_Pin GPIO_PIN_15 |  | ||||||
| #define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC |  | ||||||
| #define BUTTON_OK_Pin GPIO_PIN_3 |  | ||||||
| #define BUTTON_OK_GPIO_Port GPIOH |  | ||||||
| #define BUTTON_OK_EXTI_IRQn EXTI3_IRQn |  | ||||||
| #define SPEAKER_Pin GPIO_PIN_8 |  | ||||||
| #define SPEAKER_GPIO_Port GPIOB |  | ||||||
| #define IR_TX_Pin GPIO_PIN_9 |  | ||||||
| #define IR_TX_GPIO_Port GPIOB |  | ||||||
| #define PC0_Pin GPIO_PIN_0 |  | ||||||
| #define PC0_GPIO_Port GPIOC |  | ||||||
| #define PC1_Pin GPIO_PIN_1 |  | ||||||
| #define PC1_GPIO_Port GPIOC |  | ||||||
| #define SPI_D_MISO_Pin GPIO_PIN_2 |  | ||||||
| #define SPI_D_MISO_GPIO_Port GPIOC |  | ||||||
| #define PC3_Pin GPIO_PIN_3 |  | ||||||
| #define PC3_GPIO_Port GPIOC |  | ||||||
| #define IR_RX_Pin GPIO_PIN_0 |  | ||||||
| #define IR_RX_GPIO_Port GPIOA |  | ||||||
| #define RF_SW_0_Pin GPIO_PIN_1 |  | ||||||
| #define RF_SW_0_GPIO_Port GPIOA |  | ||||||
| #define RF_SW_1_Pin GPIO_PIN_2 |  | ||||||
| #define RF_SW_1_GPIO_Port GPIOA |  | ||||||
| #define PERIPH_POWER_Pin GPIO_PIN_3 |  | ||||||
| #define PERIPH_POWER_GPIO_Port GPIOA |  | ||||||
| #define PA4_Pin GPIO_PIN_4 |  | ||||||
| #define PA4_GPIO_Port GPIOA |  | ||||||
| #define SPI_R_SCK_Pin GPIO_PIN_5 |  | ||||||
| #define SPI_R_SCK_GPIO_Port GPIOA |  | ||||||
| #define PA6_Pin GPIO_PIN_6 |  | ||||||
| #define PA6_GPIO_Port GPIOA |  | ||||||
| #define PA7_Pin GPIO_PIN_7 |  | ||||||
| #define PA7_GPIO_Port GPIOA |  | ||||||
| #define RFID_PULL_Pin GPIO_PIN_8 |  | ||||||
| #define RFID_PULL_GPIO_Port GPIOA |  | ||||||
| #define RFID_PULL_EXTI_IRQn EXTI9_5_IRQn |  | ||||||
| #define CC1101_G0_Pin GPIO_PIN_4 |  | ||||||
| #define CC1101_G0_GPIO_Port GPIOC |  | ||||||
| #define RFID_RF_IN_Pin GPIO_PIN_5 |  | ||||||
| #define RFID_RF_IN_GPIO_Port GPIOC |  | ||||||
| #define PB2_Pin GPIO_PIN_2 |  | ||||||
| #define PB2_GPIO_Port GPIOB |  | ||||||
| #define BUTTON_UP_Pin GPIO_PIN_10 |  | ||||||
| #define BUTTON_UP_GPIO_Port GPIOB |  | ||||||
| #define BUTTON_UP_EXTI_IRQn EXTI15_10_IRQn |  | ||||||
| #define BUTTON_LEFT_Pin GPIO_PIN_11 |  | ||||||
| #define BUTTON_LEFT_GPIO_Port GPIOB |  | ||||||
| #define BUTTON_LEFT_EXTI_IRQn EXTI15_10_IRQn |  | ||||||
| #define DISPLAY_RST_Pin GPIO_PIN_0 |  | ||||||
| #define DISPLAY_RST_GPIO_Port GPIOB |  | ||||||
| #define BUTTON_DOWN_Pin GPIO_PIN_1 |  | ||||||
| #define BUTTON_DOWN_GPIO_Port GPIOB |  | ||||||
| #define BUTTON_DOWN_EXTI_IRQn EXTI1_IRQn | #define BUTTON_DOWN_EXTI_IRQn EXTI1_IRQn | ||||||
| #define NFC_CS_Pin GPIO_PIN_4 | #define BUTTON_DOWN_GPIO_Port GPIOB | ||||||
| #define NFC_CS_GPIO_Port GPIOE | #define BUTTON_DOWN_Pin GPIO_PIN_1 | ||||||
| #define BUTTON_RIGHT_Pin GPIO_PIN_12 | #define BUTTON_LEFT_EXTI_IRQn EXTI15_10_IRQn | ||||||
| #define BUTTON_RIGHT_GPIO_Port GPIOB | #define BUTTON_LEFT_GPIO_Port GPIOB | ||||||
|  | #define BUTTON_LEFT_Pin GPIO_PIN_11 | ||||||
|  | #define BUTTON_OK_EXTI_IRQn EXTI3_IRQn | ||||||
|  | #define BUTTON_OK_GPIO_Port GPIOH | ||||||
|  | #define BUTTON_OK_Pin GPIO_PIN_3 | ||||||
| #define BUTTON_RIGHT_EXTI_IRQn EXTI15_10_IRQn | #define BUTTON_RIGHT_EXTI_IRQn EXTI15_10_IRQn | ||||||
| #define RFID_OUT_Pin GPIO_PIN_13 | #define BUTTON_RIGHT_GPIO_Port GPIOB | ||||||
| #define RFID_OUT_GPIO_Port GPIOB | #define BUTTON_RIGHT_Pin GPIO_PIN_12 | ||||||
| #define iBTN_Pin GPIO_PIN_14 | #define BUTTON_UP_EXTI_IRQn EXTI15_10_IRQn | ||||||
| #define iBTN_GPIO_Port GPIOB | #define BUTTON_UP_GPIO_Port GPIOB | ||||||
| #define SPI_D_MOSI_Pin GPIO_PIN_15 | #define BUTTON_UP_Pin GPIO_PIN_10 | ||||||
| #define SPI_D_MOSI_GPIO_Port GPIOB |  | ||||||
| #define DISPLAY_DI_Pin GPIO_PIN_6 |  | ||||||
| #define DISPLAY_DI_GPIO_Port GPIOC |  | ||||||
| #define SD_CD_Pin GPIO_PIN_15 |  | ||||||
| #define SD_CD_GPIO_Port GPIOA |  | ||||||
| #define VIBRO_Pin GPIO_PIN_10 |  | ||||||
| #define VIBRO_GPIO_Port GPIOC |  | ||||||
| #define DISPLAY_CS_Pin GPIO_PIN_11 |  | ||||||
| #define DISPLAY_CS_GPIO_Port GPIOC |  | ||||||
| #define SD_CS_Pin GPIO_PIN_12 |  | ||||||
| #define SD_CS_GPIO_Port GPIOC |  | ||||||
| #define CC1101_CS_Pin GPIO_PIN_0 |  | ||||||
| #define CC1101_CS_GPIO_Port GPIOD | #define CC1101_CS_GPIO_Port GPIOD | ||||||
| #define SPI_D_SCK_Pin GPIO_PIN_1 | #define CC1101_CS_Pin GPIO_PIN_0 | ||||||
| #define SPI_D_SCK_GPIO_Port GPIOD | #define CC1101_G0_GPIO_Port GPIOC | ||||||
| #define PB3_Pin GPIO_PIN_3 | #define CC1101_G0_Pin GPIO_PIN_4 | ||||||
|  | #define DISPLAY_CS_GPIO_Port GPIOC | ||||||
|  | #define DISPLAY_CS_Pin GPIO_PIN_11 | ||||||
|  | #define DISPLAY_DI_GPIO_Port GPIOC | ||||||
|  | #define DISPLAY_DI_Pin GPIO_PIN_6 | ||||||
|  | #define DISPLAY_RST_GPIO_Port GPIOB | ||||||
|  | #define DISPLAY_RST_Pin GPIO_PIN_0 | ||||||
|  | #define IR_RX_GPIO_Port GPIOA | ||||||
|  | #define IR_RX_Pin GPIO_PIN_0 | ||||||
|  | #define IR_TX_GPIO_Port GPIOB | ||||||
|  | #define IR_TX_Pin GPIO_PIN_9 | ||||||
|  | #define NFC_CS_GPIO_Port GPIOE | ||||||
|  | #define NFC_CS_Pin GPIO_PIN_4 | ||||||
|  | #define PA4_GPIO_Port GPIOA | ||||||
|  | #define PA4_Pin GPIO_PIN_4 | ||||||
|  | #define PA6_GPIO_Port GPIOA | ||||||
|  | #define PA6_Pin GPIO_PIN_6 | ||||||
|  | #define PA7_GPIO_Port GPIOA | ||||||
|  | #define PA7_Pin GPIO_PIN_7 | ||||||
|  | #define PB2_GPIO_Port GPIOB | ||||||
|  | #define PB2_Pin GPIO_PIN_2 | ||||||
| #define PB3_GPIO_Port GPIOB | #define PB3_GPIO_Port GPIOB | ||||||
| #define SPI_R_MISO_Pin GPIO_PIN_4 | #define PB3_Pin GPIO_PIN_3 | ||||||
| #define SPI_R_MISO_GPIO_Port GPIOB | #define PC0_GPIO_Port GPIOC | ||||||
| #define SPI_R_MOSI_Pin GPIO_PIN_5 | #define PC0_Pin GPIO_PIN_0 | ||||||
| #define SPI_R_MOSI_GPIO_Port GPIOB | #define PC1_GPIO_Port GPIOC | ||||||
| /* USER CODE BEGIN Private defines */ | #define PC1_Pin GPIO_PIN_1 | ||||||
|  | #define PC3_GPIO_Port GPIOC | ||||||
|  | #define PC3_Pin GPIO_PIN_3 | ||||||
|  | #define PERIPH_POWER_GPIO_Port GPIOA | ||||||
|  | #define PERIPH_POWER_Pin GPIO_PIN_3 | ||||||
|  | #define QUARTZ_32MHZ_IN_GPIO_Port GPIOC | ||||||
|  | #define QUARTZ_32MHZ_IN_Pin GPIO_PIN_14 | ||||||
|  | #define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC | ||||||
|  | #define QUARTZ_32MHZ_OUT_Pin GPIO_PIN_15 | ||||||
|  | #define RFID_OUT_GPIO_Port GPIOB | ||||||
|  | #define RFID_OUT_Pin GPIO_PIN_13 | ||||||
|  | #define RFID_PULL_EXTI_IRQn EXTI9_5_IRQn | ||||||
|  | #define RFID_PULL_GPIO_Port GPIOA | ||||||
|  | #define RFID_PULL_Pin GPIO_PIN_8 | ||||||
|  | #define RFID_RF_IN_GPIO_Port GPIOC | ||||||
|  | #define RFID_RF_IN_Pin GPIO_PIN_5 | ||||||
|  | #define RF_SW_0_GPIO_Port GPIOA | ||||||
|  | #define RF_SW_0_Pin GPIO_PIN_1 | ||||||
|  | #define RF_SW_1_GPIO_Port GPIOA | ||||||
|  | #define RF_SW_1_Pin GPIO_PIN_2 | ||||||
|  | #define SD_CD_GPIO_Port GPIOA | ||||||
|  | #define SD_CD_Pin GPIO_PIN_15 | ||||||
|  | #define SD_CS_GPIO_Port GPIOC | ||||||
|  | #define SD_CS_Pin GPIO_PIN_12 | ||||||
|  | #define SPEAKER_GPIO_Port GPIOB | ||||||
|  | #define SPEAKER_Pin GPIO_PIN_8 | ||||||
|  | #define VIBRO_GPIO_Port GPIOC | ||||||
|  | #define VIBRO_Pin GPIO_PIN_10 | ||||||
|  | #define iBTN_GPIO_Port GPIOB | ||||||
|  | #define iBTN_Pin GPIO_PIN_14 | ||||||
| 
 | 
 | ||||||
| #define MISO_PIN GpioPin{.port = SPI_R_MISO_GPIO_Port, .pin = SPI_R_MISO_Pin} | #define SPI_D_MISO_GPIO_Port GPIOC | ||||||
|  | #define SPI_D_MISO_Pin GPIO_PIN_2 | ||||||
|  | #define SPI_D_MOSI_GPIO_Port GPIOB | ||||||
|  | #define SPI_D_MOSI_Pin GPIO_PIN_15 | ||||||
|  | #define SPI_D_SCK_GPIO_Port GPIOD | ||||||
|  | #define SPI_D_SCK_Pin GPIO_PIN_1 | ||||||
|  | #define SPI_R_MISO_GPIO_Port GPIOB | ||||||
|  | #define SPI_R_MISO_Pin GPIO_PIN_4 | ||||||
|  | #define SPI_R_MOSI_GPIO_Port GPIOB | ||||||
|  | #define SPI_R_MOSI_Pin GPIO_PIN_5 | ||||||
|  | #define SPI_R_SCK_GPIO_Port GPIOA | ||||||
|  | #define SPI_R_SCK_Pin GPIO_PIN_5 | ||||||
| 
 | 
 | ||||||
| #define SPI_R hspi1 | #define SPI_R hspi1 | ||||||
| #define SPI_D hspi2 | #define SPI_D hspi2 | ||||||
| @ -182,12 +130,6 @@ extern TIM_HandleTypeDef htim16; | |||||||
| #define NFC_IRQ_Pin RFID_PULL_Pin | #define NFC_IRQ_Pin RFID_PULL_Pin | ||||||
| #define NFC_IRQ_GPIO_Port RFID_PULL_GPIO_Port | #define NFC_IRQ_GPIO_Port RFID_PULL_GPIO_Port | ||||||
| 
 | 
 | ||||||
| /* USER CODE END Private defines */ |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 |  | ||||||
| #endif /* __MAIN_H */ |  | ||||||
| 
 |  | ||||||
| /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ |  | ||||||
|  | |||||||
| @ -23,5 +23,6 @@ void delay_us(float microseconds) { | |||||||
| void delay(float milliseconds) { | void delay(float milliseconds) { | ||||||
|     uint32_t ticks = milliseconds / (1000.0f / osKernelGetTickFreq()); |     uint32_t ticks = milliseconds / (1000.0f / osKernelGetTickFreq()); | ||||||
|     osStatus_t result = osDelay(ticks); |     osStatus_t result = osDelay(ticks); | ||||||
|  |     (void)result; | ||||||
|     assert(result == osOK); |     assert(result == osOK); | ||||||
| } | } | ||||||
| @ -20,11 +20,6 @@ void hal_gpio_init( | |||||||
|     HAL_GPIO_Init(gpio->port, &GPIO_InitStruct); |     HAL_GPIO_Init(gpio->port, &GPIO_InitStruct); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void enable_cc1101_irq() { |  | ||||||
|     HAL_NVIC_SetPriority(EXTI4_IRQn, 5, 0); |  | ||||||
|     HAL_NVIC_EnableIRQ(EXTI4_IRQn); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| extern COMP_HandleTypeDef hcomp1; | extern COMP_HandleTypeDef hcomp1; | ||||||
| 
 | 
 | ||||||
| bool get_rfid_in_level() { | bool get_rfid_in_level() { | ||||||
|  | |||||||
| @ -24,6 +24,12 @@ typedef enum { | |||||||
|     GpioModeEventRiseFall = GPIO_MODE_EVT_RISING_FALLING, |     GpioModeEventRiseFall = GPIO_MODE_EVT_RISING_FALLING, | ||||||
| } GpioMode; | } GpioMode; | ||||||
| 
 | 
 | ||||||
|  | typedef enum { | ||||||
|  |     GpioPullNo = GPIO_NOPULL, | ||||||
|  |     GpioPullUp = GPIO_PULLUP, | ||||||
|  |     GpioPullDown = GPIO_PULLDOWN, | ||||||
|  | } GpioPull; | ||||||
|  | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     GpioSpeedLow = GPIO_SPEED_FREQ_LOW, |     GpioSpeedLow = GPIO_SPEED_FREQ_LOW, | ||||||
|     GpioSpeedMedium = GPIO_SPEED_FREQ_MEDIUM, |     GpioSpeedMedium = GPIO_SPEED_FREQ_MEDIUM, | ||||||
| @ -31,12 +37,6 @@ typedef enum { | |||||||
|     GpioSpeedVeryHigh = GPIO_SPEED_FREQ_VERY_HIGH, |     GpioSpeedVeryHigh = GPIO_SPEED_FREQ_VERY_HIGH, | ||||||
| } GpioSpeed; | } GpioSpeed; | ||||||
| 
 | 
 | ||||||
| typedef enum { |  | ||||||
|     GpioPullNo = GPIO_NOPULL, |  | ||||||
|     GpioPullUp = GPIO_PULLUP, |  | ||||||
|     GpioPullDown = GPIO_PULLDOWN, |  | ||||||
| } GpioPull; |  | ||||||
| 
 |  | ||||||
| typedef struct { | typedef struct { | ||||||
|     GPIO_TypeDef* port; |     GPIO_TypeDef* port; | ||||||
|     uint16_t pin; |     uint16_t pin; | ||||||
|  | |||||||
| @ -28,3 +28,17 @@ const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin); | |||||||
| const GpioPin vibro_gpio = {VIBRO_GPIO_Port, VIBRO_Pin}; | const GpioPin vibro_gpio = {VIBRO_GPIO_Port, VIBRO_Pin}; | ||||||
| const GpioPin ibutton_gpio = {iBTN_GPIO_Port, iBTN_Pin}; | const GpioPin ibutton_gpio = {iBTN_GPIO_Port, iBTN_Pin}; | ||||||
| const GpioPin cc1101_g0_gpio = {CC1101_G0_GPIO_Port, CC1101_G0_Pin}; | const GpioPin cc1101_g0_gpio = {CC1101_G0_GPIO_Port, CC1101_G0_Pin}; | ||||||
|  | 
 | ||||||
|  | const GpioPin gpio_subghz_cs = { .port=CC1101_CS_GPIO_Port, .pin=CC1101_CS_Pin }; | ||||||
|  | const GpioPin gpio_display_cs = { .port=DISPLAY_CS_GPIO_Port, .pin=DISPLAY_CS_Pin }; | ||||||
|  | const GpioPin gpio_display_rst = { .port=DISPLAY_RST_GPIO_Port, .pin=DISPLAY_RST_Pin }; | ||||||
|  | const GpioPin gpio_display_di = { .port=DISPLAY_DI_GPIO_Port, .pin=DISPLAY_DI_Pin }; | ||||||
|  | const GpioPin gpio_sdcard_cs = { .port=SD_CS_GPIO_Port, .pin=SD_CS_Pin }; | ||||||
|  | const GpioPin gpio_nfc_cs = { .port=NFC_CS_GPIO_Port, .pin=NFC_CS_Pin }; | ||||||
|  | 
 | ||||||
|  | const GpioPin gpio_spi_d_miso = { .port=SPI_D_MISO_GPIO_Port, .pin=SPI_D_MISO_Pin }; | ||||||
|  | const GpioPin gpio_spi_d_mosi = { .port=SPI_D_MOSI_GPIO_Port, .pin=SPI_D_MOSI_Pin }; | ||||||
|  | const GpioPin gpio_spi_d_sck = { .port=SPI_D_SCK_GPIO_Port, .pin=SPI_D_SCK_Pin }; | ||||||
|  | const GpioPin gpio_spi_r_miso = { .port=SPI_R_MISO_GPIO_Port, .pin=SPI_R_MISO_Pin }; | ||||||
|  | const GpioPin gpio_spi_r_mosi = { .port=SPI_R_MOSI_GPIO_Port, .pin=SPI_R_MOSI_Pin }; | ||||||
|  | const GpioPin gpio_spi_r_sck = { .port=SPI_R_SCK_GPIO_Port, .pin=SPI_R_SCK_Pin }; | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ extern "C" { | |||||||
| #define POWER_I2C_SDA_GPIO_Port GPIOA | #define POWER_I2C_SDA_GPIO_Port GPIOA | ||||||
| 
 | 
 | ||||||
| #define POWER_I2C I2C1 | #define POWER_I2C I2C1 | ||||||
| /* Timing register value is computed with the STM32CubeMX Tool,
 | /** Timing register value is computed with the STM32CubeMX Tool,
 | ||||||
|   * Fast Mode @100kHz with I2CCLK = 64 MHz, |   * Fast Mode @100kHz with I2CCLK = 64 MHz, | ||||||
|   * rise time = 0ns, fall time = 0ns |   * rise time = 0ns, fall time = 0ns | ||||||
|   */ |   */ | ||||||
| @ -57,6 +57,24 @@ extern const GpioPin vibro_gpio; | |||||||
| extern const GpioPin ibutton_gpio; | extern const GpioPin ibutton_gpio; | ||||||
| extern const GpioPin cc1101_g0_gpio; | extern const GpioPin cc1101_g0_gpio; | ||||||
| 
 | 
 | ||||||
|  | extern const GpioPin gpio_subghz_cs; | ||||||
|  | extern const GpioPin gpio_display_cs; | ||||||
|  | 
 | ||||||
|  | extern const GpioPin gpio_subghz_cs; | ||||||
|  | extern const GpioPin gpio_display_cs; | ||||||
|  | extern const GpioPin gpio_display_rst; | ||||||
|  | extern const GpioPin gpio_display_di; | ||||||
|  | extern const GpioPin gpio_sdcard_cs; | ||||||
|  | extern const GpioPin gpio_nfc_cs; | ||||||
|  | 
 | ||||||
|  | extern const GpioPin gpio_spi_d_miso; | ||||||
|  | extern const GpioPin gpio_spi_d_mosi; | ||||||
|  | extern const GpioPin gpio_spi_d_sck; | ||||||
|  | extern const GpioPin gpio_spi_r_miso; | ||||||
|  | extern const GpioPin gpio_spi_r_mosi; | ||||||
|  | extern const GpioPin gpio_spi_r_sck; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -1,14 +1,89 @@ | |||||||
| #include "main.h" | #include <api-hal-spi-config.h> | ||||||
| #include "api-hal-spi-config.h" | #include <api-hal-resources.h> | ||||||
| 
 | 
 | ||||||
| extern SPI_HandleTypeDef SPI_R; | extern SPI_HandleTypeDef SPI_R; | ||||||
| extern SPI_HandleTypeDef SPI_D; | extern SPI_HandleTypeDef SPI_D; | ||||||
| 
 | 
 | ||||||
|  | const SPI_InitTypeDef api_hal_spi_config_nfc = { | ||||||
|  |     .Mode = SPI_MODE_MASTER, | ||||||
|  |     .Direction = SPI_DIRECTION_2LINES, | ||||||
|  |     .DataSize = SPI_DATASIZE_8BIT, | ||||||
|  |     .CLKPolarity = SPI_POLARITY_LOW, | ||||||
|  |     .CLKPhase = SPI_PHASE_2EDGE, | ||||||
|  |     .NSS = SPI_NSS_SOFT, | ||||||
|  |     .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8, | ||||||
|  |     .FirstBit = SPI_FIRSTBIT_MSB, | ||||||
|  |     .TIMode = SPI_TIMODE_DISABLE, | ||||||
|  |     .CRCCalculation = SPI_CRCCALCULATION_DISABLE, | ||||||
|  |     .CRCPolynomial = 7, | ||||||
|  |     .CRCLength = SPI_CRC_LENGTH_DATASIZE, | ||||||
|  |     .NSSPMode = SPI_NSS_PULSE_DISABLE, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SPI_InitTypeDef api_hal_spi_config_subghz = { | ||||||
|  |     .Mode = SPI_MODE_MASTER, | ||||||
|  |     .Direction = SPI_DIRECTION_2LINES, | ||||||
|  |     .DataSize = SPI_DATASIZE_8BIT, | ||||||
|  |     .CLKPolarity = SPI_POLARITY_LOW, | ||||||
|  |     .CLKPhase = SPI_PHASE_1EDGE, | ||||||
|  |     .NSS = SPI_NSS_SOFT, | ||||||
|  |     .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8, | ||||||
|  |     .FirstBit = SPI_FIRSTBIT_MSB, | ||||||
|  |     .TIMode = SPI_TIMODE_DISABLE, | ||||||
|  |     .CRCCalculation = SPI_CRCCALCULATION_DISABLE, | ||||||
|  |     .CRCPolynomial = 7, | ||||||
|  |     .CRCLength = SPI_CRC_LENGTH_DATASIZE, | ||||||
|  |     .NSSPMode = SPI_NSS_PULSE_DISABLE, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SPI_InitTypeDef api_hal_spi_config_display = { | ||||||
|  |     .Mode = SPI_MODE_MASTER, | ||||||
|  |     .Direction = SPI_DIRECTION_2LINES, | ||||||
|  |     .DataSize = SPI_DATASIZE_8BIT, | ||||||
|  |     .CLKPolarity = SPI_POLARITY_LOW, | ||||||
|  |     .CLKPhase = SPI_PHASE_1EDGE, | ||||||
|  |     .NSS = SPI_NSS_SOFT, | ||||||
|  |     .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16, | ||||||
|  |     .FirstBit = SPI_FIRSTBIT_MSB, | ||||||
|  |     .TIMode = SPI_TIMODE_DISABLE, | ||||||
|  |     .CRCCalculation = SPI_CRCCALCULATION_DISABLE, | ||||||
|  |     .CRCPolynomial = 7, | ||||||
|  |     .CRCLength = SPI_CRC_LENGTH_DATASIZE, | ||||||
|  |     .NSSPMode = SPI_NSS_PULSE_ENABLE, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | osMutexId_t spi_mutex_d = NULL; | ||||||
|  | osMutexId_t spi_mutex_r = NULL; | ||||||
|  | 
 | ||||||
|  | const ApiHalSpiBus spi_r = { | ||||||
|  |     .spi=&SPI_R, | ||||||
|  |     .mutex=&spi_mutex_r, | ||||||
|  |     .miso=&gpio_spi_r_miso, | ||||||
|  |     .mosi=&gpio_spi_r_mosi, | ||||||
|  |     .clk=&gpio_spi_r_sck, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const ApiHalSpiBus spi_d = { | ||||||
|  |     .spi=&SPI_D, | ||||||
|  |     .mutex=&spi_mutex_d, | ||||||
|  |     .miso=&gpio_spi_d_miso, | ||||||
|  |     .mosi=&gpio_spi_d_mosi, | ||||||
|  |     .clk=&gpio_spi_d_sck, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const ApiHalSpiDevice api_hal_spi_devices[ApiHalSpiDeviceIdMax] = { | ||||||
|  |     { .bus=&spi_r, .config=&api_hal_spi_config_subghz, .chip_select=&gpio_subghz_cs, }, | ||||||
|  |     { .bus=&spi_d, .config=&api_hal_spi_config_display, .chip_select=&gpio_display_cs, }, | ||||||
|  |     { .bus=&spi_d, .config=NULL, .chip_select=&gpio_sdcard_cs, }, | ||||||
|  |     { .bus=&spi_r, .config=&api_hal_spi_config_nfc, .chip_select=&gpio_nfc_cs }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * SD Card in fast mode (after init) |  * SD Card in fast mode (after init) | ||||||
|  */ |  */ | ||||||
| const SPIDevice sd_fast_spi = { | const SPIDevice sd_fast_spi = { | ||||||
|     .spi = &SPI_D, |     .bus= &spi_d, | ||||||
|     .config = { |     .config = { | ||||||
|         .Mode = SPI_MODE_MASTER, |         .Mode = SPI_MODE_MASTER, | ||||||
|         .Direction = SPI_DIRECTION_2LINES, |         .Direction = SPI_DIRECTION_2LINES, | ||||||
| @ -29,7 +104,7 @@ const SPIDevice sd_fast_spi = { | |||||||
|  * SD Card in slow mode (before init) |  * SD Card in slow mode (before init) | ||||||
|  */ |  */ | ||||||
| const SPIDevice sd_slow_spi = { | const SPIDevice sd_slow_spi = { | ||||||
|     .spi = &SPI_D, |     .bus= &spi_d, | ||||||
|     .config = { |     .config = { | ||||||
|         .Mode = SPI_MODE_MASTER, |         .Mode = SPI_MODE_MASTER, | ||||||
|         .Direction = SPI_DIRECTION_2LINES, |         .Direction = SPI_DIRECTION_2LINES, | ||||||
| @ -45,24 +120,3 @@ const SPIDevice sd_slow_spi = { | |||||||
|         .CRCLength = SPI_CRC_LENGTH_DATASIZE, |         .CRCLength = SPI_CRC_LENGTH_DATASIZE, | ||||||
|         .NSSPMode = SPI_NSS_PULSE_ENABLE, |         .NSSPMode = SPI_NSS_PULSE_ENABLE, | ||||||
|     }}; |     }}; | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Display |  | ||||||
|  */ |  | ||||||
| const SPIDevice display_spi = { |  | ||||||
|     .spi = &SPI_D, |  | ||||||
|     .config = { |  | ||||||
|         .Mode = SPI_MODE_MASTER, |  | ||||||
|         .Direction = SPI_DIRECTION_2LINES, |  | ||||||
|         .DataSize = SPI_DATASIZE_8BIT, |  | ||||||
|         .CLKPolarity = SPI_POLARITY_LOW, |  | ||||||
|         .CLKPhase = SPI_PHASE_1EDGE, |  | ||||||
|         .NSS = SPI_NSS_SOFT, |  | ||||||
|         .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16, |  | ||||||
|         .FirstBit = SPI_FIRSTBIT_MSB, |  | ||||||
|         .TIMode = SPI_TIMODE_DISABLE, |  | ||||||
|         .CRCCalculation = SPI_CRCCALCULATION_DISABLE, |  | ||||||
|         .CRCPolynomial = 7, |  | ||||||
|         .CRCLength = SPI_CRC_LENGTH_DATASIZE, |  | ||||||
|         .NSSPMode = SPI_NSS_PULSE_ENABLE, |  | ||||||
|     }}; |  | ||||||
|  | |||||||
| @ -1,17 +1,66 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <api-hal-gpio.h> | ||||||
|  | #include <cmsis_os2.h> | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | extern const SPI_InitTypeDef api_hal_spi_config_nfc; | ||||||
|  | extern const SPI_InitTypeDef api_hal_spi_config_subghz; | ||||||
|  | extern const SPI_InitTypeDef api_hal_spi_config_display; | ||||||
|  | 
 | ||||||
|  | /** API HAL SPI BUS handler
 | ||||||
|  |  * Structure content may change at some point | ||||||
|  |  */ | ||||||
| typedef struct { | typedef struct { | ||||||
|     SPI_HandleTypeDef* spi; |     const SPI_HandleTypeDef* spi; | ||||||
|  |     const osMutexId_t* mutex; | ||||||
|  |     const GpioPin* miso; | ||||||
|  |     const GpioPin* mosi; | ||||||
|  |     const GpioPin* clk; | ||||||
|  | } ApiHalSpiBus; | ||||||
|  | 
 | ||||||
|  | /** API HAL SPI Device handler
 | ||||||
|  |  * Structure content may change at some point | ||||||
|  |  */ | ||||||
|  | typedef struct { | ||||||
|  |     const ApiHalSpiBus* bus; | ||||||
|  |     const SPI_InitTypeDef* config; | ||||||
|  |     const GpioPin* chip_select; | ||||||
|  | } ApiHalSpiDevice; | ||||||
|  | 
 | ||||||
|  | /** API HAL SPI Standard Device IDs */ | ||||||
|  | typedef enum { | ||||||
|  |     ApiHalSpiDeviceIdSubGhz,    /** SubGhz: CC1101, non-standard SPI usage */ | ||||||
|  |     ApiHalSpiDeviceIdDisplay,   /** Display: ERC12864, only have MOSI */ | ||||||
|  |     ApiHalSpiDeviceIdSdCard,    /** SDCARD: no default bus config, bus must explicitly be configured */ | ||||||
|  |     ApiHalSpiDeviceIdNfc,       /** NFC: ST25R3916, pretty standard, but RFAL makes it complex */ | ||||||
|  | 
 | ||||||
|  |     ApiHalSpiDeviceIdMax,       /** Service Value, do not use */ | ||||||
|  | } ApiHalSpiDeviceId; | ||||||
|  | 
 | ||||||
|  | /** Api Hal Spi Bus R
 | ||||||
|  |  * CC1101, Nfc | ||||||
|  |  */ | ||||||
|  | extern const ApiHalSpiBus spi_r; | ||||||
|  | 
 | ||||||
|  | /** Api Hal Spi Bus D
 | ||||||
|  |  * Display, SdCard | ||||||
|  |  */ | ||||||
|  | extern const ApiHalSpiBus spi_d; | ||||||
|  | 
 | ||||||
|  | /** Api Hal Spi devices */ | ||||||
|  | extern const ApiHalSpiDevice api_hal_spi_devices[ApiHalSpiDeviceIdMax]; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     const ApiHalSpiBus* bus; | ||||||
|     const SPI_InitTypeDef config; |     const SPI_InitTypeDef config; | ||||||
| } SPIDevice; | } SPIDevice; | ||||||
| 
 | 
 | ||||||
| extern const SPIDevice sd_fast_spi; | extern const SPIDevice sd_fast_spi; | ||||||
| extern const SPIDevice sd_slow_spi; | extern const SPIDevice sd_slow_spi; | ||||||
| extern const SPIDevice display_spi; |  | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,36 +1,167 @@ | |||||||
| #include "api-hal-spi.h" | #include "api-hal-spi.h" | ||||||
| #include <cmsis_os2.h> | #include <api-hal-resources.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | #include <spi.h> | ||||||
|  | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| osMutexId_t spi_mutex_r; |  | ||||||
| osMutexId_t spi_mutex_d; |  | ||||||
| 
 | 
 | ||||||
| extern SPI_HandleTypeDef SPI_R; |  | ||||||
| extern SPI_HandleTypeDef SPI_D; |  | ||||||
| extern void Enable_SPI(SPI_HandleTypeDef* spi); | extern void Enable_SPI(SPI_HandleTypeDef* spi); | ||||||
| 
 | 
 | ||||||
| void api_hal_spi_init() { | void api_hal_spi_init() { | ||||||
|     spi_mutex_r = osMutexNew(NULL); |     // Spi structure is const, but mutex is not
 | ||||||
|     spi_mutex_d = osMutexNew(NULL); |     // Need some hell-ish casting to make it work
 | ||||||
|  |     *(osMutexId_t*)spi_r.mutex = osMutexNew(NULL); | ||||||
|  |     *(osMutexId_t*)spi_d.mutex = osMutexNew(NULL); | ||||||
|  |     // 
 | ||||||
|  |     for (size_t i=0; i<ApiHalSpiDeviceIdMax; ++i) { | ||||||
|  |         hal_gpio_init( | ||||||
|  |             api_hal_spi_devices[i].chip_select, | ||||||
|  |             GpioModeOutputPushPull, | ||||||
|  |             GpioPullNo, | ||||||
|  |             GpioSpeedVeryHigh | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_spi_bus_lock(const ApiHalSpiBus* bus) { | ||||||
|  |     furi_assert(bus); | ||||||
|  |     if (bus->mutex) { | ||||||
|  |         osMutexAcquire(*bus->mutex, osWaitForever); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_spi_bus_unlock(const ApiHalSpiBus* bus) { | ||||||
|  |     furi_assert(bus); | ||||||
|  |     if (bus->mutex) { | ||||||
|  |         osMutexRelease(*bus->mutex); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool api_hal_spi_bus_rx(const ApiHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) { | ||||||
|  |     furi_assert(bus); | ||||||
|  |     furi_assert(buffer); | ||||||
|  |     furi_assert(size > 0); | ||||||
|  | 
 | ||||||
|  |     HAL_StatusTypeDef ret = HAL_SPI_Receive((SPI_HandleTypeDef *)bus->spi, buffer, size, HAL_MAX_DELAY); | ||||||
|  | 
 | ||||||
|  |     return ret == HAL_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool api_hal_spi_bus_tx(const ApiHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) { | ||||||
|  |     furi_assert(bus); | ||||||
|  |     furi_assert(buffer); | ||||||
|  |     furi_assert(size > 0); | ||||||
|  | 
 | ||||||
|  |     HAL_StatusTypeDef ret = HAL_SPI_Transmit((SPI_HandleTypeDef *)bus->spi, buffer, size, HAL_MAX_DELAY); | ||||||
|  | 
 | ||||||
|  |     return ret == HAL_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool api_hal_spi_bus_trx(const ApiHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) { | ||||||
|  |     furi_assert(bus); | ||||||
|  |     furi_assert(tx_buffer); | ||||||
|  |     furi_assert(rx_buffer); | ||||||
|  |     furi_assert(size > 0); | ||||||
|  | 
 | ||||||
|  |     HAL_StatusTypeDef ret = HAL_SPI_TransmitReceive((SPI_HandleTypeDef *)bus->spi, tx_buffer, rx_buffer, size, HAL_MAX_DELAY); | ||||||
|  | 
 | ||||||
|  |     return ret == HAL_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const ApiHalSpiDevice* api_hal_spi_device_get(ApiHalSpiDeviceId device_id) { | ||||||
|  |     furi_assert(device_id < ApiHalSpiDeviceIdMax); | ||||||
|  | 
 | ||||||
|  |     const ApiHalSpiDevice* device = &api_hal_spi_devices[device_id]; | ||||||
|  |     assert(device); | ||||||
|  |     api_hal_spi_bus_lock(device->bus); | ||||||
|  | 
 | ||||||
|  |     if (device->config) { | ||||||
|  |         memcpy((SPI_InitTypeDef*)&device->bus->spi->Init, device->config, sizeof(SPI_InitTypeDef)); | ||||||
|  |         if(HAL_SPI_Init((SPI_HandleTypeDef *)device->bus->spi) != HAL_OK) { | ||||||
|  |             Error_Handler(); | ||||||
|  |         } | ||||||
|  |         Enable_SPI((SPI_HandleTypeDef *)device->bus->spi); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return device; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_spi_device_return(const ApiHalSpiDevice* device) { | ||||||
|  |     api_hal_spi_bus_unlock(device->bus); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool api_hal_spi_device_rx(const ApiHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout) { | ||||||
|  |     furi_assert(device); | ||||||
|  |     furi_assert(buffer); | ||||||
|  |     furi_assert(size > 0); | ||||||
|  | 
 | ||||||
|  |     if (device->chip_select) { | ||||||
|  |         hal_gpio_write(device->chip_select, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool ret = api_hal_spi_bus_rx(device->bus, buffer, size, HAL_MAX_DELAY); | ||||||
|  | 
 | ||||||
|  |     if (device->chip_select) { | ||||||
|  |         hal_gpio_write(device->chip_select, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool api_hal_spi_device_tx(const ApiHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout) { | ||||||
|  |     furi_assert(device); | ||||||
|  |     furi_assert(buffer); | ||||||
|  |     furi_assert(size > 0); | ||||||
|  | 
 | ||||||
|  |     if (device->chip_select) { | ||||||
|  |         hal_gpio_write(device->chip_select, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool ret = api_hal_spi_bus_tx(device->bus, buffer, size, HAL_MAX_DELAY); | ||||||
|  | 
 | ||||||
|  |     if (device->chip_select) { | ||||||
|  |         hal_gpio_write(device->chip_select, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool api_hal_spi_device_trx(const ApiHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) { | ||||||
|  |     furi_assert(device); | ||||||
|  |     furi_assert(tx_buffer); | ||||||
|  |     furi_assert(rx_buffer); | ||||||
|  |     furi_assert(size > 0); | ||||||
|  | 
 | ||||||
|  |     if (device->chip_select) { | ||||||
|  |         hal_gpio_write(device->chip_select, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool ret = api_hal_spi_bus_trx(device->bus, tx_buffer, rx_buffer, size, HAL_MAX_DELAY); | ||||||
|  | 
 | ||||||
|  |     if (device->chip_select) { | ||||||
|  |         hal_gpio_write(device->chip_select, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void api_hal_spi_apply_config(const SPIDevice* device) { | void api_hal_spi_apply_config(const SPIDevice* device) { | ||||||
|     osKernelLock(); |     osKernelLock(); | ||||||
| 
 | 
 | ||||||
|     memcpy(&device->spi->Init, &device->config, sizeof(SPI_InitTypeDef)); |     memcpy((SPI_InitTypeDef*)&device->bus->spi->Init, &device->config, sizeof(SPI_InitTypeDef)); | ||||||
| 
 | 
 | ||||||
|     if(HAL_SPI_Init(device->spi) != HAL_OK) { |     if(HAL_SPI_Init((SPI_HandleTypeDef*)device->bus->spi) != HAL_OK) { | ||||||
|         Error_Handler(); |         Error_Handler(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Enable_SPI(device->spi); |     Enable_SPI((SPI_HandleTypeDef*)device->bus->spi); | ||||||
| 
 | 
 | ||||||
|     osKernelUnlock(); |     osKernelUnlock(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool api_hal_spi_config_are_actual(const SPIDevice* device) { | bool api_hal_spi_config_are_actual(const SPIDevice* device) { | ||||||
|     return (memcmp(&device->config, &device->spi->Init, sizeof(SPI_InitTypeDef)) == 0); |     return (memcmp(&device->config, &device->bus->spi->Init, sizeof(SPI_InitTypeDef)) == 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void api_hal_spi_config_device(const SPIDevice* device) { | void api_hal_spi_config_device(const SPIDevice* device) { | ||||||
| @ -39,31 +170,11 @@ void api_hal_spi_config_device(const SPIDevice* device) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void api_hal_spi_lock(SPI_HandleTypeDef* spi) { |  | ||||||
|     if(spi == &SPI_D) { |  | ||||||
|         osMutexAcquire(spi_mutex_d, osWaitForever); |  | ||||||
|     } else if(spi == &SPI_R) { |  | ||||||
|         osMutexAcquire(spi_mutex_r, osWaitForever); |  | ||||||
|     } else { |  | ||||||
|         Error_Handler(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void api_hal_spi_unlock(SPI_HandleTypeDef* spi) { |  | ||||||
|     if(spi == &SPI_D) { |  | ||||||
|         osMutexRelease(spi_mutex_d); |  | ||||||
|     } else if(spi == &SPI_R) { |  | ||||||
|         osMutexRelease(spi_mutex_r); |  | ||||||
|     } else { |  | ||||||
|         Error_Handler(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void api_hal_spi_lock_device(const SPIDevice* device) { | void api_hal_spi_lock_device(const SPIDevice* device) { | ||||||
|     api_hal_spi_lock(device->spi); |     api_hal_spi_bus_lock(device->bus); | ||||||
|     api_hal_spi_config_device(device); |     api_hal_spi_config_device(device); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void api_hal_spi_unlock_device(const SPIDevice* device) { | void api_hal_spi_unlock_device(const SPIDevice* device) { | ||||||
|     api_hal_spi_unlock(device->spi); |     api_hal_spi_bus_unlock(device->bus); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "main.h" | #include "main.h" | ||||||
| #include "api-hal-spi-config.h" | #include "api-hal-spi-config.h" | ||||||
|  | #include <api-hal-gpio.h> | ||||||
|  | #include <stdbool.h> | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| @ -11,15 +13,83 @@ extern "C" { | |||||||
|  */ |  */ | ||||||
| void api_hal_spi_init(); | void api_hal_spi_init(); | ||||||
| 
 | 
 | ||||||
| /**
 | /* Bus Level API */ | ||||||
|  * Lock SPI bus |  | ||||||
|  */ |  | ||||||
| void api_hal_spi_lock(SPI_HandleTypeDef* spi); |  | ||||||
| 
 | 
 | ||||||
| /**
 | /** Lock SPI bus
 | ||||||
|  * Unlock SPI bus |  * Takes bus mutex, if used | ||||||
|  */ |  */ | ||||||
| void api_hal_spi_unlock(SPI_HandleTypeDef* spi); | void api_hal_spi_bus_lock(const ApiHalSpiBus* bus); | ||||||
|  | 
 | ||||||
|  | /** Unlock SPI bus
 | ||||||
|  |  * Releases BUS mutex, if used | ||||||
|  |  */ | ||||||
|  | void api_hal_spi_bus_unlock(const ApiHalSpiBus* bus); | ||||||
|  | 
 | ||||||
|  | /** SPI Receive
 | ||||||
|  |  * @param bus - spi bus handler | ||||||
|  |  * @param buffer - receive buffer | ||||||
|  |  * @param size - transaction size | ||||||
|  |  * @param timeout - bus operation timeout in ms | ||||||
|  |  */ | ||||||
|  | bool api_hal_spi_bus_rx(const ApiHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout); | ||||||
|  | 
 | ||||||
|  | /** SPI Transmit
 | ||||||
|  |  * @param bus - spi bus handler | ||||||
|  |  * @param buffer - transmit buffer | ||||||
|  |  * @param size - transaction size | ||||||
|  |  * @param timeout - bus operation timeout in ms | ||||||
|  |  */ | ||||||
|  | bool api_hal_spi_bus_tx(const ApiHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout); | ||||||
|  | 
 | ||||||
|  | /** SPI Transmit and Receive
 | ||||||
|  |  * @param bus - spi bus handlere | ||||||
|  |  * @param tx_buffer - device handle | ||||||
|  |  * @param rx_buffer - device handle | ||||||
|  |  * @param size - transaction size | ||||||
|  |  * @param timeout - bus operation timeout in ms | ||||||
|  |  */ | ||||||
|  | bool api_hal_spi_bus_trx(const ApiHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout); | ||||||
|  | 
 | ||||||
|  | /* Device Level API */ | ||||||
|  | 
 | ||||||
|  | /** Get Device handle
 | ||||||
|  |  * And lock access to the corresponding SPI BUS | ||||||
|  |  * @param device_id - device identifier | ||||||
|  |  * @return device handle | ||||||
|  |  */ | ||||||
|  | const ApiHalSpiDevice* api_hal_spi_device_get(ApiHalSpiDeviceId device_id); | ||||||
|  | 
 | ||||||
|  | /** Return Device handle
 | ||||||
|  |  * And unlock access to the corresponding SPI BUS | ||||||
|  |  * @param device - device handle | ||||||
|  |  */ | ||||||
|  | void api_hal_spi_device_return(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** SPI Recieve
 | ||||||
|  |  * @param device - device handle | ||||||
|  |  * @param buffer - receive buffer | ||||||
|  |  * @param size - transaction size | ||||||
|  |  * @param timeout - bus operation timeout in ms | ||||||
|  |  */ | ||||||
|  | bool api_hal_spi_device_rx(const ApiHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout); | ||||||
|  | 
 | ||||||
|  | /** SPI Transmit
 | ||||||
|  |  * @param device - device handle | ||||||
|  |  * @param buffer - transmit buffer | ||||||
|  |  * @param size - transaction size | ||||||
|  |  * @param timeout - bus operation timeout in ms | ||||||
|  |  */ | ||||||
|  | bool api_hal_spi_device_tx(const ApiHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout); | ||||||
|  | 
 | ||||||
|  | /** SPI Transmit and Receive
 | ||||||
|  |  * @param device - device handle | ||||||
|  |  * @param tx_buffer - device handle | ||||||
|  |  * @param rx_buffer - device handle | ||||||
|  |  * @param size - transaction size | ||||||
|  |  * @param timeout - bus operation timeout in ms | ||||||
|  |  */ | ||||||
|  | bool api_hal_spi_device_trx(const ApiHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Lock SPI device bus and apply config if needed |  * Lock SPI device bus and apply config if needed | ||||||
|  | |||||||
| @ -1,19 +1,181 @@ | |||||||
| #include "api-hal-subghz.h" | #include "api-hal-subghz.h" | ||||||
| #include <stm32wbxx_ll_gpio.h> | #include <stm32wbxx_ll_gpio.h> | ||||||
|  | #include <api-hal-gpio.h> | ||||||
|  | #include <api-hal-spi.h> | ||||||
|  | #include <cc1101.h> | ||||||
|  | #include <stdio.h> | ||||||
| #include "main.h" | #include "main.h" | ||||||
| 
 | 
 | ||||||
| void api_hal_rf_band_set(RfBand band) { | static const uint8_t api_hal_subghz_preset_ook_async_regs[][2] = { | ||||||
|     if (band == RfBand1) { |     /* Base setting */ | ||||||
|         LL_GPIO_ResetOutputPin(RF_SW_0_GPIO_Port, RF_SW_0_Pin); |     { CC1101_IOCFG0,    0x0D }, // GD0 as async serial data output/input
 | ||||||
|         LL_GPIO_SetOutputPin(RF_SW_1_GPIO_Port, RF_SW_1_Pin); |     { CC1101_FSCTRL1,   0x06 }, // Set IF 26m/2^10*2=2.2MHz
 | ||||||
|     } else if (band == RfBand2) { |     { CC1101_MCSM0,     0x18 }, // Autocalibrate on idle to TRX, ~150us OSC guard time
 | ||||||
|         LL_GPIO_SetOutputPin(RF_SW_0_GPIO_Port, RF_SW_0_Pin); |     /* Async OOK Specific things  */ | ||||||
|         LL_GPIO_ResetOutputPin(RF_SW_1_GPIO_Port, RF_SW_1_Pin); |     { CC1101_MDMCFG2,   0x30 }, // ASK/OOK, No preamble/sync
 | ||||||
|     } else if (band == RfBand3) { |     { CC1101_PKTCTRL0,  0x32 }, // Async, no CRC, Infinite
 | ||||||
|         LL_GPIO_SetOutputPin(RF_SW_0_GPIO_Port, RF_SW_0_Pin); |     { CC1101_FREND0,    0x01 }, // OOK/ASK PATABLE
 | ||||||
|         LL_GPIO_SetOutputPin(RF_SW_1_GPIO_Port, RF_SW_1_Pin); |     /* End  */ | ||||||
|     } else if (band == RfBandIsolation) { |     { 0, 0 }, | ||||||
|         LL_GPIO_ResetOutputPin(RF_SW_0_GPIO_Port, RF_SW_0_Pin); | }; | ||||||
|         LL_GPIO_ResetOutputPin(RF_SW_1_GPIO_Port, RF_SW_1_Pin); | 
 | ||||||
|  | static const uint8_t api_hal_subghz_preset_ook_async_patable[8] = { | ||||||
|  |     0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const uint8_t api_hal_subghz_preset_2fsk_packet_regs[][2] = { | ||||||
|  |     /* Base setting */ | ||||||
|  |     { CC1101_IOCFG0,    0x06 }, // GD0 as async serial data output/input
 | ||||||
|  |     { CC1101_FSCTRL1,   0x06 }, // Set IF 26m/2^10*2=2.2MHz
 | ||||||
|  |     { CC1101_MCSM0,     0x18 }, // Autocalibrate on idle to TRX, ~150us OSC guard time
 | ||||||
|  |     /* End */ | ||||||
|  |     { 0, 0 }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const uint8_t api_hal_subghz_preset_2fsk_packet_patable[8] = { | ||||||
|  |     0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_init() { | ||||||
|  |     LL_GPIO_SetPinMode(RF_SW_0_GPIO_Port, RF_SW_0_Pin, LL_GPIO_MODE_OUTPUT); | ||||||
|  |     LL_GPIO_SetPinSpeed(RF_SW_0_GPIO_Port, RF_SW_0_Pin, LL_GPIO_SPEED_FREQ_LOW); | ||||||
|  |     LL_GPIO_SetPinOutputType(RF_SW_0_GPIO_Port, RF_SW_0_Pin, LL_GPIO_OUTPUT_PUSHPULL); | ||||||
|  |     LL_GPIO_SetPinMode(RF_SW_1_GPIO_Port, RF_SW_1_Pin, LL_GPIO_MODE_OUTPUT); | ||||||
|  |     LL_GPIO_SetPinSpeed(RF_SW_1_GPIO_Port, RF_SW_1_Pin, LL_GPIO_SPEED_FREQ_LOW); | ||||||
|  |     LL_GPIO_SetPinOutputType(RF_SW_1_GPIO_Port, RF_SW_1_Pin, LL_GPIO_OUTPUT_PUSHPULL); | ||||||
|  | 
 | ||||||
|  |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
|  |     // Reset and shutdown
 | ||||||
|  |     cc1101_reset(device); | ||||||
|  |     cc1101_write_reg(device, CC1101_IOCFG0, 0x2E); // High impedance 3-state
 | ||||||
|  |     cc1101_shutdown(device); | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_dump_state() { | ||||||
|  |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
|  |     printf( | ||||||
|  |         "[api_hal_subghz] cc1101 chip %d, version %d\r\n", | ||||||
|  |         cc1101_get_partnumber(device), | ||||||
|  |         cc1101_get_version(device) | ||||||
|  |     ); | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_load_preset(ApiHalSubGhzPreset preset) { | ||||||
|  |     if(preset == ApiHalSubGhzPresetOokAsync) { | ||||||
|  |         api_hal_subghz_load_registers(api_hal_subghz_preset_ook_async_regs); | ||||||
|  |         api_hal_subghz_load_patable(api_hal_subghz_preset_ook_async_patable); | ||||||
|  |     } else if(preset == ApiHalSubGhzPreset2FskPacket) { | ||||||
|  |         api_hal_subghz_load_registers(api_hal_subghz_preset_2fsk_packet_regs); | ||||||
|  |         api_hal_subghz_load_patable(api_hal_subghz_preset_2fsk_packet_patable); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_load_registers(const uint8_t data[][2]) { | ||||||
|  |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
|  |     cc1101_reset(device); | ||||||
|  |     uint32_t i = 0; | ||||||
|  |     while (data[i][0]) { | ||||||
|  |         cc1101_write_reg(device, data[i][0], data[i][1]); | ||||||
|  |         i++; | ||||||
|  |     } | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_load_patable(const uint8_t data[8]) { | ||||||
|  |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
|  |     cc1101_set_pa_table(device, data); | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_write_packet(const uint8_t* data, uint8_t size) { | ||||||
|  |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
|  |     cc1101_flush_tx(device); | ||||||
|  |     cc1101_write_fifo(device, data, size); | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_read_packet(uint8_t* data, uint8_t size) { | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_shutdown() { | ||||||
|  |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
|  |     // Reset and shutdown
 | ||||||
|  |     cc1101_shutdown(device); | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_reset() { | ||||||
|  |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
|  |     cc1101_reset(device); | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_idle() { | ||||||
|  |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
|  |     cc1101_switch_to_idle(device); | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_rx() { | ||||||
|  |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
|  |     cc1101_switch_to_rx(device); | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_tx() { | ||||||
|  |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
|  |     cc1101_switch_to_tx(device); | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float api_hal_subghz_get_rssi() { | ||||||
|  |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
|  |     int32_t rssi_dec = cc1101_get_rssi(device); | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t api_hal_subghz_set_frequency(uint32_t value) { | ||||||
|  |     const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSubGhz); | ||||||
|  | 
 | ||||||
|  |     // Compensate rounding
 | ||||||
|  |     if (value % cc1101_get_frequency_step(device) > (cc1101_get_frequency_step(device) / 2)) { | ||||||
|  |         value += cc1101_get_frequency_step(device); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     uint32_t real_frequency = cc1101_set_frequency(device, value); | ||||||
|  |     cc1101_calibrate(device); | ||||||
|  | 
 | ||||||
|  |     api_hal_spi_device_return(device); | ||||||
|  | 
 | ||||||
|  |     return real_frequency; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_subghz_set_path(ApiHalSubGhzPath path) { | ||||||
|  |     if (path == ApiHalSubGhzPath1) { | ||||||
|  |         LL_GPIO_ResetOutputPin(RF_SW_0_GPIO_Port, RF_SW_0_Pin); | ||||||
|  |         LL_GPIO_SetOutputPin(RF_SW_1_GPIO_Port, RF_SW_1_Pin); | ||||||
|  |     } else if (path == ApiHalSubGhzPath2) { | ||||||
|  |         LL_GPIO_SetOutputPin(RF_SW_0_GPIO_Port, RF_SW_0_Pin); | ||||||
|  |         LL_GPIO_ResetOutputPin(RF_SW_1_GPIO_Port, RF_SW_1_Pin); | ||||||
|  |     } else if (path == ApiHalSubGhzPath3) { | ||||||
|  |         LL_GPIO_SetOutputPin(RF_SW_0_GPIO_Port, RF_SW_0_Pin); | ||||||
|  |         LL_GPIO_SetOutputPin(RF_SW_1_GPIO_Port, RF_SW_1_Pin); | ||||||
|  |     } else if (path == ApiHalSubGhzPathIsolate) { | ||||||
|  |         LL_GPIO_ResetOutputPin(RF_SW_0_GPIO_Port, RF_SW_0_Pin); | ||||||
|  |         LL_GPIO_ResetOutputPin(RF_SW_1_GPIO_Port, RF_SW_1_Pin); | ||||||
|  |     } else { | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,4 +8,5 @@ void api_hal_init() { | |||||||
|     api_hal_power_init(); |     api_hal_power_init(); | ||||||
|     api_hal_light_init(); |     api_hal_light_init(); | ||||||
|     api_hal_vibro_init(); |     api_hal_vibro_init(); | ||||||
|  |     api_hal_subghz_init(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ | |||||||
| static osThreadAttr_t platform_irq_thread_attr; | static osThreadAttr_t platform_irq_thread_attr; | ||||||
| static volatile osThreadId_t platform_irq_thread_id = NULL; | static volatile osThreadId_t platform_irq_thread_id = NULL; | ||||||
| static volatile PlatformIrqCallback platform_irq_callback = NULL; | static volatile PlatformIrqCallback platform_irq_callback = NULL; | ||||||
|  | static ApiHalSpiDevice* platform_st25r3916 = NULL; | ||||||
| 
 | 
 | ||||||
| void nfc_isr(void* _pin, void* _ctx) { | void nfc_isr(void* _pin, void* _ctx) { | ||||||
|     uint32_t pin = (uint32_t)_pin; |     uint32_t pin = (uint32_t)_pin; | ||||||
| @ -36,27 +37,30 @@ void platformSetIrqCallback(PlatformIrqCallback callback) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t len) { | HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t len) { | ||||||
|     HAL_StatusTypeDef ret; |     bool ret = false; | ||||||
|     if (txBuf && rxBuf) { |     if (txBuf && rxBuf) { | ||||||
|         ret = HAL_SPI_TransmitReceive(&SPI_R, (uint8_t*)txBuf, rxBuf, len, HAL_MAX_DELAY); |         ret = api_hal_spi_bus_trx(platform_st25r3916->bus, (uint8_t*)txBuf, rxBuf, len, 1000); | ||||||
|     } else if (txBuf) { |     } else if (txBuf) { | ||||||
|         ret = HAL_SPI_Transmit(&SPI_R, (uint8_t*)txBuf, len, HAL_MAX_DELAY); |         ret = api_hal_spi_bus_tx(platform_st25r3916->bus, (uint8_t*)txBuf, len, 1000); | ||||||
|     } else if (rxBuf) { |     } else if (rxBuf) { | ||||||
|         ret = HAL_SPI_Receive(&SPI_R, (uint8_t*)rxBuf, len, HAL_MAX_DELAY); |         ret = api_hal_spi_bus_rx(platform_st25r3916->bus, (uint8_t*)rxBuf, len, 1000); | ||||||
|     } |     } | ||||||
|      | 
 | ||||||
|     if(ret != HAL_OK) { |     if(!ret) { | ||||||
|         asm("bkpt 1"); |         asm("bkpt 1"); | ||||||
|         exit(255); |         return HAL_ERROR; | ||||||
|  |     } else { | ||||||
|  |         return HAL_OK; | ||||||
|     } |     } | ||||||
|     return ret; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void platformProtectST25RComm() { | void platformProtectST25RComm() { | ||||||
|     api_hal_spi_lock(&SPI_R); |     furi_assert(platform_st25r3916 == NULL); | ||||||
|     NFC_SPI_Reconfigure(); |     platform_st25r3916 = (ApiHalSpiDevice*)api_hal_spi_device_get(ApiHalSpiDeviceIdNfc); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void platformUnprotectST25RComm() { | void platformUnprotectST25RComm() { | ||||||
|     api_hal_spi_unlock(&SPI_R); |     furi_assert(platform_st25r3916); | ||||||
|  |     api_hal_spi_device_return(platform_st25r3916); | ||||||
|  |     platform_st25r3916 = NULL; | ||||||
| } | } | ||||||
|  | |||||||
| @ -58,40 +58,40 @@ void platformUnprotectST25RComm(); | |||||||
| 
 | 
 | ||||||
| #define platformIrqST25RSetCallback( cb )           platformSetIrqCallback(cb) | #define platformIrqST25RSetCallback( cb )           platformSetIrqCallback(cb) | ||||||
| 
 | 
 | ||||||
| #define platformProtectST25RIrqStatus()               platformProtectST25RComm()                               /*!< Protect unique access to IRQ status var - IRQ disable on single thread environment (MCU) ; Mutex lock on a multi thread environment */ | #define platformProtectST25RIrqStatus()             platformProtectST25RComm()                          /*!< Protect unique access to IRQ status var - IRQ disable on single thread environment (MCU) ; Mutex lock on a multi thread environment */ | ||||||
| #define platformUnprotectST25RIrqStatus()             platformUnprotectST25RComm()                             /*!< Unprotect the IRQ status var - IRQ enable on a single thread environment (MCU) ; Mutex unlock on a multi thread environment         */ | #define platformUnprotectST25RIrqStatus()           platformUnprotectST25RComm()                        /*!< Unprotect the IRQ status var - IRQ enable on a single thread environment (MCU) ; Mutex unlock on a multi thread environment         */ | ||||||
| 
 | 
 | ||||||
| #define platformLedOff( port, pin )                   api_hal_light_set(pin, 0x00) | #define platformLedOff( port, pin )                 api_hal_light_set(pin, 0x00) | ||||||
| #define platformLedOn( port, pin )                    api_hal_light_set(pin, 0xFF) | #define platformLedOn( port, pin )                  api_hal_light_set(pin, 0xFF) | ||||||
| 
 | 
 | ||||||
| #define platformGpioSet( port, pin )                  HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET)               /*!< Turns the given GPIO High                   */ | #define platformGpioSet( port, pin )                HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET)          /*!< Turns the given GPIO High                   */ | ||||||
| #define platformGpioClear( port, pin )                HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET)             /*!< Turns the given GPIO Low                    */ | #define platformGpioClear( port, pin )              HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET)        /*!< Turns the given GPIO Low                    */ | ||||||
| #define platformGpioToogle( port, pin )               HAL_GPIO_TogglePin(port, pin)                            /*!< Toogles the given GPIO                      */ | #define platformGpioToogle( port, pin )             HAL_GPIO_TogglePin(port, pin)                       /*!< Toogles the given GPIO                      */ | ||||||
| #define platformGpioIsHigh( port, pin )               (HAL_GPIO_ReadPin(port, pin) == GPIO_PIN_SET)            /*!< Checks if the given LED is High             */ | #define platformGpioIsHigh( port, pin )             (HAL_GPIO_ReadPin(port, pin) == GPIO_PIN_SET)       /*!< Checks if the given LED is High             */ | ||||||
| #define platformGpioIsLow( port, pin )                (!platformGpioIsHigh(port, pin))                         /*!< Checks if the given LED is Low              */ | #define platformGpioIsLow( port, pin )              (!platformGpioIsHigh(port, pin))                    /*!< Checks if the given LED is Low              */ | ||||||
| 
 | 
 | ||||||
| #define platformTimerCreate( t )                      timerCalculateTimer(t)                                    /*!< Create a timer with the given time (ms)     */ | #define platformTimerCreate( t )                    timerCalculateTimer(t)                              /*!< Create a timer with the given time (ms)     */ | ||||||
| #define platformTimerIsExpired( timer )               timerIsExpired(timer)                                     /*!< Checks if the given timer is expired        */ | #define platformTimerIsExpired( timer )             timerIsExpired(timer)                               /*!< Checks if the given timer is expired        */ | ||||||
| #define platformDelay( t )                            osDelay( t )                                              /*!< Performs a delay for the given time (ms)    */ | #define platformDelay( t )                          osDelay( t )                                        /*!< Performs a delay for the given time (ms)    */ | ||||||
| 
 | 
 | ||||||
| #define platformGetSysTick()                          osKernelGetTickCount()                                    /*!< Get System Tick (1 tick = 1 ms)             */ | #define platformGetSysTick()                        osKernelGetTickCount()                              /*!< Get System Tick (1 tick = 1 ms)             */ | ||||||
| 
 | 
 | ||||||
| #define platformAssert( exp )                         assert_param( exp )                                      /*!< Asserts whether the given expression is true*/ | #define platformAssert( exp )                       assert_param( exp )                                 /*!< Asserts whether the given expression is true*/ | ||||||
| // #define platformErrorHandle()                         Error_Handler()                                           /*!< Global error handle\trap                    */
 | #define platformErrorHandle()                       Error_Handler()                                     /*!< Global error handle\trap                    */ | ||||||
| 
 | 
 | ||||||
| #define platformSpiSelect()                           platformGpioClear( ST25R_SS_PORT, ST25R_SS_PIN )         /*!< SPI SS\CS: Chip|Slave Select                */ | #define platformSpiSelect()                         platformGpioClear( ST25R_SS_PORT, ST25R_SS_PIN )    /*!< SPI SS\CS: Chip|Slave Select                */ | ||||||
| #define platformSpiDeselect()                         platformGpioSet( ST25R_SS_PORT, ST25R_SS_PIN )           /*!< SPI SS\CS: Chip|Slave Deselect              */ | #define platformSpiDeselect()                       platformGpioSet( ST25R_SS_PORT, ST25R_SS_PIN )      /*!< SPI SS\CS: Chip|Slave Deselect              */ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #define platformI2CTx( txBuf, len, last, txOnly )                                                              /*!< I2C Transmit                                */ | #define platformI2CTx( txBuf, len, last, txOnly )                                                       /*!< I2C Transmit                                */ | ||||||
| #define platformI2CRx( txBuf, len )                                                                            /*!< I2C Receive                                 */ | #define platformI2CRx( txBuf, len )                                                                     /*!< I2C Receive                                 */ | ||||||
| #define platformI2CStart()                                                                                     /*!< I2C Start condition                         */ | #define platformI2CStart()                                                                              /*!< I2C Start condition                         */ | ||||||
| #define platformI2CStop()                                                                                      /*!< I2C Stop condition                          */ | #define platformI2CStop()                                                                               /*!< I2C Stop condition                          */ | ||||||
| #define platformI2CRepeatStart()                                                                               /*!< I2C Repeat Start                            */ | #define platformI2CRepeatStart()                                                                        /*!< I2C Repeat Start                            */ | ||||||
| #define platformI2CSlaveAddrWR(add)                                                                            /*!< I2C Slave address for Write operation       */ | #define platformI2CSlaveAddrWR(add)                                                                     /*!< I2C Slave address for Write operation       */ | ||||||
| #define platformI2CSlaveAddrRD(add)                                                                            /*!< I2C Slave address for Read operation        */ | #define platformI2CSlaveAddrRD(add)                                                                     /*!< I2C Slave address for Read operation        */ | ||||||
| 
 | 
 | ||||||
| #define platformLog(...)                                                                                       /*!< Log  method                                 */ | #define platformLog(...)                                                                                /*!< Log  method                                 */ | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  ****************************************************************************** |  ****************************************************************************** | ||||||
|  | |||||||
							
								
								
									
										171
									
								
								lib/drivers/cc1101.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								lib/drivers/cc1101.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,171 @@ | |||||||
|  | #include "cc1101.h" | ||||||
|  | #include <cmsis_os2.h> | ||||||
|  | #include <api-hal-delay.h> | ||||||
|  | #include <assert.h> | ||||||
|  | #include <string.h> | ||||||
|  | 
 | ||||||
|  | CC1101Status cc1101_strobe(const ApiHalSpiDevice* device, uint8_t strobe) { | ||||||
|  |     uint8_t tx[1] = { strobe }; | ||||||
|  |     CC1101Status rx[1] = { 0 }; | ||||||
|  | 
 | ||||||
|  |     hal_gpio_write(device->chip_select, false); | ||||||
|  |     while(hal_gpio_read(device->bus->miso)); | ||||||
|  |     api_hal_spi_bus_trx(device->bus, tx, (uint8_t*)rx, 1, CC1101_TIMEOUT); | ||||||
|  |     hal_gpio_write(device->chip_select, true); | ||||||
|  | 
 | ||||||
|  |     assert(rx[0].CHIP_RDYn == 0); | ||||||
|  |     return rx[0]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | CC1101Status cc1101_write_reg(const ApiHalSpiDevice* device, uint8_t reg, uint8_t data) { | ||||||
|  |     uint8_t tx[2] = { reg, data }; | ||||||
|  |     CC1101Status rx[2] = { 0 }; | ||||||
|  | 
 | ||||||
|  |     hal_gpio_write(device->chip_select, false); | ||||||
|  |     while(hal_gpio_read(device->bus->miso)); | ||||||
|  |     api_hal_spi_bus_trx(device->bus, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT); | ||||||
|  |     hal_gpio_write(device->chip_select, true); | ||||||
|  | 
 | ||||||
|  |     assert((rx[0].CHIP_RDYn|rx[1].CHIP_RDYn) == 0); | ||||||
|  |     return rx[1]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | CC1101Status cc1101_read_reg(const ApiHalSpiDevice* device, uint8_t reg, uint8_t* data) { | ||||||
|  |     assert(sizeof(CC1101Status) == 1); | ||||||
|  |     uint8_t tx[2] = { reg|CC1101_READ, 0}; | ||||||
|  |     CC1101Status rx[2] = { 0 }; | ||||||
|  | 
 | ||||||
|  |     hal_gpio_write(device->chip_select, false); | ||||||
|  |     while(hal_gpio_read(device->bus->miso)); | ||||||
|  |     api_hal_spi_bus_trx(device->bus, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT); | ||||||
|  |     hal_gpio_write(device->chip_select, true); | ||||||
|  | 
 | ||||||
|  |     assert((rx[0].CHIP_RDYn) == 0); | ||||||
|  |     *data = *(uint8_t*)&rx[1]; | ||||||
|  |     return rx[0]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t cc1101_get_partnumber(const ApiHalSpiDevice* device) { | ||||||
|  |     uint8_t partnumber=0; | ||||||
|  |     cc1101_read_reg(device, CC1101_STATUS_PARTNUM|CC1101_BURST, &partnumber); | ||||||
|  |     return partnumber; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t cc1101_get_version(const ApiHalSpiDevice* device) { | ||||||
|  |     uint8_t version=0; | ||||||
|  |     cc1101_read_reg(device, CC1101_STATUS_VERSION|CC1101_BURST, &version); | ||||||
|  |     return version; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t cc1101_get_rssi(const ApiHalSpiDevice* device) { | ||||||
|  |     uint8_t rssi=0; | ||||||
|  |     cc1101_read_reg(device, CC1101_STATUS_RSSI|CC1101_BURST, &rssi); | ||||||
|  |     return rssi; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cc1101_reset(const ApiHalSpiDevice* device) { | ||||||
|  |     hal_gpio_write(device->chip_select, false); | ||||||
|  |     delay_us(1000); | ||||||
|  |     hal_gpio_write(device->chip_select, true); | ||||||
|  |     delay_us(1000); | ||||||
|  |     cc1101_strobe(device, CC1101_STROBE_SRES); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cc1101_shutdown(const ApiHalSpiDevice* device) { | ||||||
|  |     cc1101_strobe(device, CC1101_STROBE_SPWD); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cc1101_calibrate(const ApiHalSpiDevice* device) { | ||||||
|  |     cc1101_strobe(device, CC1101_STROBE_SCAL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cc1101_switch_to_idle(const ApiHalSpiDevice* device) { | ||||||
|  |     cc1101_strobe(device, CC1101_STROBE_SIDLE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cc1101_switch_to_rx(const ApiHalSpiDevice* device) { | ||||||
|  |     cc1101_strobe(device, CC1101_STROBE_SRX); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cc1101_switch_to_tx(const ApiHalSpiDevice* device) { | ||||||
|  |     cc1101_strobe(device, CC1101_STROBE_STX); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cc1101_flush_rx(const ApiHalSpiDevice* device) { | ||||||
|  |     cc1101_strobe(device, CC1101_STROBE_SFRX); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cc1101_flush_tx(const ApiHalSpiDevice* device) { | ||||||
|  |     cc1101_strobe(device, CC1101_STROBE_SFTX); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t cc1101_set_frequency(const ApiHalSpiDevice* device, uint32_t value) { | ||||||
|  |     uint64_t real_value = (uint64_t)value * 0xFFFF / CC1101_QUARTZ; | ||||||
|  | 
 | ||||||
|  |     // Sanity check
 | ||||||
|  |     assert((real_value & 0xFFFFFF) == real_value); | ||||||
|  | 
 | ||||||
|  |     cc1101_write_reg(device, CC1101_FREQ2, (real_value >> 16) & 0xFF); | ||||||
|  |     cc1101_write_reg(device, CC1101_FREQ1, (real_value >> 8 ) & 0xFF); | ||||||
|  |     cc1101_write_reg(device, CC1101_FREQ0, (real_value >> 0 ) & 0xFF); | ||||||
|  | 
 | ||||||
|  |     uint64_t real_frequency = real_value * CC1101_QUARTZ / 0xFFFF; | ||||||
|  | 
 | ||||||
|  |     return (uint32_t)real_frequency; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t cc1101_get_frequency_step(const ApiHalSpiDevice* device) { | ||||||
|  |     return CC1101_QUARTZ / 0xFFFF; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t cc1101_set_frequency_offset(const ApiHalSpiDevice* device, uint32_t value) { | ||||||
|  |     uint64_t real_value = value * 0x4000 / CC1101_QUARTZ; | ||||||
|  |     assert((real_value & 0xFF) == real_value); | ||||||
|  | 
 | ||||||
|  |     cc1101_write_reg(device, CC1101_FSCTRL0, (real_value >> 0 ) & 0xFF); | ||||||
|  | 
 | ||||||
|  |     uint64_t real_frequency = real_value * CC1101_QUARTZ / 0x4000; | ||||||
|  | 
 | ||||||
|  |     return (uint32_t)real_frequency; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t cc1101_get_frequency_offset_step(const ApiHalSpiDevice* device) { | ||||||
|  |     return CC1101_QUARTZ / 0x4000; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cc1101_set_pa_table(const ApiHalSpiDevice* device, const uint8_t value[8]) { | ||||||
|  |     uint8_t tx[9] = { CC1101_PATABLE | CC1101_BURST }; | ||||||
|  |     CC1101Status rx[9] = { 0 }; | ||||||
|  | 
 | ||||||
|  |     memcpy(&tx[1], &value[0], 8); | ||||||
|  | 
 | ||||||
|  |     hal_gpio_write(device->chip_select, false); | ||||||
|  |     while(hal_gpio_read(device->bus->miso)); | ||||||
|  |     api_hal_spi_bus_trx(device->bus, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT); | ||||||
|  |     hal_gpio_write(device->chip_select, true); | ||||||
|  | 
 | ||||||
|  |     assert((rx[0].CHIP_RDYn|rx[8].CHIP_RDYn) == 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t cc1101_write_fifo(const ApiHalSpiDevice* device, const uint8_t* data, uint8_t size) { | ||||||
|  |     uint8_t tx = CC1101_FIFO | CC1101_BURST; | ||||||
|  |     CC1101Status rx = { 0 }; | ||||||
|  | 
 | ||||||
|  |     // Start transaction
 | ||||||
|  |     hal_gpio_write(device->chip_select, false); | ||||||
|  |     // Wait IC to become ready
 | ||||||
|  |     while(hal_gpio_read(device->bus->miso)); | ||||||
|  |     // Tell IC what we want
 | ||||||
|  |     api_hal_spi_bus_trx(device->bus, &tx, (uint8_t*)&rx, 1, CC1101_TIMEOUT); | ||||||
|  |     assert((rx.CHIP_RDYn) == 0); | ||||||
|  |     // Transmit data
 | ||||||
|  |     api_hal_spi_bus_tx(device->bus, (uint8_t*)data, size, CC1101_TIMEOUT); | ||||||
|  |     // Finish transaction
 | ||||||
|  |     hal_gpio_write(device->chip_select, true); | ||||||
|  | 
 | ||||||
|  |     return size; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t cc1101_read_fifo(const ApiHalSpiDevice* device, uint8_t* data, uint8_t size) { | ||||||
|  |     return size; | ||||||
|  | } | ||||||
							
								
								
									
										153
									
								
								lib/drivers/cc1101.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								lib/drivers/cc1101.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,153 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "cc1101_regs.h" | ||||||
|  | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <api-hal-spi.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* Low level API */ | ||||||
|  | 
 | ||||||
|  | /** Strobe command to the device
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  * @param strobe - command to execute | ||||||
|  |  * @return device status | ||||||
|  |  */ | ||||||
|  | CC1101Status cc1101_strobe(const ApiHalSpiDevice* device, uint8_t strobe); | ||||||
|  | 
 | ||||||
|  | /** Write device register
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  * @param reg - register | ||||||
|  |  * @param data - data to write | ||||||
|  |  * @return device status | ||||||
|  |  */ | ||||||
|  | CC1101Status cc1101_write_reg(const ApiHalSpiDevice* device, uint8_t reg, uint8_t data); | ||||||
|  | 
 | ||||||
|  | /** Read device register
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  * @param reg - register | ||||||
|  |  * @param[out] data - pointer to data | ||||||
|  |  * @return device status | ||||||
|  |  */ | ||||||
|  | CC1101Status cc1101_read_reg(const ApiHalSpiDevice* device, uint8_t reg, uint8_t* data); | ||||||
|  | 
 | ||||||
|  | /* High level API */ | ||||||
|  | 
 | ||||||
|  | /** Reset
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  */ | ||||||
|  | void cc1101_reset(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Enable shutdown mode
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  */ | ||||||
|  | void cc1101_shutdown(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Get Partnumber
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  */ | ||||||
|  | uint8_t cc1101_get_partnumber(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Get Version
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  */ | ||||||
|  | uint8_t cc1101_get_version(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Get raw RSSI value
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  */ | ||||||
|  | uint8_t cc1101_get_rssi(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Calibrate oscillator
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  */ | ||||||
|  | void cc1101_calibrate(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Switch to idle
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  */ | ||||||
|  | void cc1101_switch_to_idle(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Switch to RX
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  */ | ||||||
|  | void cc1101_switch_to_rx(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Switch to TX
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  */ | ||||||
|  | void cc1101_switch_to_tx(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Flush RX FIFO
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  */ | ||||||
|  | void cc1101_flush_rx(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Flush TX FIFO
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  */ | ||||||
|  | void cc1101_flush_tx(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Set Frequency
 | ||||||
|  |  * Is not 100% precise, depends on quartz used | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  * @param value - frequency in herz | ||||||
|  |  * @return real frequency that were set | ||||||
|  |  */ | ||||||
|  | uint32_t cc1101_set_frequency(const ApiHalSpiDevice* device, uint32_t value); | ||||||
|  | 
 | ||||||
|  | /** Get Frequency Step
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  * @return frequency step | ||||||
|  |  */ | ||||||
|  | uint32_t cc1101_get_frequency_step(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Set Frequency Offset
 | ||||||
|  |  * Is not 100% precise, depends on quartz used | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  * @param value - frequency offset in herz | ||||||
|  |  * @return real frequency that were set | ||||||
|  |  */ | ||||||
|  | uint32_t cc1101_set_frequency_offset(const ApiHalSpiDevice* device, uint32_t value); | ||||||
|  | 
 | ||||||
|  | /** Get Frequency Offset Step
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  * @return frequency offset step | ||||||
|  |  */ | ||||||
|  | uint32_t cc1101_get_frequency_offset_step(const ApiHalSpiDevice* device); | ||||||
|  | 
 | ||||||
|  | /** Set Power Amplifier level table, ramp
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  * @param value - array of power level values | ||||||
|  |  */ | ||||||
|  | void cc1101_set_pa_table(const ApiHalSpiDevice* device, const uint8_t value[8]); | ||||||
|  | 
 | ||||||
|  | /** Set Power Amplifier level table, ramp
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  * @param value - array of power level values | ||||||
|  |  */ | ||||||
|  | void cc1101_set_pa_table(const ApiHalSpiDevice* device, const uint8_t value[8]); | ||||||
|  | 
 | ||||||
|  | /** Write FIFO
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  * @param data, pointer to byte array | ||||||
|  |  * @param size, write bytes count | ||||||
|  |  * @return size, written bytes count | ||||||
|  |  */ | ||||||
|  | uint8_t cc1101_write_fifo(const ApiHalSpiDevice* device, const uint8_t* data, uint8_t size); | ||||||
|  | 
 | ||||||
|  | /** Read FIFO
 | ||||||
|  |  * @param device - pointer to ApiHalSpiDevice | ||||||
|  |  * @param data, pointer to byte array | ||||||
|  |  * @param size, bytes to read from fifo | ||||||
|  |  * @return size, read bytes count | ||||||
|  |  */ | ||||||
|  | uint8_t cc1101_read_fifo(const ApiHalSpiDevice* device, uint8_t* data, uint8_t size); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										131
									
								
								lib/drivers/cc1101_regs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								lib/drivers/cc1101_regs.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,131 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #define CC1101_QUARTZ                   26000000 | ||||||
|  | 
 | ||||||
|  | #define CC1101_TIMEOUT                  500 | ||||||
|  | 
 | ||||||
|  | #define CC1101_READ                     (1<<7)  /** Read Bit */ | ||||||
|  | #define CC1101_BURST                    (1<<6)  /** Burst Bit */ | ||||||
|  | 
 | ||||||
|  | /* Common registers, CC1101_BURST and CC1101_WRITE behaves as expected  */ | ||||||
|  | #define CC1101_IOCFG2                   0x00    /** GDO2 output pin configuration */ | ||||||
|  | #define CC1101_IOCFG1                   0x01    /** GDO1 output pin configuration */ | ||||||
|  | #define CC1101_IOCFG0                   0x02    /** GDO0 output pin configuration */ | ||||||
|  | #define CC1101_FIFOTHR                  0x03    /** RX FIFO and TX FIFO thresholds */ | ||||||
|  | #define CC1101_SYNC1                    0x04    /** Sync word, high byte */ | ||||||
|  | #define CC1101_SYNC0                    0x05    /** Sync word, low byte */ | ||||||
|  | #define CC1101_PKTLEN                   0x06    /** Packet length */ | ||||||
|  | #define CC1101_PKTCTRL1                 0x07    /** Packet automation control */ | ||||||
|  | #define CC1101_PKTCTRL0                 0x08    /** Packet automation control */ | ||||||
|  | #define CC1101_ADDR                     0x09    /** Device address */ | ||||||
|  | #define CC1101_CHANNR                   0x0A    /** Channel number */ | ||||||
|  | #define CC1101_FSCTRL1                  0x0B    /** Frequency synthesizer control */ | ||||||
|  | #define CC1101_FSCTRL0                  0x0C    /** Frequency synthesizer control */ | ||||||
|  | #define CC1101_FREQ2                    0x0D    /** Frequency control word, high byte */ | ||||||
|  | #define CC1101_FREQ1                    0x0E    /** Frequency control word, middle byte */ | ||||||
|  | #define CC1101_FREQ0                    0x0F    /** Frequency control word, low byte */ | ||||||
|  | #define CC1101_MDMCFG4                  0x10    /** Modem configuration */ | ||||||
|  | #define CC1101_MDMCFG3                  0x11    /** Modem configuration */ | ||||||
|  | #define CC1101_MDMCFG2                  0x12    /** Modem configuration */ | ||||||
|  | #define CC1101_MDMCFG1                  0x13    /** Modem configuration */ | ||||||
|  | #define CC1101_MDMCFG0                  0x14    /** Modem configuration */ | ||||||
|  | #define CC1101_DEVIATN                  0x15    /** Modem deviation setting */ | ||||||
|  | #define CC1101_MCSM2                    0x16    /** Main Radio Control State Machine configuration */ | ||||||
|  | #define CC1101_MCSM1                    0x17    /** Main Radio Control State Machine configuration */ | ||||||
|  | #define CC1101_MCSM0                    0x18    /** Main Radio Control State Machine configuration */ | ||||||
|  | #define CC1101_FOCCFG                   0x19    /** Frequency Offset Compensation configuration */ | ||||||
|  | #define CC1101_BSCFG                    0x1A    /** Bit Synchronization configuration */ | ||||||
|  | #define CC1101_AGCTRL2                  0x1B    /** AGC control */ | ||||||
|  | #define CC1101_AGCTRL1                  0x1C    /** AGC control */ | ||||||
|  | #define CC1101_AGCTRL0                  0x1D    /** AGC control */ | ||||||
|  | #define CC1101_WOREVT1                  0x1E    /** High byte Event 0 timeout */ | ||||||
|  | #define CC1101_WOREVT0                  0x1F    /** Low byte Event 0 timeout */ | ||||||
|  | #define CC1101_WORCTRL                  0x20    /** Wake On Radio control */ | ||||||
|  | #define CC1101_FREND1                   0x21    /** Front end RX configuration */ | ||||||
|  | #define CC1101_FREND0                   0x22    /** Front end TX configuration */ | ||||||
|  | #define CC1101_FSCAL3                   0x23    /** Frequency synthesizer calibration */ | ||||||
|  | #define CC1101_FSCAL2                   0x24    /** Frequency synthesizer calibration */ | ||||||
|  | #define CC1101_FSCAL1                   0x25    /** Frequency synthesizer calibration */ | ||||||
|  | #define CC1101_FSCAL0                   0x26    /** Frequency synthesizer calibration */ | ||||||
|  | #define CC1101_RCCTRL1                  0x27    /** RC oscillator configuration */ | ||||||
|  | #define CC1101_RCCTRL0                  0x28    /** RC oscillator configuration */ | ||||||
|  | #define CC1101_FSTEST                   0x29    /** Frequency synthesizer calibration control */ | ||||||
|  | #define CC1101_PTEST                    0x2A    /** Production test */ | ||||||
|  | #define CC1101_AGCTEST                  0x2B    /** AGC test */ | ||||||
|  | #define CC1101_TEST2                    0x2C    /** Various test settings */ | ||||||
|  | #define CC1101_TEST1                    0x2D    /** Various test settings */ | ||||||
|  | #define CC1101_TEST0                    0x2E    /** Various test settings */ | ||||||
|  | 
 | ||||||
|  | /* Strobe registers, CC1101_BURST is not available, CC1101_WRITE ignored */ | ||||||
|  | #define CC1101_STROBE_SRES              0x30    /** Reset chip. */ | ||||||
|  | #define CC1101_STROBE_SFSTXON           0x31    /** Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). If in RX (with CCA): Go to a wait state where only the synthesizer is running (for quick RX / TX turnaround). */ | ||||||
|  | #define CC1101_STROBE_SXOFF             0x32    /** Turn off crystal oscillator. */ | ||||||
|  | #define CC1101_STROBE_SCAL              0x33    /** Calibrate frequency synthesizer and turn it off. SCAL can be strobed from IDLE mode without setting manual calibration mode (MCSM0.FS_AUTOCAL=0) */ | ||||||
|  | #define CC1101_STROBE_SRX               0x34    /** Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1. */ | ||||||
|  | #define CC1101_STROBE_STX               0x35    /** In IDLE state: Enable TX. Perform calibration first if MCSM0.FS_AUTOCAL=1. If in RX state and CCA is enabled: Only go to TX if channel is clear. */ | ||||||
|  | #define CC1101_STROBE_SIDLE             0x36    /** Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable. */ | ||||||
|  | #define CC1101_STROBE_SWOR              0x38    /** Start automatic RX polling sequence (Wake-on-Radio) as described in Section 19.5 if WORCTRL.RC_PD=0. */ | ||||||
|  | /* 0x37 is unused */ | ||||||
|  | #define CC1101_STROBE_SPWD              0x39    /** Enter power down mode when CSn goes high. */ | ||||||
|  | #define CC1101_STROBE_SFRX              0x3A    /** Flush the RX FIFO buffer. Only issue SFRX in IDLE or RXFIFO_OVERFLOW states. */ | ||||||
|  | #define CC1101_STROBE_SFTX              0x3B    /** Flush the TX FIFO buffer. Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states. */ | ||||||
|  | #define CC1101_STROBE_SWORRST           0x3C    /** Reset real time clock to Event1 value. */ | ||||||
|  | #define CC1101_STROBE_SNOP              0x3D    /** No operation. May be used to get access to the chip status byte.*/ | ||||||
|  | 
 | ||||||
|  | /* Status registers, must be accessed with CC1101_BURST, but one by one */ | ||||||
|  | #define CC1101_STATUS_PARTNUM           0x30    /** Chip ID Part Number */ | ||||||
|  | #define CC1101_STATUS_VERSION           0x31    /** Chip ID Version */ | ||||||
|  | #define CC1101_STATUS_FREQEST           0x32    /** Frequency Offset Estimate from Demodulator */ | ||||||
|  | #define CC1101_STATUS_LQI               0x33    /** Demodulator Estimate for Link Quality */ | ||||||
|  | #define CC1101_STATUS_RSSI              0x34    /** Received Signal Strength Indication */ | ||||||
|  | #define CC1101_STATUS_MARCSTATE         0x35    /** Main Radio Control State Machine State */ | ||||||
|  | #define CC1101_STATUS_WORTIME1          0x36    /** High Byte of WOR Time */ | ||||||
|  | #define CC1101_STATUS_WORTIME0          0x37    /** Low Byte of WOR Time */ | ||||||
|  | #define CC1101_STATUS_PKTSTATUS         0x38    /** Current GDOx Status and Packet Status */ | ||||||
|  | #define CC1101_STATUS_VCO_VC_DAC        0x39    /** Current Setting from PLL Calibration Module */ | ||||||
|  | #define CC1101_STATUS_TXBYTES           0x3A    /** Underflow and Number of Bytes */ | ||||||
|  | #define CC1101_STATUS_RXBYTES           0x3B    /** Overflow and Number of Bytes */ | ||||||
|  | #define CC1101_STATUS_RCCTRL1_STATUS    0x3C    /** Last RC Oscillator Calibration Result */ | ||||||
|  | #define CC1101_STATUS_RCCTRL0_STATUS    0x3D    /** Last RC Oscillator Calibration Result */ | ||||||
|  | 
 | ||||||
|  | /* Some special registers, use CC1101_BURST to read/write data */ | ||||||
|  | #define CC1101_PATABLE                  0x3E    /** PATABLE register number, an 8-byte table that defines the PA control settings */ | ||||||
|  | #define CC1101_FIFO                     0x3F    /** FIFO register nunmber, can be combined with CC1101_WRITE and/or CC1101_BURST */ | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     CC1101StateIDLE=0b000,              /** IDLE state */ | ||||||
|  |     CC1101StateRX=0b001,                /** Receive mode */ | ||||||
|  |     CC1101StateTX=0b010,                /** Transmit mode */ | ||||||
|  |     CC1101StateFSTXON=0b011,            /** Fast TX ready */ | ||||||
|  |     CC1101StateCALIBRATE=0b100,         /** Frequency synthesizer calibration is running */ | ||||||
|  |     CC1101StateSETTLING=0b101,          /** PLL is settling */ | ||||||
|  |     CC1101StateRXFIFO_OVERFLOW=0b110,   /** RX FIFO has overflowed. Read out any useful data, then flush the FIFO with SFRX */ | ||||||
|  |     CC1101StateTXFIFO_UNDERFLOW=0b111,  /** TX FIFO has underflowed. Acknowledge with SFTX */ | ||||||
|  | } CC1101State; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t FIFO_BYTES_AVAILABLE:4; | ||||||
|  |     CC1101State STATE:3; | ||||||
|  |     bool CHIP_RDYn:1; | ||||||
|  | } CC1101Status; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t NUM_TXBYTES:7; | ||||||
|  |     bool TXFIFO_UNDERFLOW:1; | ||||||
|  | } CC1101TxBytes; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t NUM_RXBYTES:7; | ||||||
|  |     bool RXFIFO_OVERFLOW:1; | ||||||
|  | } CC1101RxBytes; | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく