Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/flipperzero-firmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--applications/cli/cli.h1
-rw-r--r--applications/subghz/helpers/subghz_chat.c141
-rw-r--r--applications/subghz/helpers/subghz_chat.h29
-rw-r--r--applications/subghz/subghz_cli.c157
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-subghz.c77
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-subghz.c67
-rw-r--r--firmware/targets/furi-hal-include/furi-hal-subghz.h11
-rw-r--r--lib/subghz/subghz_tx_rx_worker.c72
8 files changed, 459 insertions, 96 deletions
diff --git a/applications/cli/cli.h b/applications/cli/cli.h
index 9a166dc5..1f1b61a2 100644
--- a/applications/cli/cli.h
+++ b/applications/cli/cli.h
@@ -18,6 +18,7 @@ typedef enum {
CliSymbolAsciiBell = 0x07,
CliSymbolAsciiBackspace = 0x08,
CliSymbolAsciiTab = 0x09,
+ CliSymbolAsciiLF = 0x0A,
CliSymbolAsciiCR = 0x0D,
CliSymbolAsciiEsc = 0x1B,
CliSymbolAsciiUS = 0x1F,
diff --git a/applications/subghz/helpers/subghz_chat.c b/applications/subghz/helpers/subghz_chat.c
new file mode 100644
index 00000000..15e08dde
--- /dev/null
+++ b/applications/subghz/helpers/subghz_chat.c
@@ -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);
+} \ No newline at end of file
diff --git a/applications/subghz/helpers/subghz_chat.h b/applications/subghz/helpers/subghz_chat.h
new file mode 100644
index 00000000..89f82ef3
--- /dev/null
+++ b/applications/subghz/helpers/subghz_chat.h
@@ -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);
diff --git a/applications/subghz/subghz_cli.c b/applications/subghz/subghz_cli.c
index 2578fb26..2f9d698e 100644
--- a/applications/subghz/subghz_cli.c
+++ b/applications/subghz/subghz_cli.c
@@ -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;
+ }
+ str++;
+ }
+ string_set(input, sysmsg);
}
- } else if(c == CliSymbolAsciiCR) {
+ } 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);
+ } 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);
+ 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", 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;
}
}
-
- 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);
-
- notification_message(notification, &sequence_single_vibro);
- }
- 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) {
diff --git a/firmware/targets/f6/furi-hal/furi-hal-subghz.c b/firmware/targets/f6/furi-hal/furi-hal-subghz.c
index 20e9c1f9..85fe401e 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-subghz.c
+++ b/firmware/targets/f6/furi-hal/furi-hal-subghz.c
@@ -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);
diff --git a/firmware/targets/f7/furi-hal/furi-hal-subghz.c b/firmware/targets/f7/furi-hal/furi-hal-subghz.c
index 20e9c1f9..3e810880 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-subghz.c
+++ b/firmware/targets/f7/furi-hal/furi-hal-subghz.c
@@ -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,7 +450,10 @@ 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 {
+ } 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) &&
diff --git a/firmware/targets/furi-hal-include/furi-hal-subghz.h b/firmware/targets/furi-hal-include/furi-hal-subghz.h
index cde71705..bc69e68c 100644
--- a/firmware/targets/furi-hal-include/furi-hal-subghz.h
+++ b/firmware/targets/furi-hal-include/furi-hal-subghz.h
@@ -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
diff --git a/lib/subghz/subghz_tx_rx_worker.c b/lib/subghz/subghz_tx_rx_worker.c
index d151babe..09b77219 100644
--- a/lib/subghz/subghz_tx_rx_worker.c
+++ b/lib/subghz/subghz_tx_rx_worker.c
@@ -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);