[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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,614 +0,0 @@
|
||||
#include "cc1101.h"
|
||||
#include <furi.h>
|
||||
#include <api-hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
|
||||
#define RSSI_DELAY 5000 //rssi delay in micro second
|
||||
#define CHAN_SPA 0.05 // channel spacing
|
||||
|
||||
int16_t rssi_to_dbm(uint8_t rssi_dec, uint8_t rssiOffset) {
|
||||
int16_t rssi;
|
||||
|
||||
if(rssi_dec >= 128) {
|
||||
rssi = (int16_t)((int16_t)(rssi_dec - 256) / 2) - rssiOffset;
|
||||
} else {
|
||||
rssi = (rssi_dec / 2) - rssiOffset;
|
||||
}
|
||||
|
||||
return rssi;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
float base_freq;
|
||||
uint8_t reg[3]; // FREQ2, FREQ1, FREQ0
|
||||
uint8_t first_channel;
|
||||
uint8_t last_channel;
|
||||
uint8_t rssi_offset;
|
||||
} Band;
|
||||
|
||||
typedef struct {
|
||||
const Band* band;
|
||||
uint16_t channel;
|
||||
} FreqConfig;
|
||||
|
||||
void setup_freq(CC1101* cc1101, float freq) {
|
||||
// cc1101->SpiWriteReg(CC1101_MCSM0, 0x08); // disalbe FS_AUTOCAL
|
||||
// cc1101->SpiWriteReg(CC1101_AGCCTRL2, 0x43 | 0x0C); // MAX_DVGA_GAIN to 11 for fast rssi
|
||||
// cc1101->SpiWriteReg(CC1101_AGCCTRL0, 0xB0); // max AGC WAIT_TIME; 0 filter_length
|
||||
// cc1101->SetMod(GFSK); // set to GFSK for fast rssi measurement | +8 is dcfilter off
|
||||
|
||||
uint32_t freq_reg = freq * 1e6 / (F_OSC / 65536);
|
||||
cc1101->SetFreq((freq_reg >> 16) & 0xFF, (freq_reg >> 8) & 0xFF, (freq_reg)&0xFF);
|
||||
cc1101->SetChannel(0);
|
||||
|
||||
/*
|
||||
//set test0 to 0x09
|
||||
cc1101->SpiWriteReg(CC1101_TEST0, 0x09);
|
||||
//set FSCAL2 to 0x2A to force VCO HIGH
|
||||
cc1101->SpiWriteReg(CC1101_FSCAL2, 0x2A);
|
||||
|
||||
// perform a manual calibration by issuing SCAL command
|
||||
cc1101->SpiStrobe(CC1101_SCAL);
|
||||
*/
|
||||
}
|
||||
|
||||
static GpioPin debug_0 = {GPIOB, GPIO_PIN_2};
|
||||
|
||||
int16_t rx_rssi(CC1101* cc1101, const FreqConfig* config) {
|
||||
// cc1101->SpiStrobe(CC1101_SFRX);
|
||||
// cc1101->SetReceive();
|
||||
|
||||
// uint8_t begin_size = cc1101->SpiReadStatus(CC1101_RXBYTES);
|
||||
// uint8_t rx_status = cc1101->SpiReadStatus(CC1101_MARCSTATE);
|
||||
|
||||
// delay_us(RSSI_DELAY);
|
||||
// osDelay(15);
|
||||
|
||||
// uint8_t end_size = cc1101->SpiReadStatus(CC1101_RXBYTES);
|
||||
|
||||
// 1.4.8) read PKTSTATUS register while the radio is in RX state
|
||||
/*uint8_t _pkt_status = */ // cc1101->SpiReadStatus(CC1101_PKTSTATUS);
|
||||
|
||||
// 1.4.9) enter IDLE state by issuing a SIDLE command
|
||||
// cc1101->SpiStrobe(CC1101_SIDLE);
|
||||
|
||||
// //read rssi value and converto to dBm form
|
||||
uint8_t rssi_dec = (uint8_t)cc1101->SpiReadStatus(CC1101_RSSI);
|
||||
int16_t rssi_dBm = rssi_to_dbm(rssi_dec, config->band->rssi_offset);
|
||||
|
||||
/*
|
||||
char buf[256];
|
||||
sprintf(buf, "status: %d -> %d, rssi: %d\n", rx_status, cc1101->SpiReadStatus(CC1101_MARCSTATE), rssi_dBm);
|
||||
printf(buf);
|
||||
sprintf(buf, "begin: %d, end: %d\n", begin_size, end_size);
|
||||
printf(buf);
|
||||
*/
|
||||
|
||||
// uint8_t rx_data[64];
|
||||
// uint8_t fifo_length = end_size - begin_size;
|
||||
|
||||
/*
|
||||
if(fifo_length < 64) {
|
||||
// cc1101->SpiReadBurstReg(CC1101_RXFIFO, rx_data, fifo_length);
|
||||
|
||||
*
|
||||
printf("FIFO:");
|
||||
for(uint8_t i = 0; i < fifo_length; i++) {
|
||||
for(uint8_t bit = 0; bit < 8; bit++) {
|
||||
printf("%s", (rx_data[i] & (1 << bit)) > 0 ? "1" : "0");
|
||||
}
|
||||
printf(" ");
|
||||
}
|
||||
printf("\r\n");
|
||||
*
|
||||
|
||||
for(uint8_t i = 0; i < fifo_length; i++) {
|
||||
for(uint8_t bit = 0; bit < 8; bit++) {
|
||||
gpio_write((GpioPin*)&debug_0, (rx_data[i] & (1 << bit)) > 0);
|
||||
delay_us(5);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("fifo size over\r\n");
|
||||
}
|
||||
*/
|
||||
|
||||
return rssi_dBm;
|
||||
}
|
||||
|
||||
/*
|
||||
void flp_config(CC1101* cc1101) {
|
||||
cc1101->SpiWriteReg(
|
||||
CC1101_MCSM0, 0x18); // calibrate when going from IDLE to RX or TX ; 149 - 155 μs timeout
|
||||
// MCSM0.FS_AUTOCAL[1:0] = 1
|
||||
|
||||
cc1101->SpiWriteReg(CC1101_AGCCTRL2, 0x43);
|
||||
cc1101->SpiWriteReg(CC1101_AGCCTRL1, 0x49);
|
||||
cc1101->SpiWriteReg(CC1101_AGCCTRL0, 0x91);
|
||||
|
||||
//freq synthesizer calibration
|
||||
cc1101->SpiWriteReg(CC1101_FSCAL3, 0xEA);
|
||||
cc1101->SpiWriteReg(CC1101_FSCAL2, 0x2A);
|
||||
cc1101->SpiWriteReg(CC1101_FSCAL1, 0x00);
|
||||
cc1101->SpiWriteReg(CC1101_FSCAL0, 0x1F);
|
||||
|
||||
// async data out
|
||||
cc1101->SpiSetRegValue(CC1101_IOCFG0, 13, 5, 0); // GDO0 Output Pin Configuration
|
||||
cc1101->SpiSetRegValue(CC1101_IOCFG0, 13, 5, 0); // WAT
|
||||
|
||||
// FIFOTHR.ADC_RETENTION = 1
|
||||
cc1101->SpiSetRegValue(CC1101_FIFOTHR, 1, 6, 6);
|
||||
|
||||
// PKTCTRL1.APPEND_STATUS = 0
|
||||
cc1101->SpiSetRegValue(CC1101_PKTCTRL1, 0, 2, 2);
|
||||
|
||||
// PKTCTRL0.WHITE_DATA = 0
|
||||
cc1101->SpiSetRegValue(CC1101_PKTCTRL0, 0, 6, 6);
|
||||
|
||||
// PKTCTRL0.LENGTH_CONFIG = 2 // Infinite packet length mode
|
||||
cc1101->SpiSetRegValue(CC1101_PKTCTRL0, 2, 1, 0);
|
||||
|
||||
// PKTCTRL0.CRC_EN = 0
|
||||
cc1101->SpiSetRegValue(CC1101_PKTCTRL0, 0, 2, 2);
|
||||
|
||||
// PKTCTRL0.PKT_FORMAT = 3
|
||||
cc1101->SpiSetRegValue(CC1101_PKTCTRL0, 3, 5, 4);
|
||||
|
||||
// bandwidth 50-100 kHz
|
||||
if(!cc1101->setRxBandwidth(75.0)) {
|
||||
printf("wrong rx bw\r\n");
|
||||
}
|
||||
|
||||
// datarate ~30 kbps
|
||||
if(!cc1101->setBitRate(100.)) {
|
||||
printf("wrong bitrate\r\n");
|
||||
}
|
||||
|
||||
// mod
|
||||
// MDMCFG2.MOD_FORMAT = 3 (3: OOK, 0: 2-FSK)
|
||||
cc1101->SpiSetRegValue(CC1101_MDMCFG2, 3, 6, 4);
|
||||
// MDMCFG2.SYNC_MODE = 0
|
||||
cc1101->SpiSetRegValue(CC1101_MDMCFG2, 0, 2, 0);
|
||||
}
|
||||
*/
|
||||
|
||||
void tx_config(CC1101* cc1101) {
|
||||
// cc1101->SpiWriteReg(CC1101_IOCFG2,0x0B); //GDO2 Output Pin Configuration
|
||||
// cc1101->SpiWriteReg(CC1101_IOCFG0,0x0C); //GDO0 Output Pin Configuration
|
||||
cc1101->SpiSetRegValue(CC1101_IOCFG0, 13, 5, 0); // GDO0 Output Pin Configuration
|
||||
|
||||
cc1101->SpiWriteReg(CC1101_FIFOTHR, 0x47); //RX FIFO and TX FIFO Thresholds
|
||||
cc1101->SpiWriteReg(CC1101_PKTCTRL0, 0x32); //Packet Automation Control
|
||||
cc1101->SpiWriteReg(CC1101_FSCTRL1, 0x06); //Frequency Synthesizer Control
|
||||
cc1101->SpiWriteReg(CC1101_FREQ2, 0x10); //Frequency Control Word, High Byte
|
||||
cc1101->SpiWriteReg(CC1101_FREQ1, 0xB0); //Frequency Control Word, Middle Byte
|
||||
cc1101->SpiWriteReg(CC1101_FREQ0, 0x71); //Frequency Control Word, Low Byte
|
||||
cc1101->SpiWriteReg(CC1101_MDMCFG4, 0x6A); //Modem Configuration
|
||||
cc1101->SpiWriteReg(CC1101_MDMCFG3, 0x2E); //Modem Configuration
|
||||
cc1101->SpiWriteReg(CC1101_MDMCFG2, 0x30); //Modem Configuration
|
||||
cc1101->SpiWriteReg(CC1101_DEVIATN, 0x15); //Modem Deviation Setting
|
||||
cc1101->SpiWriteReg(CC1101_MCSM0, 0x18); //Main Radio Control State Machine Configuration
|
||||
cc1101->SpiWriteReg(CC1101_FOCCFG, 0x16); //Frequency Offset Compensation Configuration
|
||||
cc1101->SpiWriteReg(CC1101_WORCTRL, 0xFB); //Wake On Radio Control
|
||||
cc1101->SpiWriteReg(CC1101_FREND0, 0x11); //Front End TX Configuration
|
||||
cc1101->SpiWriteReg(CC1101_FSCAL3, 0xE9); //Frequency Synthesizer Calibration
|
||||
cc1101->SpiWriteReg(CC1101_FSCAL2, 0x2A); //Frequency Synthesizer Calibration
|
||||
cc1101->SpiWriteReg(CC1101_FSCAL1, 0x00); //Frequency Synthesizer Calibration
|
||||
cc1101->SpiWriteReg(CC1101_FSCAL0, 0x1F); //Frequency Synthesizer Calibration
|
||||
|
||||
/*
|
||||
cc1101->SpiWriteReg(CC1101_TEST2, 0x81); //Various Test Settings
|
||||
cc1101->SpiWriteReg(CC1101_TEST1, 0x35); //Various Test Settings
|
||||
cc1101->SpiWriteReg(CC1101_TEST0, 0x09); //Various Test Settings
|
||||
*/
|
||||
}
|
||||
|
||||
// f = (f_osc/65536) * (FREQ + CHAN * (256 + CH_SP_M) * 2^(CH_SP_E - 2))
|
||||
// FREQ = f / (f_osc/65536)
|
||||
// CHAN = 0
|
||||
// TODO: CHAN number not implemented!
|
||||
// TODO: reg values not affetcts
|
||||
|
||||
const Band bands[] = {
|
||||
{301., {0x00, 0x00, 0x00}, 0, 255, 74},
|
||||
{315., {0x00, 0x00, 0x00}, 0, 255, 74},
|
||||
{346., {0x00, 0x00, 0x00}, 0, 255, 74},
|
||||
{385., {0x00, 0x00, 0x00}, 0, 255, 74},
|
||||
{433.92, {0x00, 0x00, 0x00}, 0, 255, 74},
|
||||
{438.9, {0x00, 0x00, 0x00}, 0, 255, 74},
|
||||
{463., {0x00, 0x00, 0x00}, 0, 255, 74},
|
||||
{781., {0x00, 0x00, 0x00}, 0, 255, 74},
|
||||
{868., {0x00, 0x00, 0x00}, 0, 255, 74},
|
||||
{915., {0x00, 0x00, 0x00}, 0, 255, 74},
|
||||
{925., {0x00, 0x00, 0x00}, 0, 255, 74},
|
||||
};
|
||||
|
||||
const FreqConfig FREQ_LIST[] = {
|
||||
{&bands[0], 0},
|
||||
{&bands[1], 0},
|
||||
{&bands[2], 0},
|
||||
{&bands[3], 0},
|
||||
{&bands[4], 0},
|
||||
{&bands[5], 0},
|
||||
{&bands[6], 0},
|
||||
{&bands[7], 0},
|
||||
{&bands[8], 0},
|
||||
{&bands[9], 0},
|
||||
{&bands[10], 0},
|
||||
};
|
||||
|
||||
extern "C" void cc1101_isr(void* _pin, void* _ctx) {
|
||||
uint32_t pin = (uint32_t)_pin;
|
||||
if(pin == CC1101_G0_Pin) {
|
||||
gpio_write((GpioPin*)&debug_0, gpio_read(&cc1101_g0_gpio));
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
EventTypeTick,
|
||||
EventTypeKey,
|
||||
} EventType;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
InputEvent input;
|
||||
} value;
|
||||
EventType type;
|
||||
} AppEvent;
|
||||
|
||||
typedef enum { ModeRx, ModeTx } Mode;
|
||||
|
||||
typedef struct {
|
||||
int16_t dbm;
|
||||
uint8_t reg;
|
||||
} TxLevel;
|
||||
|
||||
const TxLevel TX_LEVELS[] = {
|
||||
{-10, 0},
|
||||
{-5, 0},
|
||||
{0, 0},
|
||||
{5, 0},
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Mode mode;
|
||||
size_t active_freq_idx;
|
||||
float active_freq;
|
||||
int16_t last_rssi;
|
||||
size_t tx_level;
|
||||
bool need_cc1101_conf;
|
||||
RfBand rf_band;
|
||||
} State;
|
||||
|
||||
static void render_callback(Canvas* canvas, void* ctx) {
|
||||
State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25);
|
||||
|
||||
if(!state) return;
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 2, 12, "cc1101 workaround");
|
||||
|
||||
{
|
||||
char buf[24];
|
||||
sprintf(
|
||||
buf,
|
||||
"freq: %ld.%02ld MHz",
|
||||
(uint32_t)state->active_freq,
|
||||
(uint32_t)(state->active_freq * 100.) % 100);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 25, buf);
|
||||
}
|
||||
|
||||
{
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
if(state->need_cc1101_conf) {
|
||||
canvas_draw_str(canvas, 2, 36, "mode: configuring...");
|
||||
} else if(state->mode == ModeRx) {
|
||||
canvas_draw_str(canvas, 2, 36, "mode: RX");
|
||||
} else if(state->mode == ModeTx) {
|
||||
canvas_draw_str(canvas, 2, 36, "mode: TX");
|
||||
} else {
|
||||
canvas_draw_str(canvas, 2, 36, "mode: unknown");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if(!state->need_cc1101_conf && state->mode == ModeRx) {
|
||||
char buf[24];
|
||||
sprintf(buf, "RSSI: %d dBm", state->last_rssi);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 48, buf);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char buf[24];
|
||||
// sprintf(buf, "tx level: %d dBm", TX_LEVELS[state->tx_level].dbm);
|
||||
sprintf(buf, "RF band: %d", (uint8_t)state->rf_band);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
if(state->rf_band == RfBandIsolation) {
|
||||
canvas_draw_str(canvas, 2, 63, "RF band: isolation");
|
||||
} else {
|
||||
canvas_draw_str(canvas, 2, 63, buf);
|
||||
}
|
||||
}
|
||||
|
||||
release_mutex((ValueMutex*)ctx, state);
|
||||
}
|
||||
|
||||
static void input_callback(InputEvent* input_event, void* ctx) {
|
||||
osMessageQueueId_t event_queue = ctx;
|
||||
|
||||
AppEvent event;
|
||||
event.type = EventTypeKey;
|
||||
event.value.input = *input_event;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
}
|
||||
|
||||
extern "C" int32_t cc1101_workaround(void* p) {
|
||||
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL);
|
||||
furi_check(event_queue);
|
||||
|
||||
State _state;
|
||||
_state.mode = ModeRx;
|
||||
_state.active_freq_idx = 4;
|
||||
|
||||
FreqConfig conf = FREQ_LIST[_state.active_freq_idx];
|
||||
_state.active_freq = conf.band->base_freq + CHAN_SPA * conf.channel;
|
||||
|
||||
_state.need_cc1101_conf = true;
|
||||
_state.last_rssi = 0;
|
||||
_state.tx_level = 0;
|
||||
_state.rf_band = RfBand1;
|
||||
|
||||
ValueMutex state_mutex;
|
||||
if(!init_mutex(&state_mutex, &_state, sizeof(State))) {
|
||||
printf("[cc1101] cannot create mutex\r\n");
|
||||
return 255;
|
||||
}
|
||||
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
|
||||
view_port_draw_callback_set(view_port, render_callback, &state_mutex);
|
||||
view_port_input_callback_set(view_port, input_callback, event_queue);
|
||||
|
||||
// Open GUI and register view_port
|
||||
Gui* gui = (Gui*)furi_record_open("gui");
|
||||
if(gui == NULL) {
|
||||
printf("[cc1101] gui is not available\r\n");
|
||||
return 255;
|
||||
}
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
gpio_init(&debug_0, GpioModeOutputPushPull);
|
||||
gpio_write((GpioPin*)&debug_0, false);
|
||||
|
||||
printf("[cc1101] creating device\r\n");
|
||||
GpioPin cs_pin = {CC1101_CS_GPIO_Port, CC1101_CS_Pin};
|
||||
|
||||
gpio_init(&cc1101_g0_gpio, GpioModeInput);
|
||||
api_interrupt_add(cc1101_isr, InterruptTypeExternalInterrupt, NULL);
|
||||
// TODO open record
|
||||
GpioPin* cs_pin_record = &cs_pin;
|
||||
CC1101 cc1101(cs_pin_record);
|
||||
printf("[cc1101] init device\r\n");
|
||||
|
||||
uint8_t address = cc1101.Init();
|
||||
if(address > 0) {
|
||||
printf("[cc1101] init done: %d\r\n", address);
|
||||
} else {
|
||||
printf("[cc1101] init fail\r\n");
|
||||
return 255;
|
||||
}
|
||||
|
||||
cc1101.SpiStrobe(CC1101_SIDLE);
|
||||
|
||||
// flp_config(&cc1101);
|
||||
tx_config(&cc1101);
|
||||
// setup_freq(&cc1101, &FREQ_LIST[4]);
|
||||
// enable_cc1101_irq();
|
||||
|
||||
printf("init ok\r\n");
|
||||
|
||||
const int16_t RSSI_THRESHOLD = -60;
|
||||
|
||||
// setup_freq(&cc1101, &FREQ_LIST[1]);
|
||||
|
||||
cc1101.SetReceive();
|
||||
|
||||
AppEvent event;
|
||||
while(1) {
|
||||
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 100);
|
||||
State* state = (State*)acquire_mutex_block(&state_mutex);
|
||||
|
||||
if(event_status == osOK) {
|
||||
if(event.type == EventTypeKey) {
|
||||
if(event.value.input.type == InputTypeShort &&
|
||||
event.value.input.key == InputKeyBack) {
|
||||
printf("[cc1101] bye!\r\n");
|
||||
|
||||
cc1101.SpiStrobe(CC1101_SIDLE);
|
||||
cc1101.SpiStrobe(CC1101_SPWD);
|
||||
|
||||
printf("[cc1101] go to power down\r\n");
|
||||
|
||||
// TODO remove all view_ports create by app
|
||||
view_port_enabled_set(view_port, false);
|
||||
return 255;
|
||||
}
|
||||
|
||||
if(event.value.input.type == InputTypeShort &&
|
||||
event.value.input.key == InputKeyDown) {
|
||||
if(state->active_freq_idx > 0) {
|
||||
state->active_freq_idx--;
|
||||
}
|
||||
|
||||
FreqConfig conf = FREQ_LIST[state->active_freq_idx];
|
||||
state->active_freq = conf.band->base_freq + CHAN_SPA * conf.channel;
|
||||
state->need_cc1101_conf = true;
|
||||
}
|
||||
|
||||
if(event.value.input.type == InputTypeShort &&
|
||||
event.value.input.key == InputKeyUp) {
|
||||
if(state->active_freq_idx < (sizeof(FREQ_LIST) / sizeof(FREQ_LIST[0]) - 1)) {
|
||||
state->active_freq_idx++;
|
||||
}
|
||||
|
||||
FreqConfig conf = FREQ_LIST[state->active_freq_idx];
|
||||
state->active_freq = conf.band->base_freq + CHAN_SPA * conf.channel;
|
||||
state->need_cc1101_conf = true;
|
||||
}
|
||||
|
||||
if(event.value.input.type == InputTypeShort &&
|
||||
event.value.input.key == InputKeyRight) {
|
||||
/*
|
||||
if(state->tx_level < (sizeof(TX_LEVELS) / sizeof(TX_LEVELS[0]) - 1)) {
|
||||
state->tx_level++;
|
||||
} else {
|
||||
state->tx_level = 0;
|
||||
}
|
||||
*/
|
||||
|
||||
if(state->rf_band < RfBand3) {
|
||||
state->rf_band = (RfBand)((uint8_t)state->rf_band + 1);
|
||||
} else {
|
||||
state->active_freq += 0.25;
|
||||
}
|
||||
state->need_cc1101_conf = true;
|
||||
}
|
||||
|
||||
if(event.value.input.type == InputTypeShort &&
|
||||
event.value.input.key == InputKeyLeft) {
|
||||
/*
|
||||
if(state->tx_level < (sizeof(TX_LEVELS) / sizeof(TX_LEVELS[0]) - 1)) {
|
||||
state->tx_level++;
|
||||
} else {
|
||||
state->tx_level = 0;
|
||||
}
|
||||
*/
|
||||
|
||||
if(state->rf_band > RfBandIsolation) {
|
||||
state->rf_band = (RfBand)((uint8_t)state->rf_band - 1);
|
||||
} else {
|
||||
state->active_freq -= 0.25;
|
||||
}
|
||||
state->need_cc1101_conf = true;
|
||||
}
|
||||
|
||||
if(event.value.input.key == InputKeyOk) {
|
||||
if(event.value.input.type == InputTypePress) {
|
||||
state->mode = ModeTx;
|
||||
state->need_cc1101_conf = true;
|
||||
} else if(event.value.input.type == InputTypeRelease) {
|
||||
state->mode = ModeRx;
|
||||
state->need_cc1101_conf = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
if(state->need_cc1101_conf) {
|
||||
if(state->mode == ModeRx) {
|
||||
cc1101.SpiStrobe(CC1101_SIDLE);
|
||||
gpio_init(&cc1101_g0_gpio, GpioModeInput);
|
||||
|
||||
setup_freq(&cc1101, state->active_freq);
|
||||
cc1101.SetReceive();
|
||||
|
||||
state->last_rssi = rx_rssi(&cc1101, &FREQ_LIST[state->active_freq_idx]);
|
||||
} else if(state->mode == ModeTx) {
|
||||
cc1101.SpiStrobe(CC1101_SIDLE);
|
||||
|
||||
setup_freq(&cc1101, state->active_freq);
|
||||
cc1101.SetTransmit();
|
||||
gpio_init(&cc1101_g0_gpio, GpioModeOutputPushPull);
|
||||
gpio_write(&cc1101_g0_gpio, false);
|
||||
}
|
||||
|
||||
api_hal_rf_band_set(state->rf_band);
|
||||
|
||||
state->need_cc1101_conf = false;
|
||||
}
|
||||
|
||||
if(!state->need_cc1101_conf && state->mode == ModeRx) {
|
||||
// TOOD what about rssi offset
|
||||
state->last_rssi = rx_rssi(&cc1101, &FREQ_LIST[state->active_freq_idx]);
|
||||
|
||||
api_hal_light_set(LightGreen, state->last_rssi > RSSI_THRESHOLD ? 0xFF : 0x00);
|
||||
} else if(!state->need_cc1101_conf && state->mode == ModeTx) {
|
||||
/*
|
||||
const uint8_t data = 0xA5;
|
||||
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
gpio_write(&cc1101_g0_gpio, (data & (1 << i)) > 0);
|
||||
osDelay(1);
|
||||
}
|
||||
gpio_write(&cc1101_g0_gpio, false);
|
||||
*/
|
||||
|
||||
/*
|
||||
// BELL UDB-Q022-0000
|
||||
const uint16_t HALF_PERIOD = 500;
|
||||
|
||||
for(uint8_t n = 0; n < 4; n++) {
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
gpio_write(&cc1101_g0_gpio, true);
|
||||
delay_us(3 * HALF_PERIOD);
|
||||
gpio_write(&cc1101_g0_gpio, false);
|
||||
delay_us(HALF_PERIOD);
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < 40; i++) {
|
||||
gpio_write(&cc1101_g0_gpio, true);
|
||||
delay_us(HALF_PERIOD);
|
||||
gpio_write(&cc1101_g0_gpio, false);
|
||||
delay_us(HALF_PERIOD);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// BELL ERA C61, static code
|
||||
const uint16_t ONE_ON = 150;
|
||||
const uint16_t ONE_OFF = 400;
|
||||
const uint16_t ZERO_ON = 420;
|
||||
const uint16_t ZERO_OFF = 130;
|
||||
|
||||
const bool SEQ[] = {true, true, false, false, true, false, true, false, true,
|
||||
false, true, true, true, false, true, false, true, true,
|
||||
true, true, true, false, true, false, true};
|
||||
|
||||
for(uint8_t n = 0; n < 10; n++) {
|
||||
for(uint8_t i = 0; i < sizeof(SEQ) / sizeof(SEQ[0]); i++) {
|
||||
if(SEQ[i]) {
|
||||
gpio_write(&cc1101_g0_gpio, false);
|
||||
delay_us(ONE_ON);
|
||||
gpio_write(&cc1101_g0_gpio, true);
|
||||
delay_us(ONE_OFF);
|
||||
} else {
|
||||
gpio_write(&cc1101_g0_gpio, false);
|
||||
delay_us(ZERO_ON);
|
||||
gpio_write(&cc1101_g0_gpio, true);
|
||||
delay_us(ZERO_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
osDelay(4);
|
||||
}
|
||||
|
||||
gpio_write(&cc1101_g0_gpio, false);
|
||||
}
|
||||
|
||||
release_mutex(&state_mutex, state);
|
||||
view_port_update(view_port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,485 +0,0 @@
|
||||
#include <furi.h>
|
||||
#include <api-hal.h>
|
||||
|
||||
#include "cc1101-workaround/cc1101.h"
|
||||
#include "spi.h"
|
||||
#include <math.h>
|
||||
|
||||
// ******************************************************************************
|
||||
#define WRITE_BURST 0x40
|
||||
#define READ_SINGLE 0x80
|
||||
#define READ_BURST 0xC0
|
||||
#define BYTES_IN_FIFO 0x7F //used to detect FIFO underflow or overflow
|
||||
|
||||
/*********************ss_pin as global variable****************************** */
|
||||
/* cc1101 */
|
||||
/******************************************************************************/
|
||||
GpioPin ss_pin;
|
||||
|
||||
CC1101::CC1101(GpioPin* ss_pin) {
|
||||
/*
|
||||
pinMode(gdo0_pin, OUTPUT); //GDO0 as asynchronous serial mode input
|
||||
pinMode(gdo2_pin, INPUT); //GDO2 as asynchronous serial mode output
|
||||
*/
|
||||
gpio_init(ss_pin, GpioModeOutputPushPull);
|
||||
this->ss_pin = ss_pin;
|
||||
|
||||
// TODO open record
|
||||
this->miso_pin = MISO_PIN;
|
||||
this->miso_pin_record = &this->miso_pin;
|
||||
}
|
||||
//******************************************************************************
|
||||
//SpiInit
|
||||
/******************************************************************************/
|
||||
extern SPI_HandleTypeDef SPI_R;
|
||||
void CC1101::SpiInit(void) {
|
||||
//initialize spi pins
|
||||
|
||||
//Enable spi master, MSB, SPI mode 0, FOSC/4
|
||||
SpiMode(0);
|
||||
|
||||
CC1101_SPI_Reconfigure();
|
||||
}
|
||||
|
||||
void CC1101::SpiEnd(void) {
|
||||
/*
|
||||
SPCR = ((0<<SPE) | // SPI Enable
|
||||
(0<<SPIE)| // SPI Interupt Enable
|
||||
(0<<DORD)| // Data Order (0:MSB first / 1:LSB first)
|
||||
(1<<MSTR)| // Master/Slave select
|
||||
(0<<SPR1)|(0<<SPR0)| // SPI Clock Rate ( 0 0 = osc/4; 0 1 = osc/16; 1 0 = osc/64; 1 1= 0sc/128)
|
||||
(0<<CPOL)| // Clock Polarity (0:SCK low / 1:SCK hi when idle)
|
||||
(0<<CPHA)); // Clock Phase (0:leading / 1:trailing edge sampling)
|
||||
|
||||
//SPSR = (0<<SPI2X); // Double Clock Rate
|
||||
*/
|
||||
}
|
||||
/******************************************************************************
|
||||
Function: SpiMode
|
||||
*INPUT : config mode
|
||||
(0<<CPOL) | (0 << CPHA) 0
|
||||
(0<<CPOL) | (1 << CPHA) 1
|
||||
(1<<CPOL) | (0 << CPHA) 2
|
||||
(1<<CPOL) | (1 << CPHA) 3
|
||||
*OUTPUT :none
|
||||
******************************************************************************/
|
||||
void CC1101::SpiMode(uint8_t config) {
|
||||
/*
|
||||
uint8_t tmp;
|
||||
// enable SPI master with configuration byte specified
|
||||
SPCR = 0;
|
||||
SPCR = (config & 0x7F) | (1<<SPE) | (1<<MSTR);
|
||||
tmp = SPSR;
|
||||
tmp = SPDR;
|
||||
*/
|
||||
}
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:SpiTransfer
|
||||
*FUNCTION :spi transfer
|
||||
*INPUT :value: data to send
|
||||
*OUTPUT :data to receive
|
||||
****************************************************************/
|
||||
uint8_t CC1101::SpiTransfer(uint8_t value) {
|
||||
uint8_t buf[1] = {value};
|
||||
uint8_t rxbuf[1] = {0};
|
||||
|
||||
HAL_SPI_TransmitReceive(&SPI_R, buf, rxbuf, 1, HAL_MAX_DELAY);
|
||||
|
||||
return rxbuf[0];
|
||||
}
|
||||
|
||||
uint8_t last_status;
|
||||
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:SpiWriteReg
|
||||
*FUNCTION :CC1101 write data to register
|
||||
*INPUT :addr: register address; value: register value
|
||||
*OUTPUT :none
|
||||
****************************************************************/
|
||||
void CC1101::SpiWriteReg(uint8_t addr, uint8_t value) {
|
||||
gpio_write(ss_pin, false);
|
||||
while(gpio_read(this->miso_pin_record))
|
||||
;
|
||||
|
||||
last_status = SpiTransfer(addr);
|
||||
last_status = SpiTransfer(value);
|
||||
gpio_write(ss_pin, true);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:SpiWriteBurstReg
|
||||
*FUNCTION :CC1101 write burst data to register
|
||||
*INPUT :addr: register address; buffer:register value array; num:number to write
|
||||
*OUTPUT :none
|
||||
****************************************************************/
|
||||
void CC1101::SpiWriteBurstReg(uint8_t addr, uint8_t* buffer, uint8_t num) {
|
||||
gpio_write(ss_pin, false);
|
||||
while(gpio_read(this->miso_pin_record))
|
||||
;
|
||||
last_status = SpiTransfer(addr | WRITE_BURST);
|
||||
for(uint8_t i = 0; i < num; i++) {
|
||||
last_status = SpiTransfer(buffer[i]);
|
||||
}
|
||||
gpio_write(ss_pin, true);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:SpiStrobe
|
||||
*FUNCTION :CC1101 Strobe
|
||||
*INPUT :strobe: command; //refer define in CC1101.h//
|
||||
*OUTPUT :none
|
||||
****************************************************************/
|
||||
void CC1101::SpiStrobe(uint8_t strobe) {
|
||||
gpio_write(ss_pin, false);
|
||||
while(gpio_read(this->miso_pin_record))
|
||||
;
|
||||
last_status = SpiTransfer(strobe);
|
||||
gpio_write(ss_pin, true);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:SpiReadReg
|
||||
*FUNCTION :CC1101 read data from register
|
||||
*INPUT :addr: register address
|
||||
*OUTPUT :register value
|
||||
****************************************************************/
|
||||
uint8_t CC1101::SpiReadReg(uint8_t addr) {
|
||||
gpio_write(ss_pin, false);
|
||||
while(gpio_read(this->miso_pin_record))
|
||||
;
|
||||
last_status = SpiTransfer(addr | READ_SINGLE);
|
||||
uint8_t value = SpiTransfer(0);
|
||||
gpio_write(ss_pin, true);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:SpiReadBurstReg
|
||||
*FUNCTION :CC1101 read burst data from register
|
||||
*INPUT :addr: register address; buffer:array to store register value; num: number to read
|
||||
*OUTPUT :none
|
||||
****************************************************************/
|
||||
void CC1101::SpiReadBurstReg(uint8_t addr, uint8_t* buffer, uint8_t num) {
|
||||
gpio_write(ss_pin, false);
|
||||
while(gpio_read(this->miso_pin_record))
|
||||
;
|
||||
last_status = SpiTransfer(addr | READ_BURST);
|
||||
for(uint8_t i = 0; i < num; i++) {
|
||||
buffer[i] = SpiTransfer(0);
|
||||
}
|
||||
gpio_write(ss_pin, true);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:SpiReadStatus
|
||||
*FUNCTION :CC1101 read status register
|
||||
*INPUT :addr: register address
|
||||
*OUTPUT :status value
|
||||
****************************************************************/
|
||||
uint8_t CC1101::SpiReadStatus(uint8_t addr) {
|
||||
gpio_write(ss_pin, false);
|
||||
while(gpio_read(this->miso_pin_record))
|
||||
;
|
||||
last_status = SpiTransfer(addr | READ_BURST);
|
||||
uint8_t value = SpiTransfer(0);
|
||||
gpio_write(ss_pin, true);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:Reset
|
||||
*FUNCTION :CC1101 reset //details refer datasheet of CC1101/CC1100//
|
||||
*INPUT :none
|
||||
*OUTPUT :none
|
||||
****************************************************************/
|
||||
void CC1101::Reset(void) {
|
||||
gpio_write(ss_pin, false);
|
||||
delay(1);
|
||||
gpio_write(ss_pin, true);
|
||||
delay(1);
|
||||
gpio_write(ss_pin, false);
|
||||
while(gpio_read(this->miso_pin_record))
|
||||
;
|
||||
last_status = SpiTransfer(CC1101_SRES);
|
||||
while(gpio_read(this->miso_pin_record))
|
||||
;
|
||||
gpio_write(ss_pin, true);
|
||||
}
|
||||
|
||||
bool CC1101::SpiSetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb) {
|
||||
if((msb > 7) || (lsb > 7) || (lsb > msb)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t current_value = SpiReadReg(reg);
|
||||
uint8_t mask = ~((0b11111111 << (msb + 1)) | (0b11111111 >> (8 - lsb)));
|
||||
uint8_t new_value = (current_value & ~mask) | (value & mask);
|
||||
SpiWriteReg(reg, new_value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:Init
|
||||
*FUNCTION :CC1101 initialization
|
||||
*INPUT :none
|
||||
*OUTPUT :none
|
||||
****************************************************************/
|
||||
uint8_t CC1101::Init(void) {
|
||||
#ifdef CC1101_DEBUG
|
||||
printf("Init SPI...\r\n");
|
||||
#endif
|
||||
SpiInit(); //spi initialization
|
||||
gpio_write(ss_pin, true);
|
||||
// gpio_write(SCK_PIN, true);
|
||||
// gpio_write(MOSI_PIN, false);
|
||||
#ifdef CC1101_DEBUG
|
||||
printf("Reset CC1101...\r\n");
|
||||
#endif
|
||||
Reset(); // CC1101 reset
|
||||
|
||||
osDelay(150);
|
||||
|
||||
uint8_t partnum __attribute__((unused));
|
||||
uint8_t version;
|
||||
partnum = SpiReadStatus(CC1101_PARTNUM);
|
||||
version = SpiReadStatus(CC1101_VERSION);
|
||||
|
||||
#ifdef CC1101_DEBUG
|
||||
|
||||
printf("Partnum:0x%02X, Version:0x%02X\n", partnum, version);
|
||||
#endif
|
||||
|
||||
#ifdef CC1101_DEBUG
|
||||
printf("Init CC1101...");
|
||||
#endif
|
||||
// RegConfigSettings(); //CC1101 register config
|
||||
|
||||
#ifdef CC1101_DEBUG
|
||||
printf("Done!\r\n");
|
||||
#endif
|
||||
|
||||
return version;
|
||||
}
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:SetMod
|
||||
*FUNCTION :CC1101 modulation type
|
||||
*INPUT :byte mode
|
||||
*OUTPUT :none
|
||||
****************************************************************/
|
||||
void CC1101::SetMod(uint8_t mode) {
|
||||
SpiWriteReg(CC1101_MDMCFG2, mode); //no sync/preamble; ASK/OOK only support up to -1dbm
|
||||
if((mode | 0x30) == ASK) {
|
||||
SpiWriteReg(CC1101_FREND0, 0x11); //use first up to PATABLE(0)
|
||||
uint8_t PaTabel[8] = {0x00, POWER, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
SpiWriteBurstReg(CC1101_PATABLE, PaTabel, 8); //CC1101 PATABLE config
|
||||
} else {
|
||||
SpiWriteReg(CC1101_FREND0, 0x10); //use first up to PATABLE(0)
|
||||
uint8_t PaTabel[8] = {POWER, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
SpiWriteBurstReg(CC1101_PATABLE, PaTabel, 8); //CC1101 PATABLE config
|
||||
}
|
||||
|
||||
#ifdef CC1101_DEBUG
|
||||
switch(mode | 0x30) {
|
||||
case GFSK: {
|
||||
printf("CC1101 Modulation: GFSK");
|
||||
break;
|
||||
}
|
||||
case MSK: {
|
||||
printf("CC1101 Modulation: MSK");
|
||||
break;
|
||||
}
|
||||
case ASK: {
|
||||
printf("CC1101 Modulation: ASK/OOK");
|
||||
break;
|
||||
}
|
||||
case FSK2: {
|
||||
printf("CC1101 Modulation: 2-FSK");
|
||||
break;
|
||||
}
|
||||
case FSK4: {
|
||||
printf("CC1101 Modulation: 4-FSK");
|
||||
break;
|
||||
}
|
||||
default: //default to GFSK
|
||||
{
|
||||
printf("Modulation mode not supported");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\r\n");
|
||||
#endif
|
||||
}
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:RegConfigSettings
|
||||
*FUNCTION :CC1101 register config //details refer datasheet of CC1101/CC1100//
|
||||
*INPUT :none
|
||||
*OUTPUT :none
|
||||
****************************************************************/
|
||||
void CC1101::RegConfigSettings(void) {
|
||||
SpiWriteReg(CC1101_FSCTRL1, 0x06); //IF frequency
|
||||
SpiWriteReg(CC1101_FSCTRL0, 0x00); //frequency offset before synthesizer
|
||||
|
||||
SpiWriteReg(CC1101_MDMCFG4, 0xCC); // RX filter bandwidth 100k(0xcc)
|
||||
SpiWriteReg(
|
||||
CC1101_MDMCFG3, 0x43); //datarate config 512kBaud for the purpose of fast rssi measurement
|
||||
SpiWriteReg(CC1101_MDMCFG1, 0x21); //FEC preamble etc. last 2 bits for channel spacing
|
||||
SpiWriteReg(CC1101_MDMCFG0, 0xF8); //100khz channel spacing
|
||||
//CC1101_CHANNR moved to SetChannel func
|
||||
|
||||
//SpiWriteReg(CC1101_DEVIATN, 0x47);
|
||||
SpiWriteReg(
|
||||
CC1101_MCSM0, 0x18); // calibrate when going from IDLE to RX or TX ; 149 - 155 μs timeout
|
||||
SpiWriteReg(CC1101_FOCCFG, 0x16); //frequency compensation
|
||||
//SpiWriteReg(CC1101_BSCFG, 0x1C); //bit synchronization config
|
||||
SpiWriteReg(CC1101_AGCCTRL2, 0x43);
|
||||
SpiWriteReg(CC1101_AGCCTRL1, 0x49);
|
||||
SpiWriteReg(CC1101_AGCCTRL0, 0x91);
|
||||
//freq synthesizer calibration
|
||||
SpiWriteReg(CC1101_FSCAL3, 0xEA);
|
||||
SpiWriteReg(CC1101_FSCAL2, 0x2A);
|
||||
SpiWriteReg(CC1101_FSCAL1, 0x00);
|
||||
SpiWriteReg(CC1101_FSCAL0, 0x1F);
|
||||
SpiWriteReg(CC1101_TEST2, 0x81);
|
||||
SpiWriteReg(CC1101_TEST1, 0x35);
|
||||
SpiWriteReg(CC1101_TEST0, 0x0B); //should be 0x0B for lower than 430.6MHz and 0x09 for higher
|
||||
|
||||
//SpiWriteReg(CC1101_FREND1, 0x56);
|
||||
|
||||
//SpiWriteReg(CC1101_IOCFG2, 0x0B); //serial clock.synchronous to the data in synchronous serial mode
|
||||
//SpiWriteReg(CC1101_IOCFG0, 0x06); //asserts when sync word has been sent/received, and de-asserts at the end of the packet
|
||||
SpiWriteReg(CC1101_IOCFG2, 0x0D); //data output pin for asynchronous mode
|
||||
SpiWriteReg(
|
||||
CC1101_IOCFG0,
|
||||
0x2E); //High impedance (3-state), GDO0 configed as data input for asynchronous mode
|
||||
//SpiWriteReg(CC1101_PKTCTRL0, 0x05); //whitening off;CRC Enable;variable length packets, packet length configured by the first byte after sync word
|
||||
SpiWriteReg(
|
||||
CC1101_PKTCTRL0, 0x33); //whitening off; asynchronous serial mode; CRC diable;reserved
|
||||
//SpiWriteReg(CC1101_PKTLEN, 0x3D); //61 bytes max length
|
||||
SpiWriteReg(
|
||||
CC1101_FIFOTHR,
|
||||
0x47); //Adc_retention enabled for RX filter bandwidth less than 325KHz; defalut fifo threthold.
|
||||
}
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:SetFreq
|
||||
*FUNCTION :SetFreq
|
||||
*INPUT :Freq2, Freq1, Freq0
|
||||
*OUTPUT :none
|
||||
****************************************************************/
|
||||
void CC1101::SetFreq(uint8_t freq2, uint8_t freq1, uint8_t freq0) {
|
||||
SpiWriteReg(CC1101_FREQ2, freq2);
|
||||
SpiWriteReg(CC1101_FREQ1, freq1);
|
||||
SpiWriteReg(CC1101_FREQ0, freq0);
|
||||
}
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:SetChannel
|
||||
*FUNCTION :SetChannel
|
||||
*INPUT :int channel
|
||||
*OUTPUT :none
|
||||
****************************************************************/
|
||||
void CC1101::SetChannel(int channel) {
|
||||
#ifdef CC1101_DEBUG
|
||||
printf("Set CC1101 channel to: %d \n", channel);
|
||||
#endif
|
||||
SpiWriteReg(CC1101_CHANNR, (uint8_t)channel); //related to channel numbers
|
||||
}
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:SetReceive
|
||||
*FUNCTION :SetReceive
|
||||
*INPUT :none
|
||||
*OUTPUT :none
|
||||
****************************************************************/
|
||||
void CC1101::SetReceive(void) {
|
||||
SpiStrobe(CC1101_SRX);
|
||||
while(SpiReadStatus(CC1101_MARCSTATE) ^ CC1101_STATUS_RX) {
|
||||
// delay(1);
|
||||
// printf("wait status\r\n");
|
||||
}
|
||||
}
|
||||
/****************************************************************
|
||||
*FUNCTION NAME:SetTransmit
|
||||
*FUNCTION :
|
||||
*INPUT :none
|
||||
*OUTPUT :none
|
||||
****************************************************************/
|
||||
void CC1101::SetTransmit(void) {
|
||||
SpiStrobe(CC1101_STX);
|
||||
while(SpiReadStatus(CC1101_MARCSTATE) ^ CC1101_STATUS_TX)
|
||||
;
|
||||
}
|
||||
//cc1101 cc1101;
|
||||
|
||||
bool CC1101::setRxBandwidth(float bandwidth) {
|
||||
if(bandwidth < 58.0 || bandwidth > 821.0) return false;
|
||||
|
||||
// set mode to standby
|
||||
SpiStrobe(CC1101_SIDLE);
|
||||
|
||||
// calculate exponent and mantissa values
|
||||
for(int8_t e = 3; e >= 0; e--) {
|
||||
for(int8_t m = 3; m >= 0; m--) {
|
||||
float point = (F_OSC) / (8 * (m + 4) * ((uint32_t)1 << e));
|
||||
if(fabs((bandwidth * 1000.0) - point) <= 1000) {
|
||||
// set Rx channel filter bandwidth
|
||||
SpiSetRegValue(CC1101_MDMCFG4, (e << 6) | (m << 4), 7, 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void getExpMant(
|
||||
float target,
|
||||
uint16_t mantOffset,
|
||||
uint8_t divExp,
|
||||
uint8_t expMax,
|
||||
uint8_t& exp,
|
||||
uint8_t& mant) {
|
||||
// get table origin point (exp = 0, mant = 0)
|
||||
float origin = (mantOffset * F_OSC) / ((uint32_t)1 << divExp);
|
||||
|
||||
// iterate over possible exponent values
|
||||
for(int8_t e = expMax; e >= 0; e--) {
|
||||
// get table column start value (exp = e, mant = 0);
|
||||
float intervalStart = ((uint32_t)1 << e) * origin;
|
||||
|
||||
// check if target value is in this column
|
||||
if(target >= intervalStart) {
|
||||
// save exponent value
|
||||
exp = e;
|
||||
|
||||
// calculate size of step between table rows
|
||||
float stepSize = intervalStart / (float)mantOffset;
|
||||
|
||||
// get target point position (exp = e, mant = m)
|
||||
mant = ((target - intervalStart) / stepSize);
|
||||
|
||||
// we only need the first match, terminate
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CC1101::setBitRate(float bitrate) {
|
||||
if(bitrate < 0.6 || bitrate > 500.0) return false;
|
||||
|
||||
// set mode to standby
|
||||
SpiStrobe(CC1101_SIDLE);
|
||||
|
||||
// calculate exponent and mantissa values
|
||||
uint8_t e = 0;
|
||||
uint8_t m = 0;
|
||||
getExpMant(bitrate * 1000.0, 256, 28, 14, e, m);
|
||||
|
||||
// set bit rate value
|
||||
SpiSetRegValue(CC1101_MDMCFG4, e, 3, 0);
|
||||
SpiSetRegValue(CC1101_MDMCFG3, m, 7, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define F_OSC 26e6
|
||||
|
||||
/*******************************debug mode*************************************/
|
||||
// #define CC1101_DEBUG 1
|
||||
|
||||
//******************************CC1101 defines ********************************
|
||||
//******************************config registers *****************************
|
||||
#define CC1101_IOCFG2 0x00 //GDO2 output pin configration
|
||||
#define CC1101_IOCFG1 0x01 // GDO1 output pin configuration
|
||||
#define CC1101_IOCFG0 0x02 // GDO0 output pin configuration
|
||||
#define CC1101_FIFOTHR 0x03 // RX FIFO and TX FIFO thresholds
|
||||
#define CC1101_SYNC1 0x04 // Sync word, high INT8U
|
||||
#define CC1101_SYNC0 0x05 // Sync word, low INT8U
|
||||
#define CC1101_PKTLEN 0x06 // Packet length
|
||||
#define CC1101_PKTCTRL1 0x07 // Packet automation control
|
||||
#define CC1101_PKTCTRL0 0x08 // Packet automation control
|
||||
#define CC1101_ADDR 0x09 // Device address
|
||||
#define CC1101_CHANNR 0x0A // Channel number
|
||||
#define CC1101_FSCTRL1 0x0B // Frequency synthesizer control
|
||||
#define CC1101_FSCTRL0 0x0C // Frequency synthesizer control
|
||||
#define CC1101_FREQ2 0x0D // Frequency control word, high INT8U
|
||||
#define CC1101_FREQ1 0x0E // Frequency control word, middle INT8U
|
||||
#define CC1101_FREQ0 0x0F // Frequency control word, low INT8U
|
||||
#define CC1101_MDMCFG4 0x10 // Modem configuration
|
||||
#define CC1101_MDMCFG3 0x11 // Modem configuration
|
||||
#define CC1101_MDMCFG2 0x12 // Modem configuration
|
||||
#define CC1101_MDMCFG1 0x13 // Modem configuration
|
||||
#define CC1101_MDMCFG0 0x14 // Modem configuration
|
||||
#define CC1101_DEVIATN 0x15 // Modem deviation setting
|
||||
#define CC1101_MCSM2 0x16 // Main Radio Control State Machine configuration
|
||||
#define CC1101_MCSM1 0x17 // Main Radio Control State Machine configuration
|
||||
#define CC1101_MCSM0 0x18 // Main Radio Control State Machine configuration
|
||||
#define CC1101_FOCCFG 0x19 // Frequency Offset Compensation configuration
|
||||
#define CC1101_BSCFG 0x1A // Bit Synchronization configuration
|
||||
#define CC1101_AGCCTRL2 0x1B // AGC control
|
||||
#define CC1101_AGCCTRL1 0x1C // AGC control
|
||||
#define CC1101_AGCCTRL0 0x1D // AGC control
|
||||
#define CC1101_WOREVT1 0x1E // High INT8U Event 0 timeout
|
||||
#define CC1101_WOREVT0 0x1F // Low INT8U Event 0 timeout
|
||||
#define CC1101_WORCTRL 0x20 // Wake On Radio control
|
||||
#define CC1101_FREND1 0x21 // Front end RX configuration
|
||||
#define CC1101_FREND0 0x22 // Front end TX configuration
|
||||
#define CC1101_FSCAL3 0x23 // Frequency synthesizer calibration
|
||||
#define CC1101_FSCAL2 0x24 // Frequency synthesizer calibration
|
||||
#define CC1101_FSCAL1 0x25 // Frequency synthesizer calibration
|
||||
#define CC1101_FSCAL0 0x26 // Frequency synthesizer calibration
|
||||
#define CC1101_RCCTRL1 0x27 // RC oscillator configuration
|
||||
#define CC1101_RCCTRL0 0x28 // RC oscillator configuration
|
||||
#define CC1101_FSTEST 0x29 // Frequency synthesizer calibration control
|
||||
#define CC1101_PTEST 0x2A // Production test
|
||||
#define CC1101_AGCTEST 0x2B // AGC test
|
||||
#define CC1101_TEST2 0x2C // Various test settings
|
||||
#define CC1101_TEST1 0x2D // Various test settings
|
||||
#define CC1101_TEST0 0x2E // Various test settings
|
||||
|
||||
//*********************CC1101 Strobe commands *********************************
|
||||
#define CC1101_SRES 0x30 // Reset chip.
|
||||
|
||||
// Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
|
||||
// If in RX/TX: Go to a wait state where only the synthesizer is
|
||||
// running (for quick RX / TX turnaround).
|
||||
#define CC1101_SFSTXON 0x31
|
||||
|
||||
#define CC1101_SXOFF 0x32 // Turn off crystal oscillator.
|
||||
|
||||
// Calibrate frequency synthesizer and turn it off
|
||||
// (enables quick start).
|
||||
#define CC1101_SCAL 0x33
|
||||
|
||||
// Enable RX. Perform calibration first if coming from IDLE and
|
||||
// MCSM0.FS_AUTOCAL=1.
|
||||
#define CC1101_SRX 0x34
|
||||
|
||||
// In IDLE state: Enable TX. Perform calibration first if
|
||||
// MCSM0.FS_AUTOCAL=1. If in RX state and CCA is enabled:
|
||||
// Only go to TX if channel is clear.
|
||||
#define CC1101_STX 0x35
|
||||
|
||||
// Exit RX / TX, turn off frequency synthesizer and exit
|
||||
// Wake-On-Radio mode if applicable.
|
||||
#define CC1101_SIDLE 0x36
|
||||
|
||||
#define CC1101_SAFC 0x37 // Perform AFC adjustment of the frequency synthesizer
|
||||
#define CC1101_SWOR 0x38 // Start automatic RX polling sequence (Wake-on-Radio)
|
||||
#define CC1101_SPWD 0x39 // Enter power down mode when CSn goes high.
|
||||
#define CC1101_SFRX 0x3A // Flush the RX FIFO buffer.
|
||||
#define CC1101_SFTX 0x3B // Flush the TX FIFO buffer.
|
||||
#define CC1101_SWORRST 0x3C // Reset real time clock.
|
||||
|
||||
// No operation. May be used to pad strobe commands to two
|
||||
// INT8Us for simpler software.
|
||||
#define CC1101_SNOP 0x3D
|
||||
|
||||
//**************************CC1101 STATUS REGSITER ****************************
|
||||
//use burst read to access
|
||||
#define CC1101_PARTNUM 0x30
|
||||
#define CC1101_VERSION 0x31
|
||||
#define CC1101_FREQEST 0x32
|
||||
#define CC1101_LQI 0x33
|
||||
#define CC1101_RSSI 0x34
|
||||
#define CC1101_MARCSTATE 0x35
|
||||
#define CC1101_WORTIME1 0x36
|
||||
#define CC1101_WORTIME0 0x37
|
||||
#define CC1101_PKTSTATUS 0x38
|
||||
#define CC1101_VCO_VC_DAC 0x39
|
||||
#define CC1101_TXBYTES 0x3A
|
||||
#define CC1101_RXBYTES 0x3B
|
||||
#define CC1101_RCCTRL1_STATUS 0x3C
|
||||
#define CC1101_RCCTRL_STATUS 0x3D
|
||||
/****************************cc1101 status ***********************************/
|
||||
#define CC1101_STATUS_RX 0x0D
|
||||
#define CC1101_STATUS_TX 0x13
|
||||
|
||||
//***********************CC1101 PATABLE,TXFIFO,RXFIFO**************************
|
||||
#define CC1101_PATABLE 0x3E
|
||||
#define CC1101_TXFIFO 0x3F
|
||||
#define CC1101_RXFIFO 0x3F
|
||||
|
||||
//******************************* pins ****************************************
|
||||
// #define SCK_PIN 13
|
||||
// #define MISO_PIN 12
|
||||
// #define MOSI_PIN 11
|
||||
// #define SS_PIN 10
|
||||
// #define GDO0 8 //pin assignment
|
||||
// #define GDO2 9
|
||||
//*****************************CC1101 Config**********************************
|
||||
//no pa ramping, output power to 10dBm
|
||||
#define POWER 0xC0 //output power to maximum
|
||||
//modulation
|
||||
#define FSK2 0x00
|
||||
#define GFSK 0x10
|
||||
#define ASK 0x30
|
||||
#define FSK4 0x40
|
||||
#define MSK 0x70
|
||||
//******************************** class **************************************//
|
||||
class CC1101 {
|
||||
private:
|
||||
GpioPin* ss_pin;
|
||||
GpioPin miso_pin;
|
||||
GpioPin* miso_pin_record;
|
||||
GpioPin* gdo0_pin;
|
||||
GpioPin* gdo2_pin;
|
||||
|
||||
private:
|
||||
void SpiMode(uint8_t config);
|
||||
uint8_t SpiTransfer(uint8_t value);
|
||||
void Reset(void);
|
||||
void SpiWriteBurstReg(uint8_t addr, uint8_t* buffer, uint8_t num);
|
||||
uint8_t SpiReadReg(uint8_t addr);
|
||||
void RegConfigSettings(void);
|
||||
|
||||
public:
|
||||
CC1101(GpioPin* ss_pin);
|
||||
|
||||
void SpiWriteReg(uint8_t addr, uint8_t value);
|
||||
bool SpiSetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb);
|
||||
void SpiReadBurstReg(uint8_t addr, uint8_t* buffer, uint8_t num);
|
||||
void SpiInit(void);
|
||||
void SpiEnd(void);
|
||||
void SetMod(uint8_t mode);
|
||||
void SetFreq(uint8_t Freq2, uint8_t Freq1, uint8_t Freq0);
|
||||
uint8_t Init(void);
|
||||
void SpiStrobe(uint8_t strobe);
|
||||
uint8_t SpiReadStatus(uint8_t addr);
|
||||
void SetReceive(void);
|
||||
void SetTransmit(void);
|
||||
void SetChannel(int channel);
|
||||
bool setRxBandwidth(float bandwidth);
|
||||
bool setBitRate(float bitrate);
|
||||
};
|
||||
@@ -34,6 +34,7 @@ void canvas_free(Canvas* canvas) {
|
||||
|
||||
void canvas_reset(Canvas* canvas) {
|
||||
furi_assert(canvas);
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -849,4 +849,4 @@ int32_t sd_filesystem(void* p) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
#include "../subghz-event.h"
|
||||
|
||||
class SubghzApp;
|
||||
|
||||
class SubghzScene {
|
||||
public:
|
||||
virtual void on_enter(SubghzApp* app) = 0;
|
||||
virtual bool on_event(SubghzApp* app, SubghzEvent* event) = 0;
|
||||
virtual void on_exit(SubghzApp* app) = 0;
|
||||
|
||||
private:
|
||||
};
|
||||
@@ -1,48 +0,0 @@
|
||||
#include "subghz-scene-spectrum-settings.h"
|
||||
#include "../subghz-app.h"
|
||||
#include "../subghz-view-manager.h"
|
||||
#include "../subghz-event.h"
|
||||
#include <callback-connector.h>
|
||||
|
||||
void SubghzSceneSpectrumSettings::on_enter(SubghzApp* app) {
|
||||
SubghzAppViewManager* view_manager = app->get_view_manager();
|
||||
SubghzViewSpectrumSettings* spectrum_settings = view_manager->get_spectrum_settings();
|
||||
|
||||
auto callback = cbc::obtain_connector(this, &SubghzSceneSpectrumSettings::ok_callback);
|
||||
spectrum_settings->set_ok_callback(callback, app);
|
||||
spectrum_settings->set_start_freq(433);
|
||||
|
||||
view_manager->switch_to(SubghzAppViewManager::ViewType::SpectrumSettings);
|
||||
}
|
||||
|
||||
bool SubghzSceneSpectrumSettings::on_event(SubghzApp* app, SubghzEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == SubghzEvent::Type::NextScene) {
|
||||
// save data
|
||||
// uint32_t start_freq = app->get_view_manager()->get_spectrum_settings()->get_start_freq();
|
||||
// app->get_spectrum_analyzer()->set_start_freq(start_freq);
|
||||
|
||||
// switch to next scene
|
||||
// app->switch_to_next_scene(SubghzApp::Scene::SceneSpectrumAnalyze);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void SubghzSceneSpectrumSettings::on_exit(SubghzApp* app) {
|
||||
SubghzAppViewManager* view_manager = app->get_view_manager();
|
||||
SubghzViewSpectrumSettings* spectrum_settings = view_manager->get_spectrum_settings();
|
||||
|
||||
spectrum_settings->set_ok_callback(nullptr, nullptr);
|
||||
spectrum_settings->set_start_freq(0);
|
||||
}
|
||||
|
||||
void SubghzSceneSpectrumSettings::ok_callback(void* context) {
|
||||
SubghzApp* app = static_cast<SubghzApp*>(context);
|
||||
SubghzEvent event;
|
||||
|
||||
event.type = SubghzEvent::Type::NextScene;
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
#include "subghz-scene-generic.h"
|
||||
|
||||
class SubghzSceneSpectrumSettings : public SubghzScene {
|
||||
public:
|
||||
void on_enter(SubghzApp* app) final;
|
||||
bool on_event(SubghzApp* app, SubghzEvent* event) final;
|
||||
void on_exit(SubghzApp* app) final;
|
||||
|
||||
private:
|
||||
void ok_callback(void* context);
|
||||
};
|
||||
@@ -1,67 +0,0 @@
|
||||
#include "subghz-scene-start.h"
|
||||
#include "../subghz-app.h"
|
||||
#include "../subghz-view-manager.h"
|
||||
#include "../subghz-event.h"
|
||||
#include <callback-connector.h>
|
||||
|
||||
typedef enum {
|
||||
SubmenuIndexSpectrumAnalyzer,
|
||||
SubmenuIndexFrequencyScanner,
|
||||
SubmenuIndexSignalAnalyzer,
|
||||
SubmenuIndexSignalTransmitter,
|
||||
SubmenuIndexApplications,
|
||||
} SubmenuIndex;
|
||||
|
||||
void SubghzSceneStart::on_enter(SubghzApp* app) {
|
||||
SubghzAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
auto callback = cbc::obtain_connector(this, &SubghzSceneStart::submenu_callback);
|
||||
|
||||
submenu_add_item(submenu, "Spectrum Analyzer", SubmenuIndexSpectrumAnalyzer, callback, app);
|
||||
submenu_add_item(submenu, "Frequency Scanner", SubmenuIndexFrequencyScanner, callback, app);
|
||||
submenu_add_item(submenu, "Signal Analyzer", SubmenuIndexSignalAnalyzer, callback, app);
|
||||
submenu_add_item(submenu, "Signal Transmitter", SubmenuIndexSignalTransmitter, callback, app);
|
||||
submenu_add_item(submenu, "Applications", SubmenuIndexApplications, callback, app);
|
||||
|
||||
view_manager->switch_to(SubghzAppViewManager::ViewType::Submenu);
|
||||
}
|
||||
|
||||
bool SubghzSceneStart::on_event(SubghzApp* app, SubghzEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == SubghzEvent::Type::MenuSelected) {
|
||||
switch(event->payload.menu_index) {
|
||||
case SubmenuIndexSpectrumAnalyzer:
|
||||
app->switch_to_next_scene(SubghzApp::Scene::SceneSpectrumSettings);
|
||||
break;
|
||||
case SubmenuIndexFrequencyScanner:
|
||||
break;
|
||||
case SubmenuIndexSignalAnalyzer:
|
||||
break;
|
||||
case SubmenuIndexSignalTransmitter:
|
||||
break;
|
||||
case SubmenuIndexApplications:
|
||||
break;
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void SubghzSceneStart::on_exit(SubghzApp* app) {
|
||||
SubghzAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
submenu_clean(submenu);
|
||||
}
|
||||
|
||||
void SubghzSceneStart::submenu_callback(void* context, uint32_t index) {
|
||||
SubghzApp* app = static_cast<SubghzApp*>(context);
|
||||
SubghzEvent event;
|
||||
|
||||
event.type = SubghzEvent::Type::MenuSelected;
|
||||
event.payload.menu_index = index;
|
||||
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
#include "subghz-scene-generic.h"
|
||||
|
||||
class SubghzSceneStart : public SubghzScene {
|
||||
public:
|
||||
void on_enter(SubghzApp* app) final;
|
||||
bool on_event(SubghzApp* app, SubghzEvent* event) final;
|
||||
void on_exit(SubghzApp* app) final;
|
||||
|
||||
private:
|
||||
void submenu_callback(void* context, uint32_t index);
|
||||
};
|
||||
@@ -1,90 +0,0 @@
|
||||
#include "subghz-app.h"
|
||||
#include <api-hal-power.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
void SubghzApp::run(void) {
|
||||
SubghzEvent event;
|
||||
bool consumed;
|
||||
bool exit = false;
|
||||
|
||||
scenes[current_scene]->on_enter(this);
|
||||
|
||||
while(!exit) {
|
||||
view.receive_event(&event);
|
||||
|
||||
consumed = scenes[current_scene]->on_event(this, &event);
|
||||
|
||||
if(!consumed) {
|
||||
if(event.type == SubghzEvent::Type::Back) {
|
||||
exit = switch_to_previous_scene();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scenes[current_scene]->on_exit(this);
|
||||
}
|
||||
|
||||
SubghzApp::SubghzApp() {
|
||||
api_hal_power_insomnia_enter();
|
||||
}
|
||||
|
||||
SubghzApp::~SubghzApp() {
|
||||
api_hal_power_insomnia_exit();
|
||||
}
|
||||
|
||||
SubghzAppViewManager* SubghzApp::get_view_manager() {
|
||||
return &view;
|
||||
}
|
||||
|
||||
void SubghzApp::switch_to_next_scene(Scene next_scene) {
|
||||
previous_scenes_list.push_front(current_scene);
|
||||
|
||||
if(next_scene != Scene::SceneExit) {
|
||||
scenes[current_scene]->on_exit(this);
|
||||
current_scene = next_scene;
|
||||
scenes[current_scene]->on_enter(this);
|
||||
}
|
||||
}
|
||||
|
||||
void SubghzApp::search_and_switch_to_previous_scene(std::initializer_list<Scene> scenes_list) {
|
||||
Scene previous_scene = Scene::SceneStart;
|
||||
bool scene_found = false;
|
||||
|
||||
while(!scene_found) {
|
||||
previous_scene = get_previous_scene();
|
||||
for(Scene element : scenes_list) {
|
||||
if(previous_scene == element || previous_scene == Scene::SceneStart) {
|
||||
scene_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scenes[current_scene]->on_exit(this);
|
||||
current_scene = previous_scene;
|
||||
scenes[current_scene]->on_enter(this);
|
||||
}
|
||||
|
||||
bool SubghzApp::switch_to_previous_scene(uint8_t count) {
|
||||
Scene previous_scene = Scene::SceneStart;
|
||||
|
||||
for(uint8_t i = 0; i < count; i++) {
|
||||
previous_scene = get_previous_scene();
|
||||
if(previous_scene == Scene::SceneExit) break;
|
||||
}
|
||||
|
||||
if(previous_scene == Scene::SceneExit) {
|
||||
return true;
|
||||
} else {
|
||||
scenes[current_scene]->on_exit(this);
|
||||
current_scene = previous_scene;
|
||||
scenes[current_scene]->on_enter(this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SubghzApp::Scene SubghzApp::get_previous_scene() {
|
||||
Scene scene = previous_scenes_list.front();
|
||||
previous_scenes_list.pop_front();
|
||||
return scene;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include "subghz-view-manager.h"
|
||||
|
||||
#include "scene/subghz-scene-start.h"
|
||||
#include "scene/subghz-scene-spectrum-settings.h"
|
||||
|
||||
class SubghzApp {
|
||||
public:
|
||||
void run(void);
|
||||
|
||||
SubghzApp();
|
||||
~SubghzApp();
|
||||
|
||||
enum class Scene : uint8_t {
|
||||
SceneExit,
|
||||
SceneStart,
|
||||
SceneSpectrumSettings,
|
||||
};
|
||||
|
||||
SubghzAppViewManager* get_view_manager();
|
||||
void switch_to_next_scene(Scene index);
|
||||
void search_and_switch_to_previous_scene(std::initializer_list<Scene> scenes_list);
|
||||
bool switch_to_previous_scene(uint8_t count = 1);
|
||||
Scene get_previous_scene();
|
||||
|
||||
private:
|
||||
std::list<Scene> previous_scenes_list = {Scene::SceneExit};
|
||||
Scene current_scene = Scene::SceneStart;
|
||||
SubghzAppViewManager view;
|
||||
|
||||
std::map<Scene, SubghzScene*> scenes = {
|
||||
{Scene::SceneStart, new SubghzSceneStart()},
|
||||
{Scene::SceneSpectrumSettings, new SubghzSceneSpectrumSettings()},
|
||||
};
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
class SubghzEvent {
|
||||
public:
|
||||
// events enum
|
||||
enum class Type : uint8_t {
|
||||
Tick,
|
||||
Back,
|
||||
MenuSelected,
|
||||
NextScene,
|
||||
};
|
||||
|
||||
// payload
|
||||
union {
|
||||
uint32_t menu_index;
|
||||
} payload;
|
||||
|
||||
// event type
|
||||
Type type;
|
||||
};
|
||||
@@ -1,81 +0,0 @@
|
||||
#include "subghz-view-manager.h"
|
||||
#include "subghz-event.h"
|
||||
#include <callback-connector.h>
|
||||
|
||||
SubghzAppViewManager::SubghzAppViewManager() {
|
||||
event_queue = osMessageQueueNew(10, sizeof(SubghzEvent), NULL);
|
||||
|
||||
view_dispatcher = view_dispatcher_alloc();
|
||||
auto callback = cbc::obtain_connector(this, &SubghzAppViewManager::previous_view_callback);
|
||||
|
||||
// allocate views
|
||||
submenu = submenu_alloc();
|
||||
view_dispatcher_add_view(
|
||||
view_dispatcher,
|
||||
static_cast<uint32_t>(SubghzAppViewManager::ViewType::Submenu),
|
||||
submenu_get_view(submenu));
|
||||
|
||||
spectrum_settings = new SubghzViewSpectrumSettings();
|
||||
view_dispatcher_add_view(
|
||||
view_dispatcher,
|
||||
static_cast<uint32_t>(SubghzAppViewManager::ViewType::SpectrumSettings),
|
||||
spectrum_settings->get_view());
|
||||
|
||||
gui = static_cast<Gui*>(furi_record_open("gui"));
|
||||
view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
// set previous view callback for all views
|
||||
view_set_previous_callback(submenu_get_view(submenu), callback);
|
||||
view_set_previous_callback(spectrum_settings->get_view(), callback);
|
||||
}
|
||||
|
||||
SubghzAppViewManager::~SubghzAppViewManager() {
|
||||
// remove views
|
||||
view_dispatcher_remove_view(
|
||||
view_dispatcher, static_cast<uint32_t>(SubghzAppViewManager::ViewType::Submenu));
|
||||
view_dispatcher_remove_view(
|
||||
view_dispatcher, static_cast<uint32_t>(SubghzAppViewManager::ViewType::SpectrumSettings));
|
||||
|
||||
// free view modules
|
||||
submenu_free(submenu);
|
||||
free(spectrum_settings);
|
||||
|
||||
// free dispatcher
|
||||
view_dispatcher_free(view_dispatcher);
|
||||
|
||||
// free event queue
|
||||
osMessageQueueDelete(event_queue);
|
||||
}
|
||||
|
||||
void SubghzAppViewManager::switch_to(ViewType type) {
|
||||
view_dispatcher_switch_to_view(view_dispatcher, static_cast<uint32_t>(type));
|
||||
}
|
||||
|
||||
Submenu* SubghzAppViewManager::get_submenu() {
|
||||
return submenu;
|
||||
}
|
||||
|
||||
SubghzViewSpectrumSettings* SubghzAppViewManager::get_spectrum_settings() {
|
||||
return spectrum_settings;
|
||||
}
|
||||
|
||||
void SubghzAppViewManager::receive_event(SubghzEvent* event) {
|
||||
if(osMessageQueueGet(event_queue, event, NULL, 100) != osOK) {
|
||||
event->type = SubghzEvent::Type::Tick;
|
||||
}
|
||||
}
|
||||
|
||||
void SubghzAppViewManager::send_event(SubghzEvent* event) {
|
||||
osStatus_t result = osMessageQueuePut(event_queue, event, 0, 0);
|
||||
furi_check(result == osOK);
|
||||
}
|
||||
|
||||
uint32_t SubghzAppViewManager::previous_view_callback(void* context) {
|
||||
if(event_queue != NULL) {
|
||||
SubghzEvent event;
|
||||
event.type = SubghzEvent::Type::Back;
|
||||
send_event(&event);
|
||||
}
|
||||
|
||||
return VIEW_IGNORE;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include "subghz-event.h"
|
||||
#include "view/subghz-view-spectrum-settings.h"
|
||||
|
||||
class SubghzAppViewManager {
|
||||
public:
|
||||
enum class ViewType : uint8_t {
|
||||
Submenu,
|
||||
SpectrumSettings,
|
||||
};
|
||||
|
||||
osMessageQueueId_t event_queue;
|
||||
|
||||
SubghzAppViewManager();
|
||||
~SubghzAppViewManager();
|
||||
|
||||
void switch_to(ViewType type);
|
||||
|
||||
void receive_event(SubghzEvent* event);
|
||||
void send_event(SubghzEvent* event);
|
||||
|
||||
Submenu* get_submenu();
|
||||
SubghzViewSpectrumSettings* get_spectrum_settings();
|
||||
|
||||
private:
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Gui* gui;
|
||||
|
||||
uint32_t previous_view_callback(void* context);
|
||||
|
||||
// view elements
|
||||
Submenu* submenu;
|
||||
SubghzViewSpectrumSettings* spectrum_settings;
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "subghz_i.h"
|
||||
|
||||
osThreadId subghz_thread_id = NULL;
|
||||
|
||||
void subghz_menu_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhz* subghz = context;
|
||||
|
||||
if(index == 0) {
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTestBasic);
|
||||
} else if(index == 1) {
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTestPacket);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t subghz_exit(void* context) {
|
||||
osThreadResume(subghz_thread_id);
|
||||
return VIEW_NONE;
|
||||
}
|
||||
|
||||
SubGhz* subghz_alloc() {
|
||||
SubGhz* subghz = furi_alloc(sizeof(SubGhz));
|
||||
|
||||
// Thread id
|
||||
subghz_thread_id = osThreadGetId();
|
||||
|
||||
// GUI
|
||||
subghz->gui = furi_record_open("gui");
|
||||
|
||||
// View Dispatcher
|
||||
subghz->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_attach_to_gui(
|
||||
subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
// Menu
|
||||
subghz->submenu = submenu_alloc();
|
||||
submenu_add_item(subghz->submenu, "Basic Test", 0, subghz_menu_callback, subghz);
|
||||
submenu_add_item(subghz->submenu, "Packet Test", 1, subghz_menu_callback, subghz);
|
||||
View* submenu_view = submenu_get_view(subghz->submenu);
|
||||
view_set_previous_callback(submenu_view, subghz_exit);
|
||||
view_dispatcher_add_view(subghz->view_dispatcher, SubGhzViewMenu, submenu_view);
|
||||
|
||||
// Basic Test Module
|
||||
subghz->subghz_test_basic = subghz_test_basic_alloc();
|
||||
view_dispatcher_add_view(
|
||||
subghz->view_dispatcher,
|
||||
SubGhzViewTestBasic,
|
||||
subghz_test_basic_get_view(subghz->subghz_test_basic));
|
||||
|
||||
// Packet Test
|
||||
subghz->subghz_test_packet = subghz_test_packet_alloc();
|
||||
view_dispatcher_add_view(
|
||||
subghz->view_dispatcher,
|
||||
SubGhzViewTestPacket,
|
||||
subghz_test_packet_get_view(subghz->subghz_test_packet));
|
||||
|
||||
// Switch to menu
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu);
|
||||
|
||||
return subghz;
|
||||
}
|
||||
|
||||
void subghz_free(SubGhz* subghz) {
|
||||
furi_assert(subghz);
|
||||
|
||||
// Packet Test
|
||||
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTestPacket);
|
||||
subghz_test_packet_free(subghz->subghz_test_packet);
|
||||
|
||||
// Basic Test
|
||||
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTestBasic);
|
||||
subghz_test_basic_free(subghz->subghz_test_basic);
|
||||
|
||||
// Submenu
|
||||
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewMenu);
|
||||
submenu_free(subghz->submenu);
|
||||
|
||||
// View Dispatcher
|
||||
view_dispatcher_free(subghz->view_dispatcher);
|
||||
|
||||
// GUI
|
||||
furi_record_close("gui");
|
||||
subghz->gui = NULL;
|
||||
|
||||
// The rest
|
||||
free(subghz);
|
||||
}
|
||||
|
||||
int32_t subghz_app(void* context) {
|
||||
SubGhz* subghz = subghz_alloc();
|
||||
|
||||
osThreadSuspend(subghz_thread_id);
|
||||
|
||||
subghz_free(subghz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "subghz-app.h"
|
||||
|
||||
// app enter function
|
||||
extern "C" int32_t app_subghz(void* p) {
|
||||
SubghzApp* app = new SubghzApp();
|
||||
app->run();
|
||||
delete app;
|
||||
|
||||
return 255;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct SubGhz SubGhz;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct SubghzTestPacket SubghzTestPacket;
|
||||
|
||||
SubghzTestPacket* subghz_test_packet_alloc();
|
||||
|
||||
void subghz_test_packet_free(SubghzTestPacket* subghz_test_packet);
|
||||
|
||||
View* subghz_test_packet_get_view(SubghzTestPacket* subghz_test_packet);
|
||||
@@ -1,95 +0,0 @@
|
||||
#include "subghz-view-spectrum-settings.h"
|
||||
#include <callback-connector.h>
|
||||
|
||||
struct SpectrumSettingsModel {
|
||||
uint32_t start_freq;
|
||||
};
|
||||
|
||||
/***************************************************************************************/
|
||||
|
||||
static void draw_callback(Canvas* canvas, void* _model) {
|
||||
SpectrumSettingsModel* model = static_cast<SpectrumSettingsModel*>(_model);
|
||||
const uint8_t str_size = 64;
|
||||
char str_buffer[str_size];
|
||||
|
||||
canvas_clear(canvas);
|
||||
snprintf(str_buffer, str_size, "Start freq < %ld > MHz", model->start_freq);
|
||||
canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, str_buffer);
|
||||
}
|
||||
|
||||
static bool input_callback(InputEvent* event, void* context) {
|
||||
SubghzViewSpectrumSettings* _this = static_cast<SubghzViewSpectrumSettings*>(context);
|
||||
|
||||
bool consumed = false;
|
||||
|
||||
// Process key presses only
|
||||
if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyOk) {
|
||||
_this->call_ok_callback();
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
with_view_model_cpp(_this->get_view(), SpectrumSettingsModel, model, {
|
||||
model->start_freq--;
|
||||
return true;
|
||||
});
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyRight) {
|
||||
with_view_model_cpp(_this->get_view(), SpectrumSettingsModel, model, {
|
||||
model->start_freq++;
|
||||
return true;
|
||||
});
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
/***************************************************************************************/
|
||||
|
||||
View* SubghzViewSpectrumSettings::get_view() {
|
||||
return view;
|
||||
}
|
||||
|
||||
void SubghzViewSpectrumSettings::set_ok_callback(OkCallback callback, void* context) {
|
||||
ok_callback = callback;
|
||||
ok_callback_context = context;
|
||||
}
|
||||
|
||||
void SubghzViewSpectrumSettings::call_ok_callback() {
|
||||
if(ok_callback != nullptr) {
|
||||
ok_callback(ok_callback_context);
|
||||
}
|
||||
}
|
||||
|
||||
void SubghzViewSpectrumSettings::set_start_freq(uint32_t start_freq) {
|
||||
with_view_model_cpp(view, SpectrumSettingsModel, model, {
|
||||
model->start_freq = start_freq;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
uint32_t SubghzViewSpectrumSettings::get_start_freq() {
|
||||
uint32_t result;
|
||||
|
||||
with_view_model_cpp(view, SpectrumSettingsModel, model, {
|
||||
result = model->start_freq;
|
||||
return false;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SubghzViewSpectrumSettings::SubghzViewSpectrumSettings() {
|
||||
view = view_alloc();
|
||||
view_set_context(view, this);
|
||||
view_allocate_model(view, ViewModelTypeLocking, sizeof(SpectrumSettingsModel));
|
||||
|
||||
view_set_draw_callback(view, draw_callback);
|
||||
|
||||
view_set_input_callback(view, input_callback);
|
||||
}
|
||||
|
||||
SubghzViewSpectrumSettings::~SubghzViewSpectrumSettings() {
|
||||
view_free(view);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#include <gui/view.h>
|
||||
|
||||
class SubghzViewSpectrumSettings {
|
||||
public:
|
||||
SubghzViewSpectrumSettings();
|
||||
~SubghzViewSpectrumSettings();
|
||||
|
||||
View* get_view();
|
||||
|
||||
// ok callback methods
|
||||
typedef void (*OkCallback)(void* context);
|
||||
void set_ok_callback(OkCallback callback, void* context);
|
||||
void call_ok_callback();
|
||||
|
||||
// model data getters/setters
|
||||
void set_start_freq(uint32_t start_freq);
|
||||
uint32_t get_start_freq();
|
||||
|
||||
private:
|
||||
View* view;
|
||||
|
||||
// ok callback data
|
||||
OkCallback ok_callback = nullptr;
|
||||
void* ok_callback_context = nullptr;
|
||||
};
|
||||
Reference in New Issue
Block a user