SubGhz: add GFSK modulation, refactoring subghz_chat (#866)

* SubGhz: add GFSK modulation, refactoring subghz_chat
* SubGhz: off echo subghz_chat
* SubGhz: subghz_chat add sending and receiving formatted text, translation of the chat to events
* SubGhz: add UTF support in subghz_chat_worker_alloc

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Skorpionm 2021-12-08 17:42:01 +04:00 committed by GitHub
parent 7170864fe4
commit f0aed7e583
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 459 additions and 96 deletions

View File

@ -18,6 +18,7 @@ typedef enum {
CliSymbolAsciiBell = 0x07,
CliSymbolAsciiBackspace = 0x08,
CliSymbolAsciiTab = 0x09,
CliSymbolAsciiLF = 0x0A,
CliSymbolAsciiCR = 0x0D,
CliSymbolAsciiEsc = 0x1B,
CliSymbolAsciiUS = 0x1F,

View File

@ -0,0 +1,141 @@
#include "subghz_chat.h"
#include <lib/subghz/subghz_tx_rx_worker.h>
#define TAG "SubGhzChat"
#define SUBGHZ_CHAT_WORKER_TIMEOUT_BETWEEN_MESSAGES 500
struct SubGhzChatWorker {
FuriThread* thread;
SubGhzTxRxWorker* subghz_txrx;
volatile bool worker_running;
volatile bool worker_stoping;
osMessageQueueId_t event_queue;
uint32_t last_time_rx_data;
};
/** Worker thread
*
* @param context
* @return exit code
*/
static int32_t subghz_chat_worker_thread(void* context) {
SubGhzChatWorker* instance = context;
FURI_LOG_I(TAG, "Worker start");
char c;
SubghzChatEvent event;
event.event = SubghzChatEventUserEntrance;
osMessageQueuePut(instance->event_queue, &event, 0, 0);
while(instance->worker_running) {
if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, osWaitForever) == 1) {
event.event = SubghzChatEventInputData;
event.c = c;
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
}
}
FURI_LOG_I(TAG, "Worker stop");
return 0;
}
static void subghz_chat_worker_update_rx_event_chat(void* context) {
furi_assert(context);
SubGhzChatWorker* instance = context;
SubghzChatEvent event;
if((millis() - instance->last_time_rx_data) > SUBGHZ_CHAT_WORKER_TIMEOUT_BETWEEN_MESSAGES) {
event.event = SubghzChatEventNewMessage;
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
}
instance->last_time_rx_data = millis();
event.event = SubghzChatEventRXData;
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
}
SubGhzChatWorker* subghz_chat_worker_alloc() {
SubGhzChatWorker* instance = furi_alloc(sizeof(SubGhzChatWorker));
instance->thread = furi_thread_alloc();
furi_thread_set_name(instance->thread, "SubghzChat");
furi_thread_set_stack_size(instance->thread, 2048);
furi_thread_set_context(instance->thread, instance);
furi_thread_set_callback(instance->thread, subghz_chat_worker_thread);
instance->subghz_txrx = subghz_tx_rx_worker_alloc();
instance->event_queue = osMessageQueueNew(80, sizeof(SubghzChatEvent), NULL);
return instance;
}
void subghz_chat_worker_free(SubGhzChatWorker* instance) {
furi_assert(instance);
furi_assert(!instance->worker_running);
osMessageQueueDelete(instance->event_queue);
subghz_tx_rx_worker_free(instance->subghz_txrx);
furi_thread_free(instance->thread);
free(instance);
}
bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency) {
furi_assert(instance);
furi_assert(!instance->worker_running);
bool res = false;
if(subghz_tx_rx_worker_start(instance->subghz_txrx, frequency)) {
osMessageQueueReset(instance->event_queue);
subghz_tx_rx_worker_set_callback_have_read(
instance->subghz_txrx, subghz_chat_worker_update_rx_event_chat, instance);
instance->worker_running = true;
instance->last_time_rx_data = 0;
res = furi_thread_start(instance->thread);
}
return res;
}
void subghz_chat_worker_stop(SubGhzChatWorker* instance) {
furi_assert(instance);
furi_assert(instance->worker_running);
if(subghz_tx_rx_worker_is_running(instance->subghz_txrx)) {
subghz_tx_rx_worker_stop(instance->subghz_txrx);
}
instance->worker_running = false;
furi_thread_join(instance->thread);
}
bool subghz_chat_worker_is_running(SubGhzChatWorker* instance) {
furi_assert(instance);
return instance->worker_running;
}
SubghzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance) {
furi_assert(instance);
SubghzChatEvent event;
if(osMessageQueueGet(instance->event_queue, &event, NULL, osWaitForever) == osOK) {
return event;
} else {
event.event = SubghzChatEventNoEvent;
return event;
}
}
void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubghzChatEvent* event) {
furi_assert(instance);
osMessageQueuePut(instance->event_queue, event, 0, osWaitForever);
}
size_t subghz_chat_worker_available(SubGhzChatWorker* instance) {
furi_assert(instance);
return subghz_tx_rx_worker_available(instance->subghz_txrx);
}
size_t subghz_chat_worker_read(SubGhzChatWorker* instance, uint8_t* data, size_t size) {
furi_assert(instance);
return subghz_tx_rx_worker_read(instance->subghz_txrx, data, size);
}
bool subghz_chat_worker_write(SubGhzChatWorker* instance, uint8_t* data, size_t size) {
furi_assert(instance);
return subghz_tx_rx_worker_write(instance->subghz_txrx, data, size);
}

View File

@ -0,0 +1,29 @@
#pragma once
#include "../subghz_i.h"
typedef struct SubGhzChatWorker SubGhzChatWorker;
typedef enum {
SubghzChatEventNoEvent,
SubghzChatEventUserEntrance,
SubghzChatEventUserExit,
SubghzChatEventInputData,
SubghzChatEventRXData,
SubghzChatEventNewMessage,
} SubghzChatEventType;
typedef struct {
SubghzChatEventType event;
char c;
} SubghzChatEvent;
SubGhzChatWorker* subghz_chat_worker_alloc();
void subghz_chat_worker_free(SubGhzChatWorker* instance);
bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency);
void subghz_chat_worker_stop(SubGhzChatWorker* instance);
bool subghz_chat_worker_is_running(SubGhzChatWorker* instance);
SubghzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance);
void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubghzChatEvent* event);
size_t subghz_chat_worker_available(SubGhzChatWorker* instance);
size_t subghz_chat_worker_read(SubGhzChatWorker* instance, uint8_t* data, size_t size);
bool subghz_chat_worker_write(SubGhzChatWorker* instance, uint8_t* data, size_t size);

View File

@ -9,7 +9,8 @@
#include <lib/subghz/subghz_keystore.h>
#include <lib/subghz/protocols/subghz_protocol_common.h>
#include <lib/subghz/protocols/subghz_protocol_princeton.h>
#include <lib/subghz/subghz_tx_rx_worker.h>
#include "helpers/subghz_chat.h"
#include <notification/notification-messages.h>
@ -377,23 +378,34 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) {
return;
}
SubGhzTxRxWorker* subghz_txrx = subghz_tx_rx_worker_alloc();
subghz_tx_rx_worker_start(subghz_txrx, frequency);
SubGhzChatWorker* subghz_chat = subghz_chat_worker_alloc();
if(!subghz_chat_worker_start(subghz_chat, frequency)) {
printf("Startup error SubGhzChatWorker\r\n");
if(subghz_chat_worker_is_running(subghz_chat)) {
subghz_chat_worker_stop(subghz_chat);
subghz_chat_worker_free(subghz_chat);
}
return;
}
printf("Receiving at frequency %lu Hz\r\n", frequency);
printf("Press CTRL+C to stop\r\n");
furi_hal_power_suppress_charge_enter();
size_t message_max_len = 64;
uint8_t message[64] = {0};
string_t input;
string_init(input);
string_t name;
string_init(name);
string_t output;
string_init(output);
string_t sysmsg;
string_init(sysmsg);
char c;
bool exit = false;
SubghzChatEvent chat_event;
NotificationApp* notification = furi_record_open("notification");
@ -402,71 +414,120 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) {
printf("%s", string_get_cstr(input));
fflush(stdout);
string_printf(sysmsg, "\033[0;34m%s joined chat.\033[0m", furi_hal_version_get_name_ptr());
subghz_tx_rx_worker_write(
subghz_txrx, (uint8_t*)string_get_cstr(sysmsg), strlen(string_get_cstr(sysmsg)));
while(!exit) {
if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 0) == 1) {
if(c == CliSymbolAsciiETX) {
chat_event = subghz_chat_worker_get_event_chat(subghz_chat);
switch(chat_event.event) {
case SubghzChatEventInputData:
if(chat_event.c == CliSymbolAsciiETX) {
printf("\r\n");
exit = true;
chat_event.event = SubghzChatEventUserExit;
subghz_chat_worker_put_event_chat(subghz_chat, &chat_event);
break;
} else if((c >= 0x20 && c < 0x7F) || (c >= 0x80 && c < 0xF0)) {
putc(c, stdout);
fflush(stdout);
string_push_back(input, c);
} else if((c == CliSymbolAsciiBackspace) || (c == CliSymbolAsciiDel)) {
size_t len = string_size(input);
if(len > string_size(name)) {
} else if(
(chat_event.c == CliSymbolAsciiBackspace) || (chat_event.c == CliSymbolAsciiDel)) {
size_t len = string_length_u(input);
if(len > string_length_u(name)) {
printf("%s", "\e[D\e[1P");
fflush(stdout);
string_set_strn(input, string_get_cstr(input), len - 1);
//delete 1 char UTF
const char* str = string_get_cstr(input);
size_t size = 0;
m_str1ng_utf8_state_e s = M_STRING_UTF8_STARTING;
string_unicode_t u = 0;
string_reset(sysmsg);
while(*str) {
m_str1ng_utf8_decode(*str, &s, &u);
if((s == M_STRING_UTF8_ERROR) || s == M_STRING_UTF8_STARTING) {
string_push_u(sysmsg, u);
if(++size >= len - 1) break;
s = M_STRING_UTF8_STARTING;
}
} else if(c == CliSymbolAsciiCR) {
str++;
}
string_set(input, sysmsg);
}
} else if(chat_event.c == CliSymbolAsciiCR) {
printf("\r\n");
subghz_tx_rx_worker_write(
subghz_txrx, (uint8_t*)string_get_cstr(input), strlen(string_get_cstr(input)));
string_push_back(input, '\r');
string_push_back(input, '\n');
while(!subghz_chat_worker_write(
subghz_chat,
(uint8_t*)string_get_cstr(input),
strlen(string_get_cstr(input)))) {
delay(10);
}
string_printf(input, "%s", string_get_cstr(name));
printf("%s", string_get_cstr(input));
fflush(stdout);
}
}
if(subghz_tx_rx_worker_available(subghz_txrx)) {
} else if(chat_event.c == CliSymbolAsciiLF) {
//cut out the symbol \n
} else {
putc(chat_event.c, stdout);
fflush(stdout);
string_push_back(input, chat_event.c);
break;
case SubghzChatEventRXData:
do {
memset(message, 0x00, message_max_len);
subghz_tx_rx_worker_read(subghz_txrx, message, message_max_len);
size_t len = subghz_chat_worker_read(subghz_chat, message, message_max_len);
for(size_t i = 0; i < len; i++) {
string_push_back(output, message[i]);
if(message[i] == '\n') {
printf("\r");
for(uint8_t i = 0; i < 80; i++) {
printf(" ");
}
printf("\r %s\r\n", message);
printf("\r %s", string_get_cstr(output));
printf("%s", string_get_cstr(input));
fflush(stdout);
string_reset(output);
}
}
} while(subghz_chat_worker_available(subghz_chat));
break;
case SubghzChatEventNewMessage:
notification_message(notification, &sequence_single_vibro);
break;
case SubghzChatEventUserEntrance:
string_printf(
sysmsg,
"\033[0;34m%s joined chat.\033[0m\r\n",
furi_hal_version_get_name_ptr());
subghz_chat_worker_write(
subghz_chat,
(uint8_t*)string_get_cstr(sysmsg),
strlen(string_get_cstr(sysmsg)));
break;
case SubghzChatEventUserExit:
string_printf(
sysmsg, "\033[0;31m%s left chat.\033[0m\r\n", furi_hal_version_get_name_ptr());
subghz_chat_worker_write(
subghz_chat,
(uint8_t*)string_get_cstr(sysmsg),
strlen(string_get_cstr(sysmsg)));
delay(10);
exit = true;
break;
default:
FURI_LOG_W("SubGhzChat", "Error event");
break;
}
}
osDelay(1);
}
string_printf(sysmsg, "\033[0;31m%s left chat.\033[0m", furi_hal_version_get_name_ptr());
subghz_tx_rx_worker_write(
subghz_txrx, (uint8_t*)string_get_cstr(sysmsg), strlen(string_get_cstr(sysmsg)));
osDelay(10);
printf("\r\nExit chat\r\n");
string_clear(input);
string_clear(name);
string_clear(output);
string_clear(sysmsg);
furi_hal_power_suppress_charge_exit();
furi_record_close("notification");
if(subghz_tx_rx_worker_is_running(subghz_txrx)) {
subghz_tx_rx_worker_stop(subghz_txrx);
subghz_tx_rx_worker_free(subghz_txrx);
if(subghz_chat_worker_is_running(subghz_chat)) {
subghz_chat_worker_stop(subghz_chat);
subghz_chat_worker_free(subghz_chat);
}
printf("\r\nExit chat\r\n");
}
static void subghz_cli_command(Cli* cli, string_t args, void* context) {

View File

@ -291,6 +291,45 @@ static const uint8_t furi_hal_subghz_preset_msk_99_97kb_async_regs[][2] = {
/* End */
{0, 0},
};
static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs[][2] = {
{CC1101_IOCFG0, 0x06}, //GDO0 Output Pin Configuration
{CC1101_FIFOTHR, 0x47}, //RX FIFO and TX FIFO Thresholds
//1 : CRC calculation in TX and CRC check in RX enabled,
//1 : Variable packet length mode. Packet length configured by the first byte after sync word
{CC1101_PKTCTRL0, 0x05},
{CC1101_FSCTRL1, 0x06}, //Frequency Synthesizer Control
{CC1101_SYNC1, 0x46},
{CC1101_SYNC0, 0x4C},
{CC1101_ADDR, 0x00},
{CC1101_PKTLEN, 0x00},
{CC1101_MDMCFG4, 0xC8}, //Modem Configuration 9.99
{CC1101_MDMCFG3, 0x93}, //Modem Configuration
{CC1101_MDMCFG2, 0x12}, // 2: 16/16 sync word bits detected
{CC1101_DEVIATN, 0x34}, //Deviation = 19.042969
{CC1101_MCSM0, 0x18}, //Main Radio Control State Machine Configuration
{CC1101_FOCCFG, 0x16}, //Frequency Offset Compensation Configuration
{CC1101_AGCCTRL2, 0x43}, //AGC Control
{CC1101_AGCCTRL1, 0x40},
{CC1101_AGCCTRL0, 0x91},
{CC1101_WORCTRL, 0xFB}, //Wake On Radio Control
{CC1101_FSCAL3, 0xE9}, //Frequency Synthesizer Calibration
{CC1101_FSCAL2, 0x2A}, //Frequency Synthesizer Calibration
{CC1101_FSCAL1, 0x00}, //Frequency Synthesizer Calibration
{CC1101_FSCAL0, 0x1F}, //Frequency Synthesizer Calibration
{CC1101_TEST2, 0x81}, //Various Test Settings
{CC1101_TEST1, 0x35}, //Various Test Settings
{CC1101_TEST0, 0x09}, //Various Test Settings
/* End */
{0, 0},
};
static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = {
0x00,
@ -319,6 +358,15 @@ static const uint8_t furi_hal_subghz_preset_msk_async_patable[8] = {
0x00,
0x00,
0x00};
static const uint8_t furi_hal_subghz_preset_gfsk_async_patable[8] = {
0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00};
void furi_hal_subghz_init() {
furi_assert(furi_hal_subghz_state == SubGhzStateInit);
@ -344,7 +392,8 @@ void furi_hal_subghz_init() {
;
// GD0 high
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV);
cc1101_write_reg(
&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV);
while(hal_gpio_read(&gpio_cc1101_g0) != true)
;
@ -402,6 +451,9 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
} else if(preset == FuriHalSubGhzPresetMSK99_97KbAsync) {
furi_hal_subghz_load_registers(furi_hal_subghz_preset_msk_99_97kb_async_regs);
furi_hal_subghz_load_patable(furi_hal_subghz_preset_msk_async_patable);
} else if(preset == FuriHalSubGhzPresetGFSK9_99KbAsync) {
furi_hal_subghz_load_registers(furi_hal_subghz_preset_gfsk_9_99kb_async_regs);
furi_hal_subghz_load_patable(furi_hal_subghz_preset_gfsk_async_patable);
} else {
furi_crash(NULL);
}
@ -438,10 +490,17 @@ void furi_hal_subghz_flush_rx() {
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
}
void furi_hal_subghz_flush_tx() {
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
cc1101_flush_tx(&furi_hal_spi_bus_handle_subghz);
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
}
bool furi_hal_subghz_rx_pipe_not_empty() {
CC1101RxBytes status[1];
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
cc1101_read_reg(&furi_hal_spi_bus_handle_subghz, (CC1101_STATUS_RXBYTES) | CC1101_BURST, (uint8_t*)status);
cc1101_read_reg(
&furi_hal_spi_bus_handle_subghz, (CC1101_STATUS_RXBYTES) | CC1101_BURST, (uint8_t*)status);
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
// TODO: you can add a buffer overflow flag if needed
if(status->NUM_RXBYTES > 0) {
@ -520,6 +579,14 @@ float furi_hal_subghz_get_rssi() {
return rssi;
}
uint8_t furi_hal_subghz_get_lqi() {
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
uint8_t data[1];
cc1101_read_reg(&furi_hal_spi_bus_handle_subghz, CC1101_STATUS_LQI | CC1101_BURST, data);
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
return data[0] & 0x7F;
}
bool furi_hal_subghz_is_frequency_valid(uint32_t value) {
if(!(value >= 299999755 && value <= 348000335) &&
!(value >= 386999938 && value <= 464000000) &&
@ -607,13 +674,15 @@ void furi_hal_subghz_set_path(FuriHalSubGhzPath path) {
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
if(path == FuriHalSubGhzPath433) {
hal_gpio_write(&gpio_rf_sw_0, 0);
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
cc1101_write_reg(
&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
} else if(path == FuriHalSubGhzPath315) {
hal_gpio_write(&gpio_rf_sw_0, 1);
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW);
} else if(path == FuriHalSubGhzPath868) {
hal_gpio_write(&gpio_rf_sw_0, 1);
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
cc1101_write_reg(
&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
} else if(path == FuriHalSubGhzPathIsolate) {
hal_gpio_write(&gpio_rf_sw_0, 0);
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW);

View File

@ -291,6 +291,45 @@ static const uint8_t furi_hal_subghz_preset_msk_99_97kb_async_regs[][2] = {
/* End */
{0, 0},
};
static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs[][2] = {
{CC1101_IOCFG0, 0x06}, //GDO0 Output Pin Configuration
{CC1101_FIFOTHR, 0x47}, //RX FIFO and TX FIFO Thresholds
//1 : CRC calculation in TX and CRC check in RX enabled,
//1 : Variable packet length mode. Packet length configured by the first byte after sync word
{CC1101_PKTCTRL0,0x05},
{CC1101_FSCTRL1, 0x06}, //Frequency Synthesizer Control
{CC1101_SYNC1, 0x46},
{CC1101_SYNC0, 0x4C},
{CC1101_ADDR, 0x00},
{CC1101_PKTLEN, 0x00},
{CC1101_MDMCFG4, 0xC8}, //Modem Configuration 9.99
{CC1101_MDMCFG3, 0x93}, //Modem Configuration
{CC1101_MDMCFG2, 0x12}, // 2: 16/16 sync word bits detected
{CC1101_DEVIATN, 0x34}, //Deviation = 19.042969
{CC1101_MCSM0, 0x18}, //Main Radio Control State Machine Configuration
{CC1101_FOCCFG, 0x16}, //Frequency Offset Compensation Configuration
{CC1101_AGCCTRL2, 0x43 }, //AGC Control
{CC1101_AGCCTRL1, 0x40},
{CC1101_AGCCTRL0, 0x91},
{CC1101_WORCTRL, 0xFB}, //Wake On Radio Control
{CC1101_FSCAL3, 0xE9}, //Frequency Synthesizer Calibration
{CC1101_FSCAL2, 0x2A}, //Frequency Synthesizer Calibration
{CC1101_FSCAL1, 0x00}, //Frequency Synthesizer Calibration
{CC1101_FSCAL0, 0x1F}, //Frequency Synthesizer Calibration
{CC1101_TEST2, 0x81}, //Various Test Settings
{CC1101_TEST1, 0x35}, //Various Test Settings
{CC1101_TEST0, 0x09}, //Various Test Settings
/* End */
{0, 0},
};
static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = {
0x00,
@ -319,6 +358,15 @@ static const uint8_t furi_hal_subghz_preset_msk_async_patable[8] = {
0x00,
0x00,
0x00};
static const uint8_t furi_hal_subghz_preset_gfsk_async_patable[8] = {
0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00};
void furi_hal_subghz_init() {
furi_assert(furi_hal_subghz_state == SubGhzStateInit);
@ -402,6 +450,9 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
} else if(preset == FuriHalSubGhzPresetMSK99_97KbAsync) {
furi_hal_subghz_load_registers(furi_hal_subghz_preset_msk_99_97kb_async_regs);
furi_hal_subghz_load_patable(furi_hal_subghz_preset_msk_async_patable);
} else if(preset == FuriHalSubGhzPresetGFSK9_99KbAsync) {
furi_hal_subghz_load_registers(furi_hal_subghz_preset_gfsk_9_99kb_async_regs);
furi_hal_subghz_load_patable(furi_hal_subghz_preset_gfsk_async_patable);
} else{
furi_crash(NULL);
}
@ -438,6 +489,12 @@ void furi_hal_subghz_flush_rx() {
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
}
void furi_hal_subghz_flush_tx() {
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
cc1101_flush_tx(&furi_hal_spi_bus_handle_subghz);
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
}
bool furi_hal_subghz_rx_pipe_not_empty() {
CC1101RxBytes status[1];
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
@ -520,6 +577,14 @@ float furi_hal_subghz_get_rssi() {
return rssi;
}
uint8_t furi_hal_subghz_get_lqi() {
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
uint8_t data[1];
cc1101_read_reg(&furi_hal_spi_bus_handle_subghz, CC1101_STATUS_LQI | CC1101_BURST, data);
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
return data[0] & 0x7F;
}
bool furi_hal_subghz_is_frequency_valid(uint32_t value) {
if(!(value >= 299999755 && value <= 348000335) &&
!(value >= 386999938 && value <= 464000000) &&

View File

@ -21,6 +21,7 @@ typedef enum {
FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */
FuriHalSubGhzPreset2FSKDev476Async, /**< FM, deviation 4.760742 kHz, asynchronous */
FuriHalSubGhzPresetMSK99_97KbAsync, /**< MSK, deviation 47.60742 kHz, 99.97Kb/s, asynchronous */
FuriHalSubGhzPresetGFSK9_99KbAsync /**< GFSK, deviation 19.042969 kHz, 9.996Kb/s, asynchronous */
} FuriHalSubGhzPreset;
/** Switchable Radio Paths */
@ -114,6 +115,10 @@ void furi_hal_subghz_read_packet(uint8_t* data, uint8_t* size);
*/
void furi_hal_subghz_flush_rx();
/** Flush tx FIFO buffer
*/
void furi_hal_subghz_flush_tx();
/** Shutdown Issue spwd command
* @warning registers content will be lost
*/
@ -144,6 +149,12 @@ bool furi_hal_subghz_tx();
*/
float furi_hal_subghz_get_rssi();
/** Get LQI
*
* @return LQI value
*/
uint8_t furi_hal_subghz_get_lqi();
/** Check if frequency is in valid range
*
* @param value frequency in Hz

View File

@ -5,11 +5,11 @@
#define TAG "SubGhzTxRxWorker"
#define GUBGHZ_TXRX_WORKER_BUF_SIZE 2048
#define SUBGHZ_TXRX_WORKER_BUF_SIZE 2048
//you can not set more than 62 because it will not fit into the FIFO CC1101
#define GUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE 60
#define SUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE 60
#define GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF 40
#define SUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF 40
struct SubGhzTxRxWorker {
FuriThread* thread;
@ -19,7 +19,7 @@ struct SubGhzTxRxWorker {
volatile bool worker_running;
volatile bool worker_stoping;
SubGhzTxRxWorkerStatus satus;
SubGhzTxRxWorkerStatus status;
uint32_t frequency;
@ -33,7 +33,7 @@ bool subghz_tx_rx_worker_write(SubGhzTxRxWorker* instance, uint8_t* data, size_t
size_t stream_tx_free_byte = xStreamBufferSpacesAvailable(instance->stream_tx);
if(size && (stream_tx_free_byte >= size)) {
if(xStreamBufferSend(
instance->stream_tx, data, size, GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF) ==
instance->stream_tx, data, size, SUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF) ==
size) {
ret = true;
}
@ -48,22 +48,7 @@ size_t subghz_tx_rx_worker_available(SubGhzTxRxWorker* instance) {
size_t subghz_tx_rx_worker_read(SubGhzTxRxWorker* instance, uint8_t* data, size_t size) {
furi_assert(instance);
size_t len = 0;
size_t stream_rx_byte = xStreamBufferBytesAvailable(instance->stream_rx);
if(stream_rx_byte > 0) {
if(stream_rx_byte <= size) {
len = xStreamBufferReceive(
instance->stream_rx,
data,
stream_rx_byte,
GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
} else {
len = xStreamBufferReceive(
instance->stream_rx, data, size, GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
}
}
return len;
return xStreamBufferReceive(instance->stream_rx, data, size, 0);
}
void subghz_tx_rx_worker_set_callback_have_read(
@ -78,11 +63,11 @@ void subghz_tx_rx_worker_set_callback_have_read(
}
bool subghz_tx_rx_worker_rx(SubGhzTxRxWorker* instance, uint8_t* data, uint8_t* size) {
uint8_t timeout = 20;
uint8_t timeout = 100;
bool ret = false;
if(instance->satus != SubGhzTxRxWorkerStatusRx) {
if(instance->status != SubGhzTxRxWorkerStatusRx) {
furi_hal_subghz_rx();
instance->satus = SubGhzTxRxWorkerStatusRx;
instance->status = SubGhzTxRxWorkerStatusRx;
osDelay(1);
}
//waiting for reception to complete
@ -97,6 +82,8 @@ bool subghz_tx_rx_worker_rx(SubGhzTxRxWorker* instance, uint8_t* data, uint8_t*
}
if(furi_hal_subghz_rx_pipe_not_empty()) {
FURI_LOG_I(
TAG, "RSSI: %03.1fdbm LQI: %d", furi_hal_subghz_get_rssi(), furi_hal_subghz_get_lqi());
if(furi_hal_subghz_is_rx_data_crc_valid()) {
furi_hal_subghz_read_packet(data, size);
ret = true;
@ -108,15 +95,13 @@ bool subghz_tx_rx_worker_rx(SubGhzTxRxWorker* instance, uint8_t* data, uint8_t*
}
void subghz_tx_rx_worker_tx(SubGhzTxRxWorker* instance, uint8_t* data, size_t size) {
uint8_t timeout = 40;
if(instance->satus != SubGhzTxRxWorkerStatusIDLE) {
uint8_t timeout = 200;
if(instance->status != SubGhzTxRxWorkerStatusIDLE) {
furi_hal_subghz_idle();
}
furi_hal_subghz_write_packet(data, size);
instance->satus = SubGhzTxRxWorkerStatusTx;
furi_hal_subghz_tx(); //start send
instance->status = SubGhzTxRxWorkerStatusTx;
while(!hal_gpio_read(&gpio_cc1101_g0)) { // Wait for GDO0 to be set -> sync transmitted
osDelay(1);
if(!--timeout) {
@ -132,7 +117,7 @@ void subghz_tx_rx_worker_tx(SubGhzTxRxWorker* instance, uint8_t* data, size_t si
}
}
furi_hal_subghz_idle();
instance->satus = SubGhzTxRxWorkerStatusIDLE;
instance->status = SubGhzTxRxWorkerStatusIDLE;
}
/** Worker thread
*
@ -145,13 +130,14 @@ static int32_t subghz_tx_rx_worker_thread(void* context) {
furi_hal_subghz_reset();
furi_hal_subghz_idle();
furi_hal_subghz_load_preset(FuriHalSubGhzPresetMSK99_97KbAsync);
furi_hal_subghz_load_preset(FuriHalSubGhzPresetGFSK9_99KbAsync);
//furi_hal_subghz_load_preset(FuriHalSubGhzPresetMSK99_97KbAsync);
hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
furi_hal_subghz_set_frequency_and_path(instance->frequency);
furi_hal_subghz_flush_rx();
uint8_t data[GUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE] = {0};
uint8_t data[SUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE + 1] = {0};
size_t size_tx = 0;
uint8_t size_rx[1] = {0};
uint8_t timeout_tx = 0;
@ -161,18 +147,18 @@ static int32_t subghz_tx_rx_worker_thread(void* context) {
//transmit
size_tx = xStreamBufferBytesAvailable(instance->stream_tx);
if(size_tx > 0 && !timeout_tx) {
timeout_tx = 20; //20ms
if(size_tx > GUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE) {
timeout_tx = 10; //20ms
if(size_tx > SUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE) {
xStreamBufferReceive(
instance->stream_tx,
&data,
GUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE,
GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
subghz_tx_rx_worker_tx(instance, data, GUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE);
SUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE,
SUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
subghz_tx_rx_worker_tx(instance, data, SUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE);
} else {
//todo checking that he managed to write all the data to the TX buffer
xStreamBufferReceive(
instance->stream_tx, &data, size_tx, GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
instance->stream_tx, &data, size_tx, SUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
subghz_tx_rx_worker_tx(instance, data, size_tx);
}
} else {
@ -188,7 +174,7 @@ static int32_t subghz_tx_rx_worker_thread(void* context) {
instance->stream_rx,
&data,
size_rx[0],
GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
SUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
if(callback_rx) {
instance->callback_have_read(instance->context_have_read);
callback_rx = false;
@ -219,11 +205,11 @@ SubGhzTxRxWorker* subghz_tx_rx_worker_alloc() {
furi_thread_set_context(instance->thread, instance);
furi_thread_set_callback(instance->thread, subghz_tx_rx_worker_thread);
instance->stream_tx =
xStreamBufferCreate(sizeof(uint8_t) * GUBGHZ_TXRX_WORKER_BUF_SIZE, sizeof(uint8_t));
xStreamBufferCreate(sizeof(uint8_t) * SUBGHZ_TXRX_WORKER_BUF_SIZE, sizeof(uint8_t));
instance->stream_rx =
xStreamBufferCreate(sizeof(uint8_t) * GUBGHZ_TXRX_WORKER_BUF_SIZE, sizeof(uint8_t));
xStreamBufferCreate(sizeof(uint8_t) * SUBGHZ_TXRX_WORKER_BUF_SIZE, sizeof(uint8_t));
instance->satus = SubGhzTxRxWorkerStatusIDLE;
instance->status = SubGhzTxRxWorkerStatusIDLE;
instance->worker_stoping = true;
return instance;
@ -231,7 +217,7 @@ SubGhzTxRxWorker* subghz_tx_rx_worker_alloc() {
void subghz_tx_rx_worker_free(SubGhzTxRxWorker* instance) {
furi_assert(instance);
furi_assert(!instance->worker_running);
vStreamBufferDelete(instance->stream_tx);
vStreamBufferDelete(instance->stream_rx);
furi_thread_free(instance->thread);