Преглед изворни кода

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>
Skorpionm пре 4 година
родитељ
комит
f0aed7e583

+ 1 - 0
applications/cli/cli.h

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

+ 141 - 0
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);
+}

+ 29 - 0
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);

+ 109 - 48
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) {

+ 73 - 4
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);

+ 66 - 1
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) &&

+ 11 - 0
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

+ 29 - 43
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);