[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:
あく 2021-03-31 20:52:26 +03:00 committed by GitHub
parent 5309bfae41
commit 5439e232cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 2364 additions and 2500 deletions

View File

@ -16,7 +16,6 @@ int32_t gui_task(void* p);
int32_t backlight_control(void* p);
int32_t irda(void* p);
int32_t app_loader(void* p);
int32_t cc1101_workaround(void* p);
int32_t lf_rfid_workaround(void* p);
int32_t nfc_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 floopper_bloopper(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 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},
#endif
#ifdef APP_CC1101
{.app = cc1101_workaround,
.name = "cc1101 workaround",
.stack_size = 1024,
.icon = A_Plugins_14},
#endif
#ifdef APP_LF_RFID
{.app = 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},
#endif
#ifdef APP_SUBGHZ
{.app = app_subghz, .name = "app_subghz", .stack_size = 1024, .icon = A_Plugins_14},
#endif
#ifdef APP_KEYPAD_TEST
{.app = keypad_test, .name = "keypad_test", .icon = A_Plugins_14},
#endif
@ -164,8 +152,8 @@ const size_t FLIPPER_SERVICES_COUNT = sizeof(FLIPPER_SERVICES) / sizeof(FlipperA
// Main menu APP
const FlipperApplication FLIPPER_APPS[] = {
#ifdef BUILD_CC1101
{.app = cc1101_workaround, .name = "Sub-1 GHz", .stack_size = 1024, .icon = A_Sub1ghz_14},
#ifdef BUILD_SUBGHZ
{.app = subghz_app, .name = "Sub-1 GHz", .stack_size = 1024, .icon = A_Sub1ghz_14},
#endif
#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},
#endif
#ifdef BUILD_SUBGHZ
{.app = app_subghz, .name = "app_subghz", .stack_size = 1024, .icon = A_Plugins_14},
#endif
#ifdef BUILD_KEYPAD_TEST
{.app = keypad_test, .name = "keypad_test", .icon = A_Plugins_14},
#endif

View File

@ -20,7 +20,7 @@ APP_DOLPHIN = 1
BUILD_EXAMPLE_BLINK = 1
BUILD_EXAMPLE_UART_WRITE = 1
BUILD_EXAMPLE_INPUT_DUMP = 1
BUILD_CC1101 = 1
BUILD_SUBGHZ = 1
BUILD_LF_RFID = 1
BUILD_SPEAKER_DEMO = 1
BUILD_VIBRO_DEMO = 1
@ -31,7 +31,6 @@ BUILD_FLOOPPER_BLOOPPER = 1
BUILD_IBUTTON = 1
BUILD_GUI_TEST = 1
BUILD_KEYPAD_TEST = 1
BUILD_SUBGHZ = 1
endif
APP_NFC ?= 0
@ -146,16 +145,9 @@ C_SOURCES += $(APP_DIR)/examples/u8g2_qrcode.c
C_SOURCES += $(LIB_DIR)/qrcode/qrcode.c
endif
APP_CC1101 ?= 0
ifeq ($(APP_CC1101), 1)
CFLAGS += -DAPP_CC1101
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)
ifeq ($(BUILD_SUBGHZ), 1)
CFLAGS += -DBUILD_SUBGHZ
C_SOURCES += $(wildcard $(APP_DIR)/subghz/*.c)
APP_INPUT = 1
APP_GUI = 1
APP_CLI = 1
@ -292,18 +284,6 @@ CFLAGS += -DBUILD_GUI_TEST
C_SOURCES += $(wildcard $(APP_DIR)/gui-test/*.c)
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
ifeq ($(APP_SDNFC), 1)
CFLAGS += -DAPP_SDNFC

View File

@ -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;
}

View File

@ -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 Enablevariable length packets, packet length configured by the first byte after sync word
SpiWriteReg(
CC1101_PKTCTRL0, 0x33); //whitening off; asynchronous serial mode; CRC diablereserved
//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;
}

View File

@ -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);
};

View File

@ -34,6 +34,7 @@ void canvas_free(Canvas* canvas) {
void canvas_reset(Canvas* canvas) {
furi_assert(canvas);
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
}

View File

@ -1,122 +1,66 @@
#include "u8g2/u8g2.h"
#include <furi.h>
#include <api-hal.h>
#include <furi.h>
#include <main.h>
extern SPI_HandleTypeDef SPI_D;
// TODO: fix log
#ifdef DEBUG
#undef DEBUG
#endif
static ApiHalSpiDevice* u8g2_periphery_display = NULL;
uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) {
switch(msg) {
//Initialize SPI peripheral
case U8X8_MSG_GPIO_AND_DELAY_INIT:
/* HAL initialization contains all what we need so we can skip this part. */
break;
//Function which implements a delay, arg_int contains the amount of ms
case U8X8_MSG_DELAY_MILLI:
osDelay(arg_int);
break;
//Function which delays 10us
case U8X8_MSG_DELAY_10MICRO:
delay_us(10);
break;
//Function which delays 100ns
case U8X8_MSG_DELAY_100NANO:
asm("nop");
break;
// Function to define the logic level of the RESET line
case U8X8_MSG_GPIO_RESET:
#ifdef DEBUG
printf("[u8g2] rst %d\n", arg_int);
#endif
// TODO change it to FuriRecord pin
HAL_GPIO_WritePin(
DISPLAY_RST_GPIO_Port, DISPLAY_RST_Pin, arg_int ? GPIO_PIN_SET : GPIO_PIN_RESET);
hal_gpio_write(&gpio_display_rst, arg_int);
break;
default:
return 0;
}
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;
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;
}

View File

@ -37,12 +37,12 @@ static void render_callback(Canvas* canvas, void* ctx) {
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);
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);
release_mutex((ValueMutex*)ctx, state);

View File

@ -244,7 +244,7 @@ ReturnCode nfc_worker_trx(
}
void nfc_worker_exchange(NfcWorker* nfc_worker, rfalNfcDevice* nfc_device) {
ReturnCode err;
ReturnCode err = ERR_NONE;
uint8_t* rxData;
uint16_t* rcvLen;
uint8_t txBuf[100];

View File

@ -849,4 +849,4 @@ int32_t sd_filesystem(void* p) {
}
return 0;
}
}

View File

@ -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:
};

View File

@ -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);
}

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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()},
};
};

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;
};

View 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;
}

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
#pragma once
typedef struct SubGhz SubGhz;

View 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;

View 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;
}

View 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);

View 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;
}

View 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);

View File

@ -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);
}

View File

@ -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;
};

View File

@ -55,7 +55,7 @@ flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME
#
# Note that there is a pretty wide band where things are
# more or less stable, see http://openocd.zylin.com/#/c/3366/
adapter speed 8000
adapter speed 24000
adapter srst delay 100
if {[using_jtag]} {
@ -77,12 +77,12 @@ $_TARGETNAME configure -event reset-init {
mmw 0x58004000 0x00000102 0 ;# FLASH_ACR |= PRFTBE | 2(Latency)
mmw 0x58000000 0x00000091 0 ;# RCC_CR = MSI_ON | MSI Range 24 MHz
# Boost JTAG frequency
adapter speed 8000
adapter speed 24000
}
$_TARGETNAME configure -event reset-start {
# Reset clock is MSI (4 MHz)
adapter speed 8000
adapter speed 24000
}
$_TARGETNAME configure -event examine-end {

View File

@ -1,23 +1,98 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Sub-GHz band type */
/** Radio Presets */
typedef enum {
RfBandIsolation = 0,
RfBand1 = 1,
RfBand2 = 2,
RfBand3 = 3
} RfBand;
ApiHalSubGhzPresetOokAsync, /** OOK, asynchronous */
ApiHalSubGhzPreset2FskPacket, /** 2FSK, 115kBaud, variable packet length */
} ApiHalSubGhzPreset;
/**
* Set Sub-GHz band
* @param band RfBand
/** Switchable Radio Paths */
typedef enum {
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
}
#endif
#endif

View File

@ -1,153 +1,103 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* <h2><center>&copy; 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
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#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);
/* 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 QUARTZ_32MHZ_IN_Pin GPIO_PIN_14
#define QUARTZ_32MHZ_IN_GPIO_Port GPIOC
#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_BACK_GPIO_Port GPIOC
#define BUTTON_BACK_Pin GPIO_PIN_13
#define BUTTON_DOWN_EXTI_IRQn EXTI1_IRQn
#define NFC_CS_Pin GPIO_PIN_4
#define NFC_CS_GPIO_Port GPIOE
#define BUTTON_RIGHT_Pin GPIO_PIN_12
#define BUTTON_RIGHT_GPIO_Port GPIOB
#define BUTTON_DOWN_GPIO_Port GPIOB
#define BUTTON_DOWN_Pin GPIO_PIN_1
#define BUTTON_LEFT_EXTI_IRQn EXTI15_10_IRQn
#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 RFID_OUT_Pin GPIO_PIN_13
#define RFID_OUT_GPIO_Port GPIOB
#define iBTN_Pin GPIO_PIN_14
#define iBTN_GPIO_Port GPIOB
#define SPI_D_MOSI_Pin GPIO_PIN_15
#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 BUTTON_RIGHT_GPIO_Port GPIOB
#define BUTTON_RIGHT_Pin GPIO_PIN_12
#define BUTTON_UP_EXTI_IRQn EXTI15_10_IRQn
#define BUTTON_UP_GPIO_Port GPIOB
#define BUTTON_UP_Pin GPIO_PIN_10
#define CC1101_CS_GPIO_Port GPIOD
#define SPI_D_SCK_Pin GPIO_PIN_1
#define SPI_D_SCK_GPIO_Port GPIOD
#define PB3_Pin GPIO_PIN_3
#define CC1101_CS_Pin GPIO_PIN_0
#define CC1101_G0_GPIO_Port GPIOC
#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 SPI_R_MISO_Pin GPIO_PIN_4
#define SPI_R_MISO_GPIO_Port GPIOB
#define SPI_R_MOSI_Pin GPIO_PIN_5
#define SPI_R_MOSI_GPIO_Port GPIOB
/* USER CODE BEGIN Private defines */
#define PB3_Pin GPIO_PIN_3
#define PC0_GPIO_Port GPIOC
#define PC0_Pin GPIO_PIN_0
#define PC10_GPIO_Port GPIOC
#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_D hspi2
@ -183,12 +133,6 @@ extern TIM_HandleTypeDef htim16;
#define VIBRO_Pin GPIO_PIN_10
#define VIBRO_GPIO_Port GPIOC
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -23,5 +23,6 @@ void delay_us(float microseconds) {
void delay(float milliseconds) {
uint32_t ticks = milliseconds / (1000.0f / osKernelGetTickFreq());
osStatus_t result = osDelay(ticks);
(void)result;
assert(result == osOK);
}

View File

@ -4,35 +4,41 @@
const InputPin input_pins[] = {
{.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,
.pin = BUTTON_RIGHT_Pin,
.key = InputKeyRight,
.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_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 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 ibutton_gpio = {iBTN_GPIO_Port, iBTN_Pin};
const GpioPin cc1101_g0_gpio = {CC1101_G0_GPIO_Port, CC1101_G0_Pin};
// external gpio's
const GpioPin ext_pc0_gpio = {GPIOC, GPIO_PIN_0};
const GpioPin ext_pc1_gpio = {GPIOC, GPIO_PIN_1};
const GpioPin ext_pc3_gpio = {GPIOC, GPIO_PIN_3};
const GpioPin ext_pb2_gpio = {GPIOB, GPIO_PIN_2};
const GpioPin ext_pb3_gpio = {GPIOB, GPIO_PIN_3};
const GpioPin ext_pa4_gpio = {GPIOA, GPIO_PIN_4};
const GpioPin ext_pa6_gpio = {GPIOA, GPIO_PIN_6};
const GpioPin ext_pa7_gpio = {GPIOA, GPIO_PIN_7};
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 };

View File

@ -16,7 +16,7 @@ extern "C" {
#define POWER_I2C_SDA_GPIO_Port GPIOA
#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,
* rise time = 0ns, fall time = 0ns
*/
@ -53,20 +53,27 @@ typedef struct {
extern const InputPin input_pins[];
extern const size_t input_pins_count;
extern const GpioPin sd_cs_gpio;
extern const GpioPin vibro_gpio;
extern const GpioPin ibutton_gpio;
extern const GpioPin cc1101_g0_gpio;
// external gpio's
extern const GpioPin ext_pc0_gpio;
extern const GpioPin ext_pc1_gpio;
extern const GpioPin ext_pc3_gpio;
extern const GpioPin ext_pb2_gpio;
extern const GpioPin ext_pb3_gpio;
extern const GpioPin ext_pa4_gpio;
extern const GpioPin ext_pa6_gpio;
extern const GpioPin ext_pa7_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
}

View File

@ -16,25 +16,21 @@ bool hal_sd_detect(void) {
bool result = false;
// TODO open record
const GpioPin* sd_cs_record = &sd_cs_gpio;
// TODO: SPI manager
api_hal_spi_lock(sd_fast_spi.spi);
const ApiHalSpiDevice* device = api_hal_spi_device_get(ApiHalSpiDeviceIdSdCard);
// configure pin as input
gpio_init_ex(sd_cs_record, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh);
gpio_init_ex(device->chip_select, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh);
delay(1);
// if gpio_read == 0 return true else return false
result = !gpio_read(sd_cs_record);
result = !gpio_read(device->chip_select);
// configure pin back
gpio_init_ex(sd_cs_record, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
gpio_write(sd_cs_record, 1);
gpio_init_ex(device->chip_select, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
gpio_write(device->chip_select, 1);
delay(1);
// TODO: SPI manager
api_hal_spi_unlock(sd_fast_spi.spi);
api_hal_spi_device_return(device);
return result;
}

View File

@ -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_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)
*/
const SPIDevice sd_fast_spi = {
.spi = &SPI_D,
.bus= &spi_d,
.config = {
.Mode = SPI_MODE_MASTER,
.Direction = SPI_DIRECTION_2LINES,
@ -29,7 +104,7 @@ const SPIDevice sd_fast_spi = {
* SD Card in slow mode (before init)
*/
const SPIDevice sd_slow_spi = {
.spi = &SPI_D,
.bus= &spi_d,
.config = {
.Mode = SPI_MODE_MASTER,
.Direction = SPI_DIRECTION_2LINES,
@ -45,24 +120,3 @@ const SPIDevice sd_slow_spi = {
.CRCLength = SPI_CRC_LENGTH_DATASIZE,
.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,
}};

View File

@ -1,17 +1,66 @@
#pragma once
#include <api-hal-gpio.h>
#include <cmsis_os2.h>
#ifdef __cplusplus
extern "C" {
#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 {
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;
} SPIDevice;
extern const SPIDevice sd_fast_spi;
extern const SPIDevice sd_slow_spi;
extern const SPIDevice display_spi;
#ifdef __cplusplus
}

View File

@ -1,36 +1,167 @@
#include "api-hal-spi.h"
#include <cmsis_os2.h>
#include <api-hal-resources.h>
#include <stdbool.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);
void api_hal_spi_init() {
spi_mutex_r = osMutexNew(NULL);
spi_mutex_d = osMutexNew(NULL);
// Spi structure is const, but mutex is not
// 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) {
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();
}
Enable_SPI(device->spi);
Enable_SPI((SPI_HandleTypeDef*)device->bus->spi);
osKernelUnlock();
}
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) {
@ -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) {
api_hal_spi_lock(device->spi);
api_hal_spi_bus_lock(device->bus);
api_hal_spi_config_device(device);
}
void api_hal_spi_unlock_device(const SPIDevice* device) {
api_hal_spi_unlock(device->spi);
}
api_hal_spi_bus_unlock(device->bus);
}

View File

@ -1,6 +1,8 @@
#pragma once
#include "main.h"
#include "api-hal-spi-config.h"
#include <api-hal-gpio.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
@ -11,15 +13,83 @@ extern "C" {
*/
void api_hal_spi_init();
/**
* Lock SPI bus
*/
void api_hal_spi_lock(SPI_HandleTypeDef* spi);
/* Bus Level API */
/**
* Unlock SPI bus
/** Lock 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

View File

@ -1,5 +1,11 @@
#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) {}

View File

@ -8,4 +8,5 @@ void api_hal_init() {
api_hal_power_init();
api_hal_light_init();
api_hal_vibro_init();
api_hal_subghz_init();
}

View File

@ -1,155 +1,103 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* <h2><center>&copy; 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
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#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);
/* 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 QUARTZ_32MHZ_IN_Pin GPIO_PIN_14
#define QUARTZ_32MHZ_IN_GPIO_Port GPIOC
#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_BACK_GPIO_Port GPIOC
#define BUTTON_BACK_Pin GPIO_PIN_13
#define BUTTON_DOWN_EXTI_IRQn EXTI1_IRQn
#define NFC_CS_Pin GPIO_PIN_4
#define NFC_CS_GPIO_Port GPIOE
#define BUTTON_RIGHT_Pin GPIO_PIN_12
#define BUTTON_RIGHT_GPIO_Port GPIOB
#define BUTTON_DOWN_GPIO_Port GPIOB
#define BUTTON_DOWN_Pin GPIO_PIN_1
#define BUTTON_LEFT_EXTI_IRQn EXTI15_10_IRQn
#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 RFID_OUT_Pin GPIO_PIN_13
#define RFID_OUT_GPIO_Port GPIOB
#define iBTN_Pin GPIO_PIN_14
#define iBTN_GPIO_Port GPIOB
#define SPI_D_MOSI_Pin GPIO_PIN_15
#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 BUTTON_RIGHT_GPIO_Port GPIOB
#define BUTTON_RIGHT_Pin GPIO_PIN_12
#define BUTTON_UP_EXTI_IRQn EXTI15_10_IRQn
#define BUTTON_UP_GPIO_Port GPIOB
#define BUTTON_UP_Pin GPIO_PIN_10
#define CC1101_CS_GPIO_Port GPIOD
#define SPI_D_SCK_Pin GPIO_PIN_1
#define SPI_D_SCK_GPIO_Port GPIOD
#define PB3_Pin GPIO_PIN_3
#define CC1101_CS_Pin GPIO_PIN_0
#define CC1101_G0_GPIO_Port GPIOC
#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 SPI_R_MISO_Pin GPIO_PIN_4
#define SPI_R_MISO_GPIO_Port GPIOB
#define SPI_R_MOSI_Pin GPIO_PIN_5
#define SPI_R_MOSI_GPIO_Port GPIOB
/* USER CODE BEGIN Private defines */
#define PB3_Pin GPIO_PIN_3
#define PC0_GPIO_Port GPIOC
#define PC0_Pin GPIO_PIN_0
#define PC1_GPIO_Port GPIOC
#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_D hspi2
@ -182,12 +130,6 @@ extern TIM_HandleTypeDef htim16;
#define NFC_IRQ_Pin RFID_PULL_Pin
#define NFC_IRQ_GPIO_Port RFID_PULL_GPIO_Port
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -23,5 +23,6 @@ void delay_us(float microseconds) {
void delay(float milliseconds) {
uint32_t ticks = milliseconds / (1000.0f / osKernelGetTickFreq());
osStatus_t result = osDelay(ticks);
(void)result;
assert(result == osOK);
}

View File

@ -20,11 +20,6 @@ void hal_gpio_init(
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;
bool get_rfid_in_level() {

View File

@ -24,6 +24,12 @@ typedef enum {
GpioModeEventRiseFall = GPIO_MODE_EVT_RISING_FALLING,
} GpioMode;
typedef enum {
GpioPullNo = GPIO_NOPULL,
GpioPullUp = GPIO_PULLUP,
GpioPullDown = GPIO_PULLDOWN,
} GpioPull;
typedef enum {
GpioSpeedLow = GPIO_SPEED_FREQ_LOW,
GpioSpeedMedium = GPIO_SPEED_FREQ_MEDIUM,
@ -31,12 +37,6 @@ typedef enum {
GpioSpeedVeryHigh = GPIO_SPEED_FREQ_VERY_HIGH,
} GpioSpeed;
typedef enum {
GpioPullNo = GPIO_NOPULL,
GpioPullUp = GPIO_PULLUP,
GpioPullDown = GPIO_PULLDOWN,
} GpioPull;
typedef struct {
GPIO_TypeDef* port;
uint16_t pin;

View File

@ -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 ibutton_gpio = {iBTN_GPIO_Port, iBTN_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 };

View File

@ -16,7 +16,7 @@ extern "C" {
#define POWER_I2C_SDA_GPIO_Port GPIOA
#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,
* rise time = 0ns, fall time = 0ns
*/
@ -57,6 +57,24 @@ extern const GpioPin vibro_gpio;
extern const GpioPin ibutton_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
}
#endif

View File

@ -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_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)
*/
const SPIDevice sd_fast_spi = {
.spi = &SPI_D,
.bus= &spi_d,
.config = {
.Mode = SPI_MODE_MASTER,
.Direction = SPI_DIRECTION_2LINES,
@ -29,7 +104,7 @@ const SPIDevice sd_fast_spi = {
* SD Card in slow mode (before init)
*/
const SPIDevice sd_slow_spi = {
.spi = &SPI_D,
.bus= &spi_d,
.config = {
.Mode = SPI_MODE_MASTER,
.Direction = SPI_DIRECTION_2LINES,
@ -45,24 +120,3 @@ const SPIDevice sd_slow_spi = {
.CRCLength = SPI_CRC_LENGTH_DATASIZE,
.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,
}};

View File

@ -1,17 +1,66 @@
#pragma once
#include <api-hal-gpio.h>
#include <cmsis_os2.h>
#ifdef __cplusplus
extern "C" {
#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 {
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;
} SPIDevice;
extern const SPIDevice sd_fast_spi;
extern const SPIDevice sd_slow_spi;
extern const SPIDevice display_spi;
#ifdef __cplusplus
}

View File

@ -1,36 +1,167 @@
#include "api-hal-spi.h"
#include <cmsis_os2.h>
#include <api-hal-resources.h>
#include <stdbool.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);
void api_hal_spi_init() {
spi_mutex_r = osMutexNew(NULL);
spi_mutex_d = osMutexNew(NULL);
// Spi structure is const, but mutex is not
// 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) {
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();
}
Enable_SPI(device->spi);
Enable_SPI((SPI_HandleTypeDef*)device->bus->spi);
osKernelUnlock();
}
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) {
@ -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) {
api_hal_spi_lock(device->spi);
api_hal_spi_bus_lock(device->bus);
api_hal_spi_config_device(device);
}
void api_hal_spi_unlock_device(const SPIDevice* device) {
api_hal_spi_unlock(device->spi);
}
api_hal_spi_bus_unlock(device->bus);
}

View File

@ -1,6 +1,8 @@
#pragma once
#include "main.h"
#include "api-hal-spi-config.h"
#include <api-hal-gpio.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
@ -11,15 +13,83 @@ extern "C" {
*/
void api_hal_spi_init();
/**
* Lock SPI bus
*/
void api_hal_spi_lock(SPI_HandleTypeDef* spi);
/* Bus Level API */
/**
* Unlock SPI bus
/** Lock 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

View File

@ -1,19 +1,181 @@
#include "api-hal-subghz.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"
void api_hal_rf_band_set(RfBand band) {
if (band == RfBand1) {
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 (band == RfBand2) {
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 (band == RfBand3) {
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 (band == RfBandIsolation) {
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_regs[][2] = {
/* Base setting */
{ CC1101_IOCFG0, 0x0D }, // 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
/* Async OOK Specific things */
{ CC1101_MDMCFG2, 0x30 }, // ASK/OOK, No preamble/sync
{ CC1101_PKTCTRL0, 0x32 }, // Async, no CRC, Infinite
{ CC1101_FREND0, 0x01 }, // OOK/ASK PATABLE
/* End */
{ 0, 0 },
};
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 {
}
}

View File

@ -8,4 +8,5 @@ void api_hal_init() {
api_hal_power_init();
api_hal_light_init();
api_hal_vibro_init();
api_hal_subghz_init();
}

View File

@ -7,6 +7,7 @@
static osThreadAttr_t platform_irq_thread_attr;
static volatile osThreadId_t platform_irq_thread_id = NULL;
static volatile PlatformIrqCallback platform_irq_callback = NULL;
static ApiHalSpiDevice* platform_st25r3916 = NULL;
void nfc_isr(void* _pin, void* _ctx) {
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 ret;
bool ret = false;
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) {
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) {
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");
exit(255);
return HAL_ERROR;
} else {
return HAL_OK;
}
return ret;
}
void platformProtectST25RComm() {
api_hal_spi_lock(&SPI_R);
NFC_SPI_Reconfigure();
furi_assert(platform_st25r3916 == NULL);
platform_st25r3916 = (ApiHalSpiDevice*)api_hal_spi_device_get(ApiHalSpiDeviceIdNfc);
}
void platformUnprotectST25RComm() {
api_hal_spi_unlock(&SPI_R);
furi_assert(platform_st25r3916);
api_hal_spi_device_return(platform_st25r3916);
platform_st25r3916 = NULL;
}

View File

@ -58,40 +58,40 @@ void platformUnprotectST25RComm();
#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 platformUnprotectST25RIrqStatus() platformUnprotectST25RComm() /*!< Unprotect the IRQ status var - IRQ enable on a single thread environment (MCU) ; Mutex unlock 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 platformLedOff( port, pin ) api_hal_light_set(pin, 0x00)
#define platformLedOn( port, pin ) api_hal_light_set(pin, 0xFF)
#define platformLedOff( port, pin ) api_hal_light_set(pin, 0x00)
#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 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 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 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 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 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 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 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 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 platformErrorHandle() Error_Handler() /*!< Global error handle\trap */
#define platformAssert( exp ) assert_param( exp ) /*!< Asserts whether the given expression is true*/
#define platformErrorHandle() Error_Handler() /*!< Global error handle\trap */
#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 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 platformI2CTx( txBuf, len, last, txOnly ) /*!< I2C Transmit */
#define platformI2CRx( txBuf, len ) /*!< I2C Receive */
#define platformI2CStart() /*!< I2C Start condition */
#define platformI2CStop() /*!< I2C Stop condition */
#define platformI2CRepeatStart() /*!< I2C Repeat Start */
#define platformI2CSlaveAddrWR(add) /*!< I2C Slave address for Write operation */
#define platformI2CSlaveAddrRD(add) /*!< I2C Slave address for Read operation */
#define platformI2CTx( txBuf, len, last, txOnly ) /*!< I2C Transmit */
#define platformI2CRx( txBuf, len ) /*!< I2C Receive */
#define platformI2CStart() /*!< I2C Start condition */
#define platformI2CStop() /*!< I2C Stop condition */
#define platformI2CRepeatStart() /*!< I2C Repeat Start */
#define platformI2CSlaveAddrWR(add) /*!< I2C Slave address for Write 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
View 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
View 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
View 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