diff options
author | Skorpionm <85568270+Skorpionm@users.noreply.github.com> | 2021-12-08 16:42:01 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-08 16:42:01 +0300 |
commit | f0aed7e58331557fe41b7617b8dff49b63645f40 (patch) | |
tree | d9f0365ea6846a3c9909f8de4c8ba66ca967b7b3 | |
parent | 7170864fe41f783ea84892f2e326ab120e2ee446 (diff) |
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>
-rw-r--r-- | applications/cli/cli.h | 1 | ||||
-rw-r--r-- | applications/subghz/helpers/subghz_chat.c | 141 | ||||
-rw-r--r-- | applications/subghz/helpers/subghz_chat.h | 29 | ||||
-rw-r--r-- | applications/subghz/subghz_cli.c | 157 | ||||
-rw-r--r-- | firmware/targets/f6/furi-hal/furi-hal-subghz.c | 77 | ||||
-rw-r--r-- | firmware/targets/f7/furi-hal/furi-hal-subghz.c | 67 | ||||
-rw-r--r-- | firmware/targets/furi-hal-include/furi-hal-subghz.h | 11 | ||||
-rw-r--r-- | lib/subghz/subghz_tx_rx_worker.c | 72 |
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); |