SubGhz: sending / receiving messages via subghz (#851)
* SubGhz: add worker subghz_txrx * SubGhz: added support for transferring Russian characters and support for backspace in CLI subghz_txrx * SubGhz: refactoring subghz_txrx_worker, added a callback for accepting data in an empty one RX buffer * SubGhz: fix conflict * SubGhz: fix syntax errors * Cli: document string_move usage and its behavior * FuriHal: update subghz api and documentation. Subghz: move chat to subghz cli subcommand. * Subghz: update text in chat cli Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
parent
54c41e4189
commit
b912cc7991
@ -113,7 +113,9 @@ void cli_prompt(Cli* cli) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cli_reset(Cli* cli) {
|
void cli_reset(Cli* cli) {
|
||||||
|
// cli->last_line is cleared and cli->line's buffer moved to cli->last_line
|
||||||
string_move(cli->last_line, cli->line);
|
string_move(cli->last_line, cli->line);
|
||||||
|
// Reiniting cli->line
|
||||||
string_init(cli->line);
|
string_init(cli->line);
|
||||||
cli->cursor_position = 0;
|
cli->cursor_position = 0;
|
||||||
}
|
}
|
||||||
@ -129,7 +131,11 @@ static void cli_handle_backspace(Cli* cli) {
|
|||||||
string_reserve(temp, string_size(cli->line) - 1);
|
string_reserve(temp, string_size(cli->line) - 1);
|
||||||
string_set_strn(temp, string_get_cstr(cli->line), cli->cursor_position - 1);
|
string_set_strn(temp, string_get_cstr(cli->line), cli->cursor_position - 1);
|
||||||
string_cat_str(temp, string_get_cstr(cli->line) + cli->cursor_position);
|
string_cat_str(temp, string_get_cstr(cli->line) + cli->cursor_position);
|
||||||
|
|
||||||
|
// cli->line is cleared and temp's buffer moved to cli->line
|
||||||
string_move(cli->line, temp);
|
string_move(cli->line, temp);
|
||||||
|
// NO MEMORY LEAK, STOP REPORTING IT
|
||||||
|
|
||||||
cli->cursor_position--;
|
cli->cursor_position--;
|
||||||
} else {
|
} else {
|
||||||
cli_putc(CliSymbolAsciiBell);
|
cli_putc(CliSymbolAsciiBell);
|
||||||
@ -332,7 +338,11 @@ void cli_process_input(Cli* cli) {
|
|||||||
string_set_strn(temp, string_get_cstr(cli->line), cli->cursor_position);
|
string_set_strn(temp, string_get_cstr(cli->line), cli->cursor_position);
|
||||||
string_push_back(temp, c);
|
string_push_back(temp, c);
|
||||||
string_cat_str(temp, string_get_cstr(cli->line) + cli->cursor_position);
|
string_cat_str(temp, string_get_cstr(cli->line) + cli->cursor_position);
|
||||||
|
|
||||||
|
// cli->line is cleared and temp's buffer moved to cli->line
|
||||||
string_move(cli->line, temp);
|
string_move(cli->line, temp);
|
||||||
|
// NO MEMORY LEAK, STOP REPORTING IT
|
||||||
|
|
||||||
// Print character in replace mode
|
// Print character in replace mode
|
||||||
printf("\e[4h%c\e[4l", c);
|
printf("\e[4h%c\e[4l", c);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
@ -9,11 +9,12 @@
|
|||||||
#include <lib/subghz/subghz_keystore.h>
|
#include <lib/subghz/subghz_keystore.h>
|
||||||
#include <lib/subghz/protocols/subghz_protocol_common.h>
|
#include <lib/subghz/protocols/subghz_protocol_common.h>
|
||||||
#include <lib/subghz/protocols/subghz_protocol_princeton.h>
|
#include <lib/subghz/protocols/subghz_protocol_princeton.h>
|
||||||
|
#include <lib/subghz/subghz_tx_rx_worker.h>
|
||||||
|
|
||||||
#define SUBGHZ_FREQUENCY_RANGE_STR \
|
#define SUBGHZ_FREQUENCY_RANGE_STR \
|
||||||
"299999755...348000000 or 386999938...464000000 or 778999847...928000000"
|
"299999755...348000000 or 386999938...464000000 or 778999847...928000000"
|
||||||
|
|
||||||
void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context) {
|
static void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context) {
|
||||||
uint32_t frequency = 433920000;
|
uint32_t frequency = 433920000;
|
||||||
|
|
||||||
if(string_size(args)) {
|
if(string_size(args)) {
|
||||||
@ -56,7 +57,7 @@ void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context) {
|
|||||||
furi_hal_power_suppress_charge_exit();
|
furi_hal_power_suppress_charge_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_cli_command_rx_carrier(Cli* cli, string_t args, void* context) {
|
static void subghz_cli_command_rx_carrier(Cli* cli, string_t args, void* context) {
|
||||||
uint32_t frequency = 433920000;
|
uint32_t frequency = 433920000;
|
||||||
|
|
||||||
if(string_size(args)) {
|
if(string_size(args)) {
|
||||||
@ -96,7 +97,7 @@ void subghz_cli_command_rx_carrier(Cli* cli, string_t args, void* context) {
|
|||||||
furi_hal_subghz_sleep();
|
furi_hal_subghz_sleep();
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_cli_command_tx(Cli* cli, string_t args, void* context) {
|
static void subghz_cli_command_tx(Cli* cli, string_t args, void* context) {
|
||||||
uint32_t frequency = 433920000;
|
uint32_t frequency = 433920000;
|
||||||
uint32_t key = 0x0074BADE;
|
uint32_t key = 0x0074BADE;
|
||||||
size_t repeat = 10;
|
size_t repeat = 10;
|
||||||
@ -187,7 +188,7 @@ static void subghz_cli_command_rx_text_callback(string_t text, void* context) {
|
|||||||
printf("%s", string_get_cstr(text));
|
printf("%s", string_get_cstr(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
|
static void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
|
||||||
uint32_t frequency = 433920000;
|
uint32_t frequency = 433920000;
|
||||||
|
|
||||||
if(string_size(args)) {
|
if(string_size(args)) {
|
||||||
@ -260,7 +261,7 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
|
|||||||
free(instance);
|
free(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_cli_command_print_usage() {
|
static void subghz_cli_command_print_usage() {
|
||||||
printf("Usage:\r\n");
|
printf("Usage:\r\n");
|
||||||
printf("subghz <cmd> <args>\r\n");
|
printf("subghz <cmd> <args>\r\n");
|
||||||
printf("Cmd list:\r\n");
|
printf("Cmd list:\r\n");
|
||||||
@ -268,9 +269,10 @@ void subghz_cli_command_print_usage() {
|
|||||||
"\tencrypt_keeloq <path_decrypted_file> <path_encrypted_file> <IV:16 bytes in hex>\t - Encrypt keeloq manufacture keys\r\n");
|
"\tencrypt_keeloq <path_decrypted_file> <path_encrypted_file> <IV:16 bytes in hex>\t - Encrypt keeloq manufacture keys\r\n");
|
||||||
printf(
|
printf(
|
||||||
"\tencrypt_raw <path_decrypted_file> <path_encrypted_file> <IV:16 bytes in hex>\t - Encrypt RAW data\r\n");
|
"\tencrypt_raw <path_decrypted_file> <path_encrypted_file> <IV:16 bytes in hex>\t - Encrypt RAW data\r\n");
|
||||||
|
printf("\tchat <frequency:in Herz>\t - Chat with other Flippers\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_cli_command_encrypt_keeloq(Cli* cli, string_t args) {
|
static void subghz_cli_command_encrypt_keeloq(Cli* cli, string_t args) {
|
||||||
uint8_t iv[16];
|
uint8_t iv[16];
|
||||||
|
|
||||||
string_t source;
|
string_t source;
|
||||||
@ -312,7 +314,7 @@ void subghz_cli_command_encrypt_keeloq(Cli* cli, string_t args) {
|
|||||||
string_clear(source);
|
string_clear(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_cli_command_encrypt_raw(Cli* cli, string_t args) {
|
static void subghz_cli_command_encrypt_raw(Cli* cli, string_t args) {
|
||||||
uint8_t iv[16];
|
uint8_t iv[16];
|
||||||
|
|
||||||
string_t source;
|
string_t source;
|
||||||
@ -348,7 +350,110 @@ void subghz_cli_command_encrypt_raw(Cli* cli, string_t args) {
|
|||||||
string_clear(source);
|
string_clear(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_cli_command(Cli* cli, string_t args, void* context) {
|
static void subghz_cli_command_chat(Cli* cli, string_t args) {
|
||||||
|
uint32_t frequency = 433920000;
|
||||||
|
|
||||||
|
if(string_size(args)) {
|
||||||
|
int ret = sscanf(string_get_cstr(args), "%lu", &frequency);
|
||||||
|
if(ret != 1) {
|
||||||
|
printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency);
|
||||||
|
cli_print_usage("subghz_txrx", "<Frequency in HZ>", string_get_cstr(args));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
|
||||||
|
printf(
|
||||||
|
"Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n",
|
||||||
|
frequency);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!furi_hal_subghz_is_tx_allowed(frequency)) {
|
||||||
|
printf(
|
||||||
|
"In your region, only reception on this frequency (%lu) is allowed,\r\n"
|
||||||
|
"the actual operation of the application is not possible\r\n ",
|
||||||
|
frequency);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzTxRxWorker* subghz_txrx = subghz_tx_rx_worker_alloc();
|
||||||
|
subghz_tx_rx_worker_start(subghz_txrx, frequency);
|
||||||
|
|
||||||
|
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);
|
||||||
|
char c;
|
||||||
|
bool exit = false;
|
||||||
|
|
||||||
|
string_printf(name, "\033[0;33m%s\033[0m: ", furi_hal_version_get_name_ptr());
|
||||||
|
string_set(input, name);
|
||||||
|
printf("%s", string_get_cstr(input));
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
while(!exit) {
|
||||||
|
if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 0) == 1) {
|
||||||
|
if(c == CliSymbolAsciiETX) {
|
||||||
|
printf("\r\n");
|
||||||
|
exit = true;
|
||||||
|
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) {
|
||||||
|
size_t len = string_size(input);
|
||||||
|
if(len > string_size(name)) {
|
||||||
|
string_set_strn(input, string_get_cstr(input), len - 1);
|
||||||
|
printf("\r");
|
||||||
|
for(uint8_t i = 0; i < len; i++) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
printf("\r%s", string_get_cstr(input));
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
} else if(c == CliSymbolAsciiCR) {
|
||||||
|
printf("\r\n");
|
||||||
|
subghz_tx_rx_worker_write(
|
||||||
|
subghz_txrx, (uint8_t*)string_get_cstr(input), strlen(string_get_cstr(input)));
|
||||||
|
string_printf(input, "%s", string_get_cstr(name));
|
||||||
|
printf("%s", string_get_cstr(input));
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(subghz_tx_rx_worker_available(subghz_txrx)) {
|
||||||
|
memset(message, 0x00, message_max_len);
|
||||||
|
subghz_tx_rx_worker_read(subghz_txrx, message, message_max_len);
|
||||||
|
printf("\r");
|
||||||
|
for(uint8_t i = 0; i < 80; i++) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\r %s\r\n", message);
|
||||||
|
|
||||||
|
printf("%s", string_get_cstr(input));
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\r\nExit chat\r\n");
|
||||||
|
string_clear(input);
|
||||||
|
string_clear(name);
|
||||||
|
furi_hal_power_suppress_charge_exit();
|
||||||
|
|
||||||
|
if(subghz_tx_rx_worker_is_running(subghz_txrx)) {
|
||||||
|
subghz_tx_rx_worker_stop(subghz_txrx);
|
||||||
|
subghz_tx_rx_worker_free(subghz_txrx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void subghz_cli_command(Cli* cli, string_t args, void* context) {
|
||||||
string_t cmd;
|
string_t cmd;
|
||||||
string_init(cmd);
|
string_init(cmd);
|
||||||
|
|
||||||
@ -368,6 +473,11 @@ void subghz_cli_command(Cli* cli, string_t args, void* context) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(string_cmp_str(cmd, "chat") == 0) {
|
||||||
|
subghz_cli_command_chat(cli, args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
subghz_cli_command_print_usage();
|
subghz_cli_command_print_usage();
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
|
@ -244,6 +244,54 @@ static const uint8_t furi_hal_subghz_preset_2fsk_dev4_76khz_async_regs[][2] = {
|
|||||||
/* End */
|
/* End */
|
||||||
{0, 0},
|
{0, 0},
|
||||||
};
|
};
|
||||||
|
static const uint8_t furi_hal_subghz_preset_msk_99_97kb_async_regs[][2] = {
|
||||||
|
/* GPIO GD0 */
|
||||||
|
{CC1101_IOCFG0, 0x06},
|
||||||
|
|
||||||
|
{CC1101_FIFOTHR, 0x07}, // The only important bit is ADC_RETENTION
|
||||||
|
{CC1101_SYNC1, 0x46},
|
||||||
|
{CC1101_SYNC0, 0x4C},
|
||||||
|
{CC1101_ADDR, 0x00},
|
||||||
|
{CC1101_PKTLEN, 0x00},
|
||||||
|
{CC1101_CHANNR, 0x00},
|
||||||
|
|
||||||
|
{CC1101_PKTCTRL0, 0x05},
|
||||||
|
|
||||||
|
{CC1101_FSCTRL0, 0x23},
|
||||||
|
{CC1101_FSCTRL1, 0x06},
|
||||||
|
|
||||||
|
{CC1101_MDMCFG0, 0xF8},
|
||||||
|
{CC1101_MDMCFG1, 0x22},
|
||||||
|
{CC1101_MDMCFG2, 0x72},
|
||||||
|
{CC1101_MDMCFG3, 0xF8},
|
||||||
|
{CC1101_MDMCFG4, 0x5B},
|
||||||
|
{CC1101_DEVIATN, 0x47},
|
||||||
|
|
||||||
|
{CC1101_MCSM0, 0x18},
|
||||||
|
{CC1101_FOCCFG, 0x16},
|
||||||
|
|
||||||
|
{CC1101_AGCCTRL0, 0xB2},
|
||||||
|
{CC1101_AGCCTRL1, 0x00},
|
||||||
|
{CC1101_AGCCTRL2, 0xC7},
|
||||||
|
|
||||||
|
{CC1101_FREND0, 0x10},
|
||||||
|
{CC1101_FREND1, 0x56},
|
||||||
|
|
||||||
|
{CC1101_FSCAL3, 0xE9},
|
||||||
|
{CC1101_FSCAL2, 0x2A},
|
||||||
|
{CC1101_FSCAL1, 0x00},
|
||||||
|
{CC1101_FSCAL0, 0x1F},
|
||||||
|
|
||||||
|
{CC1101_BSCFG, 0x1C},
|
||||||
|
{CC1101_FSTEST, 0x59},
|
||||||
|
|
||||||
|
{CC1101_TEST2, 0x81},
|
||||||
|
{CC1101_TEST1, 0x35},
|
||||||
|
{CC1101_TEST0, 0x09},
|
||||||
|
/* End */
|
||||||
|
{0, 0},
|
||||||
|
};
|
||||||
|
|
||||||
static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = {
|
static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = {
|
||||||
0x00,
|
0x00,
|
||||||
0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
|
0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
|
||||||
@ -261,9 +309,16 @@ static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = {
|
|||||||
0x00,
|
0x00,
|
||||||
0x00,
|
0x00,
|
||||||
0x00,
|
0x00,
|
||||||
0x00
|
0x00};
|
||||||
|
static const uint8_t furi_hal_subghz_preset_msk_async_patable[8] = {
|
||||||
};
|
0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00};
|
||||||
|
|
||||||
void furi_hal_subghz_init() {
|
void furi_hal_subghz_init() {
|
||||||
furi_assert(furi_hal_subghz_state == SubGhzStateInit);
|
furi_assert(furi_hal_subghz_state == SubGhzStateInit);
|
||||||
@ -344,6 +399,9 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
|
|||||||
} else if(preset == FuriHalSubGhzPreset2FSKDev476Async) {
|
} else if(preset == FuriHalSubGhzPreset2FSKDev476Async) {
|
||||||
furi_hal_subghz_load_registers(furi_hal_subghz_preset_2fsk_dev4_76khz_async_regs);
|
furi_hal_subghz_load_registers(furi_hal_subghz_preset_2fsk_dev4_76khz_async_regs);
|
||||||
furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable);
|
furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable);
|
||||||
|
} 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 {
|
} else {
|
||||||
furi_crash(NULL);
|
furi_crash(NULL);
|
||||||
}
|
}
|
||||||
@ -369,6 +427,7 @@ void furi_hal_subghz_load_patable(const uint8_t data[8]) {
|
|||||||
void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size) {
|
void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size) {
|
||||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||||
cc1101_flush_tx(&furi_hal_spi_bus_handle_subghz);
|
cc1101_flush_tx(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_FIFO, size);
|
||||||
cc1101_write_fifo(&furi_hal_spi_bus_handle_subghz, data, size);
|
cc1101_write_fifo(&furi_hal_spi_bus_handle_subghz, data, size);
|
||||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||||
}
|
}
|
||||||
@ -379,6 +438,31 @@ void furi_hal_subghz_flush_rx() {
|
|||||||
furi_hal_spi_release(&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);
|
||||||
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
// TODO: you can add a buffer overflow flag if needed
|
||||||
|
if(status->NUM_RXBYTES > 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool furi_hal_subghz_is_rx_data_crc_valid() {
|
||||||
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
uint8_t data[1];
|
||||||
|
cc1101_read_reg(&furi_hal_spi_bus_handle_subghz, CC1101_STATUS_LQI | CC1101_BURST, data);
|
||||||
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
if(((data[0] >> 7) & 0x01)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void furi_hal_subghz_read_packet(uint8_t* data, uint8_t* size) {
|
void furi_hal_subghz_read_packet(uint8_t* data, uint8_t* size) {
|
||||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||||
cc1101_read_fifo(&furi_hal_spi_bus_handle_subghz, data, size);
|
cc1101_read_fifo(&furi_hal_spi_bus_handle_subghz, data, size);
|
||||||
@ -460,18 +544,16 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
|
bool furi_hal_subghz_is_tx_allowed(uint32_t value) {
|
||||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
|
||||||
|
|
||||||
//checking regional settings
|
//checking regional settings
|
||||||
bool txrx = false;
|
bool is_allowed = false;
|
||||||
switch(furi_hal_version_get_hw_region()) {
|
switch(furi_hal_version_get_hw_region()) {
|
||||||
case FuriHalVersionRegionEuRu:
|
case FuriHalVersionRegionEuRu:
|
||||||
//433,05..434,79; 868,15..868,55
|
//433,05..434,79; 868,15..868,55
|
||||||
if(!(value >= 433050000 && value <= 434790000) &&
|
if(!(value >= 433050000 && value <= 434790000) &&
|
||||||
!(value >= 868150000 && value <= 868550000)) {
|
!(value >= 868150000 && value <= 868550000)) {
|
||||||
} else {
|
} else {
|
||||||
txrx = true;
|
is_allowed = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FuriHalVersionRegionUsCaAu:
|
case FuriHalVersionRegionUsCaAu:
|
||||||
@ -480,7 +562,7 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
|
|||||||
!(value >= 433050000 && value <= 434790000) &&
|
!(value >= 433050000 && value <= 434790000) &&
|
||||||
!(value >= 915000000 && value <= 928000000)) {
|
!(value >= 915000000 && value <= 928000000)) {
|
||||||
} else {
|
} else {
|
||||||
txrx = true;
|
is_allowed = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FuriHalVersionRegionJp:
|
case FuriHalVersionRegionJp:
|
||||||
@ -488,16 +570,21 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
|
|||||||
if(!(value >= 312000000 && value <= 315250000) &&
|
if(!(value >= 312000000 && value <= 315250000) &&
|
||||||
!(value >= 920500000 && value <= 923500000)) {
|
!(value >= 920500000 && value <= 923500000)) {
|
||||||
} else {
|
} else {
|
||||||
txrx = true;
|
is_allowed = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
txrx = true;
|
is_allowed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return is_allowed;
|
||||||
|
}
|
||||||
|
|
||||||
if(txrx) {
|
uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
|
||||||
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
|
||||||
|
if(furi_hal_subghz_is_tx_allowed(value)) {
|
||||||
furi_hal_subghz_regulation = SubGhzRegulationTxRx;
|
furi_hal_subghz_regulation = SubGhzRegulationTxRx;
|
||||||
} else {
|
} else {
|
||||||
furi_hal_subghz_regulation = SubGhzRegulationOnlyRx;
|
furi_hal_subghz_regulation = SubGhzRegulationOnlyRx;
|
||||||
|
@ -244,6 +244,54 @@ static const uint8_t furi_hal_subghz_preset_2fsk_dev4_76khz_async_regs[][2] = {
|
|||||||
/* End */
|
/* End */
|
||||||
{0, 0},
|
{0, 0},
|
||||||
};
|
};
|
||||||
|
static const uint8_t furi_hal_subghz_preset_msk_99_97kb_async_regs[][2] = {
|
||||||
|
/* GPIO GD0 */
|
||||||
|
{CC1101_IOCFG0, 0x06},
|
||||||
|
|
||||||
|
{CC1101_FIFOTHR, 0x07}, // The only important bit is ADC_RETENTION
|
||||||
|
{CC1101_SYNC1, 0x46},
|
||||||
|
{CC1101_SYNC0, 0x4C},
|
||||||
|
{CC1101_ADDR, 0x00},
|
||||||
|
{CC1101_PKTLEN, 0x00},
|
||||||
|
{CC1101_CHANNR, 0x00},
|
||||||
|
|
||||||
|
{CC1101_PKTCTRL0, 0x05},
|
||||||
|
|
||||||
|
{CC1101_FSCTRL0, 0x23},
|
||||||
|
{CC1101_FSCTRL1, 0x06},
|
||||||
|
|
||||||
|
{CC1101_MDMCFG0, 0xF8},
|
||||||
|
{CC1101_MDMCFG1, 0x22},
|
||||||
|
{CC1101_MDMCFG2, 0x72},
|
||||||
|
{CC1101_MDMCFG3, 0xF8},
|
||||||
|
{CC1101_MDMCFG4, 0x5B},
|
||||||
|
{CC1101_DEVIATN, 0x47},
|
||||||
|
|
||||||
|
{CC1101_MCSM0, 0x18},
|
||||||
|
{CC1101_FOCCFG, 0x16},
|
||||||
|
|
||||||
|
{CC1101_AGCCTRL0, 0xB2},
|
||||||
|
{CC1101_AGCCTRL1, 0x00},
|
||||||
|
{CC1101_AGCCTRL2, 0xC7},
|
||||||
|
|
||||||
|
{CC1101_FREND0, 0x10},
|
||||||
|
{CC1101_FREND1, 0x56},
|
||||||
|
|
||||||
|
{CC1101_FSCAL3, 0xE9},
|
||||||
|
{CC1101_FSCAL2, 0x2A},
|
||||||
|
{CC1101_FSCAL1, 0x00},
|
||||||
|
{CC1101_FSCAL0, 0x1F},
|
||||||
|
|
||||||
|
{CC1101_BSCFG, 0x1C},
|
||||||
|
{CC1101_FSTEST, 0x59},
|
||||||
|
|
||||||
|
{CC1101_TEST2, 0x81},
|
||||||
|
{CC1101_TEST1, 0x35},
|
||||||
|
{CC1101_TEST0, 0x09},
|
||||||
|
/* End */
|
||||||
|
{0, 0},
|
||||||
|
};
|
||||||
|
|
||||||
static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = {
|
static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = {
|
||||||
0x00,
|
0x00,
|
||||||
0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
|
0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
|
||||||
@ -261,9 +309,16 @@ static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = {
|
|||||||
0x00,
|
0x00,
|
||||||
0x00,
|
0x00,
|
||||||
0x00,
|
0x00,
|
||||||
0x00
|
0x00};
|
||||||
|
static const uint8_t furi_hal_subghz_preset_msk_async_patable[8] = {
|
||||||
};
|
0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00};
|
||||||
|
|
||||||
void furi_hal_subghz_init() {
|
void furi_hal_subghz_init() {
|
||||||
furi_assert(furi_hal_subghz_state == SubGhzStateInit);
|
furi_assert(furi_hal_subghz_state == SubGhzStateInit);
|
||||||
@ -344,6 +399,9 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
|
|||||||
} else if(preset == FuriHalSubGhzPreset2FSKDev476Async) {
|
} else if(preset == FuriHalSubGhzPreset2FSKDev476Async) {
|
||||||
furi_hal_subghz_load_registers(furi_hal_subghz_preset_2fsk_dev4_76khz_async_regs);
|
furi_hal_subghz_load_registers(furi_hal_subghz_preset_2fsk_dev4_76khz_async_regs);
|
||||||
furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable);
|
furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable);
|
||||||
|
} 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 {
|
} else {
|
||||||
furi_crash(NULL);
|
furi_crash(NULL);
|
||||||
}
|
}
|
||||||
@ -369,6 +427,7 @@ void furi_hal_subghz_load_patable(const uint8_t data[8]) {
|
|||||||
void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size) {
|
void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size) {
|
||||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||||
cc1101_flush_tx(&furi_hal_spi_bus_handle_subghz);
|
cc1101_flush_tx(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_FIFO, size);
|
||||||
cc1101_write_fifo(&furi_hal_spi_bus_handle_subghz, data, size);
|
cc1101_write_fifo(&furi_hal_spi_bus_handle_subghz, data, size);
|
||||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||||
}
|
}
|
||||||
@ -379,6 +438,31 @@ void furi_hal_subghz_flush_rx() {
|
|||||||
furi_hal_spi_release(&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);
|
||||||
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
// TODO: you can add a buffer overflow flag if needed
|
||||||
|
if(status->NUM_RXBYTES > 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool furi_hal_subghz_is_rx_data_crc_valid() {
|
||||||
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
uint8_t data[1];
|
||||||
|
cc1101_read_reg(&furi_hal_spi_bus_handle_subghz, CC1101_STATUS_LQI | CC1101_BURST, data);
|
||||||
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
if(((data[0] >> 7) & 0x01)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void furi_hal_subghz_read_packet(uint8_t* data, uint8_t* size) {
|
void furi_hal_subghz_read_packet(uint8_t* data, uint8_t* size) {
|
||||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||||
cc1101_read_fifo(&furi_hal_spi_bus_handle_subghz, data, size);
|
cc1101_read_fifo(&furi_hal_spi_bus_handle_subghz, data, size);
|
||||||
@ -460,18 +544,16 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
|
bool furi_hal_subghz_is_tx_allowed(uint32_t value) {
|
||||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
|
||||||
|
|
||||||
//checking regional settings
|
//checking regional settings
|
||||||
bool txrx = false;
|
bool is_allowed = false;
|
||||||
switch(furi_hal_version_get_hw_region()) {
|
switch(furi_hal_version_get_hw_region()) {
|
||||||
case FuriHalVersionRegionEuRu:
|
case FuriHalVersionRegionEuRu:
|
||||||
//433,05..434,79; 868,15..868,55
|
//433,05..434,79; 868,15..868,55
|
||||||
if(!(value >= 433050000 && value <= 434790000) &&
|
if(!(value >= 433050000 && value <= 434790000) &&
|
||||||
!(value >= 868150000 && value <= 868550000)) {
|
!(value >= 868150000 && value <= 868550000)) {
|
||||||
} else {
|
} else {
|
||||||
txrx = true;
|
is_allowed = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FuriHalVersionRegionUsCaAu:
|
case FuriHalVersionRegionUsCaAu:
|
||||||
@ -480,7 +562,7 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
|
|||||||
!(value >= 433050000 && value <= 434790000) &&
|
!(value >= 433050000 && value <= 434790000) &&
|
||||||
!(value >= 915000000 && value <= 928000000)) {
|
!(value >= 915000000 && value <= 928000000)) {
|
||||||
} else {
|
} else {
|
||||||
txrx = true;
|
is_allowed = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FuriHalVersionRegionJp:
|
case FuriHalVersionRegionJp:
|
||||||
@ -488,16 +570,21 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
|
|||||||
if(!(value >= 312000000 && value <= 315250000) &&
|
if(!(value >= 312000000 && value <= 315250000) &&
|
||||||
!(value >= 920500000 && value <= 923500000)) {
|
!(value >= 920500000 && value <= 923500000)) {
|
||||||
} else {
|
} else {
|
||||||
txrx = true;
|
is_allowed = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
txrx = true;
|
is_allowed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return is_allowed;
|
||||||
|
}
|
||||||
|
|
||||||
if(txrx) {
|
uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
|
||||||
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
|
||||||
|
if(furi_hal_subghz_is_tx_allowed(value)) {
|
||||||
furi_hal_subghz_regulation = SubGhzRegulationTxRx;
|
furi_hal_subghz_regulation = SubGhzRegulationTxRx;
|
||||||
} else {
|
} else {
|
||||||
furi_hal_subghz_regulation = SubGhzRegulationOnlyRx;
|
furi_hal_subghz_regulation = SubGhzRegulationOnlyRx;
|
||||||
|
@ -20,6 +20,7 @@ typedef enum {
|
|||||||
FuriHalSubGhzPresetOok650Async, /**< OOK, bandwidth 650kHz, asynchronous */
|
FuriHalSubGhzPresetOok650Async, /**< OOK, bandwidth 650kHz, asynchronous */
|
||||||
FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */
|
FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */
|
||||||
FuriHalSubGhzPreset2FSKDev476Async, /**< FM, deviation 4.760742 kHz, asynchronous */
|
FuriHalSubGhzPreset2FSKDev476Async, /**< FM, deviation 4.760742 kHz, asynchronous */
|
||||||
|
FuriHalSubGhzPresetMSK99_97KbAsync, /**< MSK, deviation 47.60742 kHz, 99.97Kb/s, asynchronous */
|
||||||
} FuriHalSubGhzPreset;
|
} FuriHalSubGhzPreset;
|
||||||
|
|
||||||
/** Switchable Radio Paths */
|
/** Switchable Radio Paths */
|
||||||
@ -90,6 +91,18 @@ void furi_hal_subghz_load_patable(const uint8_t data[8]);
|
|||||||
*/
|
*/
|
||||||
void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size);
|
void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size);
|
||||||
|
|
||||||
|
/** Check if recieve pipe is not empty
|
||||||
|
*
|
||||||
|
* @return true if not empty
|
||||||
|
*/
|
||||||
|
bool furi_hal_subghz_rx_pipe_not_empty();
|
||||||
|
|
||||||
|
/** Check if recieved data crc is valid
|
||||||
|
*
|
||||||
|
* @return true if valid
|
||||||
|
*/
|
||||||
|
bool furi_hal_subghz_is_rx_data_crc_valid();
|
||||||
|
|
||||||
/** Read packet from FIFO
|
/** Read packet from FIFO
|
||||||
*
|
*
|
||||||
* @param data pointer
|
* @param data pointer
|
||||||
@ -148,6 +161,14 @@ bool furi_hal_subghz_is_frequency_valid(uint32_t value);
|
|||||||
*/
|
*/
|
||||||
uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value);
|
uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value);
|
||||||
|
|
||||||
|
/** Сheck if transmission is allowed on this frequency for your flipper region
|
||||||
|
*
|
||||||
|
* @param value frequency in Hz
|
||||||
|
*
|
||||||
|
* @return true if allowed
|
||||||
|
*/
|
||||||
|
bool furi_hal_subghz_is_tx_allowed(uint32_t value);
|
||||||
|
|
||||||
/** Set frequency
|
/** Set frequency
|
||||||
*
|
*
|
||||||
* @param value frequency in Hz
|
* @param value frequency in Hz
|
||||||
|
@ -22,14 +22,14 @@ CC1101Status cc1101_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t
|
|||||||
while(hal_gpio_read(handle->miso));
|
while(hal_gpio_read(handle->miso));
|
||||||
furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT);
|
furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT);
|
||||||
|
|
||||||
assert((rx[0].CHIP_RDYn|rx[1].CHIP_RDYn) == 0);
|
assert((rx[0].CHIP_RDYn | rx[1].CHIP_RDYn) == 0);
|
||||||
return rx[1];
|
return rx[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
CC1101Status cc1101_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* data) {
|
CC1101Status cc1101_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* data) {
|
||||||
assert(sizeof(CC1101Status) == 1);
|
assert(sizeof(CC1101Status) == 1);
|
||||||
uint8_t tx[2] = { reg|CC1101_READ, 0};
|
uint8_t tx[2] = {reg | CC1101_READ, 0};
|
||||||
CC1101Status rx[2] = { 0 };
|
CC1101Status rx[2] = {0};
|
||||||
|
|
||||||
while(hal_gpio_read(handle->miso));
|
while(hal_gpio_read(handle->miso));
|
||||||
furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT);
|
furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT);
|
||||||
@ -58,8 +58,6 @@ uint8_t cc1101_get_rssi(FuriHalSpiBusHandle* handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cc1101_reset(FuriHalSpiBusHandle* handle) {
|
void cc1101_reset(FuriHalSpiBusHandle* handle) {
|
||||||
delay_us(1000);
|
|
||||||
delay_us(1000);
|
|
||||||
cc1101_strobe(handle, CC1101_STROBE_SRES);
|
cc1101_strobe(handle, CC1101_STROBE_SRES);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +128,7 @@ void cc1101_set_pa_table(FuriHalSpiBusHandle* handle, const uint8_t value[8]) {
|
|||||||
while(hal_gpio_read(handle->miso));
|
while(hal_gpio_read(handle->miso));
|
||||||
furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, sizeof(rx), CC1101_TIMEOUT);
|
furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, sizeof(rx), CC1101_TIMEOUT);
|
||||||
|
|
||||||
assert((rx[0].CHIP_RDYn|rx[8].CHIP_RDYn) == 0);
|
assert((rx[0].CHIP_RDYn | rx[8].CHIP_RDYn) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t cc1101_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* data, uint8_t size) {
|
uint8_t cc1101_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* data, uint8_t size) {
|
||||||
@ -159,9 +157,14 @@ uint8_t cc1101_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* data, uint8_t* si
|
|||||||
|
|
||||||
// First byte - packet length
|
// First byte - packet length
|
||||||
furi_hal_spi_bus_trx(handle, buff_tx, buff_rx, 2, CC1101_TIMEOUT);
|
furi_hal_spi_bus_trx(handle, buff_tx, buff_rx, 2, CC1101_TIMEOUT);
|
||||||
*size = buff_rx[1];
|
|
||||||
|
// Check that the packet is placed in the receive buffer
|
||||||
|
if(buff_rx[1] > 64) {
|
||||||
|
*size = 64;
|
||||||
|
} else {
|
||||||
|
*size = buff_rx[1];
|
||||||
|
}
|
||||||
furi_hal_spi_bus_trx(handle, &buff_tx[1], data, *size, CC1101_TIMEOUT);
|
furi_hal_spi_bus_trx(handle, &buff_tx[1], data, *size, CC1101_TIMEOUT);
|
||||||
cc1101_flush_rx(handle);
|
|
||||||
|
|
||||||
return *size;
|
return *size;
|
||||||
}
|
}
|
||||||
|
@ -89,22 +89,21 @@ extern "C" {
|
|||||||
#define CC1101_STATUS_PARTNUM 0x30 /** Chip ID Part Number */
|
#define CC1101_STATUS_PARTNUM 0x30 /** Chip ID Part Number */
|
||||||
#define CC1101_STATUS_VERSION 0x31 /** Chip ID Version */
|
#define CC1101_STATUS_VERSION 0x31 /** Chip ID Version */
|
||||||
#define CC1101_STATUS_FREQEST 0x32 /** Frequency Offset Estimate from Demodulator */
|
#define CC1101_STATUS_FREQEST 0x32 /** Frequency Offset Estimate from Demodulator */
|
||||||
#define CC1101_STATUS_LQI 0x33 /** Demodulator Estimate for Link Quality */
|
#define CC1101_STATUS_LQI 0x33 /** Demodulator Estimate for Link Quality, 7bit-CRC, 6..0-LQI*/
|
||||||
#define CC1101_STATUS_RSSI 0x34 /** Received Signal Strength Indication */
|
#define CC1101_STATUS_RSSI 0x34 /** Received Signal Strength Indication */
|
||||||
#define CC1101_STATUS_MARCSTATE 0x35 /** Main Radio Control State Machine State */
|
#define CC1101_STATUS_MARCSTATE 0x35 /** Main Radio Control State Machine State */
|
||||||
#define CC1101_STATUS_WORTIME1 0x36 /** High Byte of WOR Time */
|
#define CC1101_STATUS_WORTIME1 0x36 /** High Byte of WOR Time */
|
||||||
#define CC1101_STATUS_WORTIME0 0x37 /** Low Byte of WOR Time */
|
#define CC1101_STATUS_WORTIME0 0x37 /** Low Byte of WOR Time */
|
||||||
#define CC1101_STATUS_PKTSTATUS 0x38 /** Current GDOx Status and Packet Status */
|
#define CC1101_STATUS_PKTSTATUS 0x38 /** Current GDOx Status and Packet Status */
|
||||||
#define CC1101_STATUS_VCO_VC_DAC 0x39 /** Current Setting from PLL Calibration Module */
|
#define CC1101_STATUS_VCO_VC_DAC 0x39 /** Current Setting from PLL Calibration Module */
|
||||||
#define CC1101_STATUS_TXBYTES 0x3A /** Underflow and Number of Bytes */
|
#define CC1101_STATUS_TXBYTES 0x3A /** Underflow and Number of Bytes, 7bit-Underflow, 6..0-Number of Bytes*/
|
||||||
#define CC1101_STATUS_RXBYTES 0x3B /** Overflow and Number of Bytes */
|
#define CC1101_STATUS_RXBYTES 0x3B /** Overflow and Number of Bytes, 7bit-Overflow*, 6..0-Number of Bytes*/
|
||||||
#define CC1101_STATUS_RCCTRL1_STATUS 0x3C /** Last RC Oscillator Calibration Result */
|
#define CC1101_STATUS_RCCTRL1_STATUS 0x3C /** Last RC Oscillator Calibration Result */
|
||||||
#define CC1101_STATUS_RCCTRL0_STATUS 0x3D /** Last RC Oscillator Calibration Result */
|
#define CC1101_STATUS_RCCTRL0_STATUS 0x3D /** Last RC Oscillator Calibration Result */
|
||||||
|
|
||||||
/* Some special registers, use CC1101_BURST to read/write data */
|
/* Some special registers, use CC1101_BURST to read/write data */
|
||||||
#define CC1101_PATABLE 0x3E /** PATABLE register number, an 8-byte table that defines the PA control settings */
|
#define CC1101_PATABLE 0x3E /** PATABLE register number, an 8-byte table that defines the PA control settings */
|
||||||
#define CC1101_FIFO 0x3F /** FIFO register nunmber, can be combined with CC1101_WRITE and/or CC1101_BURST */
|
#define CC1101_FIFO 0x3F /** FIFO register nunmber, can be combined with CC1101_WRITE and/or CC1101_BURST */
|
||||||
|
|
||||||
#define CC1101_IOCFG_INV (1<<6) /** IOCFG inversion */
|
#define CC1101_IOCFG_INV (1<<6) /** IOCFG inversion */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
273
lib/subghz/subghz_tx_rx_worker.c
Normal file
273
lib/subghz/subghz_tx_rx_worker.c
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
#include "subghz_tx_rx_worker.h"
|
||||||
|
|
||||||
|
#include <stream_buffer.h>
|
||||||
|
#include <furi.h>
|
||||||
|
|
||||||
|
#define TAG "SubGhzTxRxWorker"
|
||||||
|
|
||||||
|
#define GUBGHZ_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 GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF 40
|
||||||
|
|
||||||
|
struct SubGhzTxRxWorker {
|
||||||
|
FuriThread* thread;
|
||||||
|
StreamBufferHandle_t stream_tx;
|
||||||
|
StreamBufferHandle_t stream_rx;
|
||||||
|
|
||||||
|
volatile bool worker_running;
|
||||||
|
volatile bool worker_stoping;
|
||||||
|
|
||||||
|
SubGhzTxRxWorkerStatus satus;
|
||||||
|
|
||||||
|
uint32_t frequency;
|
||||||
|
|
||||||
|
SubGhzTxRxWorkerCallbackHaveRead callback_have_read;
|
||||||
|
void* context_have_read;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool subghz_tx_rx_worker_write(SubGhzTxRxWorker* instance, uint8_t* data, size_t size) {
|
||||||
|
furi_assert(instance);
|
||||||
|
bool ret = false;
|
||||||
|
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) ==
|
||||||
|
size) {
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t subghz_tx_rx_worker_available(SubGhzTxRxWorker* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
return xStreamBufferBytesAvailable(instance->stream_rx);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_tx_rx_worker_set_callback_have_read(
|
||||||
|
SubGhzTxRxWorker* instance,
|
||||||
|
SubGhzTxRxWorkerCallbackHaveRead callback,
|
||||||
|
void* context) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(callback);
|
||||||
|
furi_assert(context);
|
||||||
|
instance->callback_have_read = callback;
|
||||||
|
instance->context_have_read = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_tx_rx_worker_rx(SubGhzTxRxWorker* instance, uint8_t* data, uint8_t* size) {
|
||||||
|
uint8_t timeout = 20;
|
||||||
|
bool ret = false;
|
||||||
|
if(instance->satus != SubGhzTxRxWorkerStatusRx) {
|
||||||
|
furi_hal_subghz_rx();
|
||||||
|
instance->satus = SubGhzTxRxWorkerStatusRx;
|
||||||
|
osDelay(1);
|
||||||
|
}
|
||||||
|
//waiting for reception to complete
|
||||||
|
while(hal_gpio_read(&gpio_cc1101_g0)) {
|
||||||
|
osDelay(1);
|
||||||
|
if(!--timeout) {
|
||||||
|
FURI_LOG_W(TAG, "RX cc1101_g0 timeout");
|
||||||
|
furi_hal_subghz_flush_rx();
|
||||||
|
furi_hal_subghz_rx();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(furi_hal_subghz_rx_pipe_not_empty()) {
|
||||||
|
if(furi_hal_subghz_is_rx_data_crc_valid()) {
|
||||||
|
furi_hal_subghz_read_packet(data, size);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
furi_hal_subghz_flush_rx();
|
||||||
|
furi_hal_subghz_rx();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_tx_rx_worker_tx(SubGhzTxRxWorker* instance, uint8_t* data, size_t size) {
|
||||||
|
uint8_t timeout = 40;
|
||||||
|
if(instance->satus != SubGhzTxRxWorkerStatusIDLE) {
|
||||||
|
furi_hal_subghz_idle();
|
||||||
|
}
|
||||||
|
furi_hal_subghz_write_packet(data, size);
|
||||||
|
instance->satus = SubGhzTxRxWorkerStatusTx;
|
||||||
|
|
||||||
|
furi_hal_subghz_tx(); //start send
|
||||||
|
|
||||||
|
while(!hal_gpio_read(&gpio_cc1101_g0)) { // Wait for GDO0 to be set -> sync transmitted
|
||||||
|
osDelay(1);
|
||||||
|
if(!--timeout) {
|
||||||
|
FURI_LOG_W(TAG, "TX !cc1101_g0 timeout");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(hal_gpio_read(&gpio_cc1101_g0)) { // Wait for GDO0 to be cleared -> end of packet
|
||||||
|
osDelay(1);
|
||||||
|
if(!--timeout) {
|
||||||
|
FURI_LOG_W(TAG, "TX cc1101_g0 timeout");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
furi_hal_subghz_idle();
|
||||||
|
instance->satus = SubGhzTxRxWorkerStatusIDLE;
|
||||||
|
}
|
||||||
|
/** Worker thread
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @return exit code
|
||||||
|
*/
|
||||||
|
static int32_t subghz_tx_rx_worker_thread(void* context) {
|
||||||
|
SubGhzTxRxWorker* instance = context;
|
||||||
|
FURI_LOG_I(TAG, "Worker start");
|
||||||
|
|
||||||
|
furi_hal_subghz_reset();
|
||||||
|
furi_hal_subghz_idle();
|
||||||
|
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};
|
||||||
|
size_t size_tx = 0;
|
||||||
|
uint8_t size_rx[1] = {0};
|
||||||
|
uint8_t timeout_tx = 0;
|
||||||
|
bool callback_rx = false;
|
||||||
|
|
||||||
|
while(instance->worker_running) {
|
||||||
|
//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) {
|
||||||
|
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);
|
||||||
|
} 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);
|
||||||
|
subghz_tx_rx_worker_tx(instance, data, size_tx);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//recive
|
||||||
|
if(subghz_tx_rx_worker_rx(instance, data, size_rx)) {
|
||||||
|
if(xStreamBufferSpacesAvailable(instance->stream_rx) >= size_rx[0]) {
|
||||||
|
if(instance->callback_have_read &&
|
||||||
|
xStreamBufferBytesAvailable(instance->stream_rx) == 0) {
|
||||||
|
callback_rx = true;
|
||||||
|
}
|
||||||
|
//todo checking that he managed to write all the data to the RX buffer
|
||||||
|
xStreamBufferSend(
|
||||||
|
instance->stream_rx,
|
||||||
|
&data,
|
||||||
|
size_rx[0],
|
||||||
|
GUBGHZ_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF);
|
||||||
|
if(callback_rx) {
|
||||||
|
instance->callback_have_read(instance->context_have_read);
|
||||||
|
callback_rx = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//todo RX buffer overflow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(timeout_tx) timeout_tx--;
|
||||||
|
osDelay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate);
|
||||||
|
furi_hal_subghz_sleep();
|
||||||
|
|
||||||
|
FURI_LOG_I(TAG, "Worker stop");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzTxRxWorker* subghz_tx_rx_worker_alloc() {
|
||||||
|
SubGhzTxRxWorker* instance = furi_alloc(sizeof(SubGhzTxRxWorker));
|
||||||
|
|
||||||
|
instance->thread = furi_thread_alloc();
|
||||||
|
furi_thread_set_name(instance->thread, "SubghzTxRxWorker");
|
||||||
|
furi_thread_set_stack_size(instance->thread, 2048);
|
||||||
|
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));
|
||||||
|
instance->stream_rx =
|
||||||
|
xStreamBufferCreate(sizeof(uint8_t) * GUBGHZ_TXRX_WORKER_BUF_SIZE, sizeof(uint8_t));
|
||||||
|
|
||||||
|
instance->satus = SubGhzTxRxWorkerStatusIDLE;
|
||||||
|
instance->worker_stoping = true;
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_tx_rx_worker_free(SubGhzTxRxWorker* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
|
||||||
|
vStreamBufferDelete(instance->stream_tx);
|
||||||
|
vStreamBufferDelete(instance->stream_rx);
|
||||||
|
furi_thread_free(instance->thread);
|
||||||
|
|
||||||
|
free(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_tx_rx_worker_start(SubGhzTxRxWorker* instance, uint32_t frequency) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(!instance->worker_running);
|
||||||
|
bool res = false;
|
||||||
|
xStreamBufferReset(instance->stream_tx);
|
||||||
|
xStreamBufferReset(instance->stream_rx);
|
||||||
|
|
||||||
|
instance->worker_running = true;
|
||||||
|
|
||||||
|
furi_thread_start(instance->thread);
|
||||||
|
|
||||||
|
if(furi_hal_subghz_is_tx_allowed(frequency)) {
|
||||||
|
instance->frequency = frequency;
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_tx_rx_worker_stop(SubGhzTxRxWorker* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(instance->worker_running);
|
||||||
|
|
||||||
|
instance->worker_running = false;
|
||||||
|
|
||||||
|
furi_thread_join(instance->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_tx_rx_worker_is_running(SubGhzTxRxWorker* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
return instance->worker_running;
|
||||||
|
}
|
81
lib/subghz/subghz_tx_rx_worker.h
Normal file
81
lib/subghz/subghz_tx_rx_worker.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <furi-hal.h>
|
||||||
|
|
||||||
|
typedef void (*SubGhzTxRxWorkerCallbackHaveRead)(void* context);
|
||||||
|
|
||||||
|
typedef struct SubGhzTxRxWorker SubGhzTxRxWorker;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SubGhzTxRxWorkerStatusIDLE,
|
||||||
|
SubGhzTxRxWorkerStatusTx,
|
||||||
|
SubGhzTxRxWorkerStatusRx,
|
||||||
|
} SubGhzTxRxWorkerStatus;
|
||||||
|
|
||||||
|
/** SubGhzTxRxWorker, add data to transfer
|
||||||
|
*
|
||||||
|
* @param instance SubGhzTxRxWorker instance
|
||||||
|
* @param data *data
|
||||||
|
* @param size data size
|
||||||
|
* @return bool true if ok
|
||||||
|
*/
|
||||||
|
bool subghz_tx_rx_worker_write(SubGhzTxRxWorker* instance, uint8_t* data, size_t size);
|
||||||
|
|
||||||
|
/** SubGhzTxRxWorker, get available data
|
||||||
|
*
|
||||||
|
* @param instance SubGhzTxRxWorker instance
|
||||||
|
* @return size_t data size
|
||||||
|
*/
|
||||||
|
size_t subghz_tx_rx_worker_available(SubGhzTxRxWorker* instance);
|
||||||
|
|
||||||
|
/** SubGhzTxRxWorker, read data
|
||||||
|
*
|
||||||
|
* @param instance SubGhzTxRxWorker instance
|
||||||
|
* @param data *data
|
||||||
|
* @param size max data size, which can be read
|
||||||
|
* @return size_t data size, how much is actually read
|
||||||
|
*/
|
||||||
|
size_t subghz_tx_rx_worker_read(SubGhzTxRxWorker* instance, uint8_t* data, size_t size);
|
||||||
|
|
||||||
|
/** Сallback SubGhzTxRxWorker when there is data to read in an empty buffer
|
||||||
|
*
|
||||||
|
* @param instance SubGhzTxRxWorker instance
|
||||||
|
* @param callback SubGhzTxRxWorkerCallbackHaveRead callback
|
||||||
|
* @param context
|
||||||
|
*/
|
||||||
|
void subghz_tx_rx_worker_set_callback_have_read(
|
||||||
|
SubGhzTxRxWorker* instance,
|
||||||
|
SubGhzTxRxWorkerCallbackHaveRead callback,
|
||||||
|
void* context);
|
||||||
|
|
||||||
|
/** Allocate SubGhzTxRxWorker
|
||||||
|
*
|
||||||
|
* @return SubGhzTxRxWorker*
|
||||||
|
*/
|
||||||
|
SubGhzTxRxWorker* subghz_tx_rx_worker_alloc();
|
||||||
|
|
||||||
|
/** Free SubGhzTxRxWorker
|
||||||
|
*
|
||||||
|
* @param instance SubGhzTxRxWorker instance
|
||||||
|
*/
|
||||||
|
void subghz_tx_rx_worker_free(SubGhzTxRxWorker* instance);
|
||||||
|
|
||||||
|
/** Start SubGhzTxRxWorker
|
||||||
|
*
|
||||||
|
* @param instance SubGhzTxRxWorker instance
|
||||||
|
* @return bool - true if ok
|
||||||
|
*/
|
||||||
|
bool subghz_tx_rx_worker_start(SubGhzTxRxWorker* instance, uint32_t frequency);
|
||||||
|
|
||||||
|
/** Stop SubGhzTxRxWorker
|
||||||
|
*
|
||||||
|
* @param instance SubGhzTxRxWorker instance
|
||||||
|
*/
|
||||||
|
void subghz_tx_rx_worker_stop(SubGhzTxRxWorker* instance);
|
||||||
|
|
||||||
|
/** Check if worker is running
|
||||||
|
*
|
||||||
|
* @param instance SubGhzTxRxWorker instance
|
||||||
|
* @return bool - true if running
|
||||||
|
*/
|
||||||
|
bool subghz_tx_rx_worker_is_running(SubGhzTxRxWorker* instance);
|
Loading…
Reference in New Issue
Block a user