SubGhz: add GFSK modulation, refactoring subghz_chat (#866)
* SubGhz: add GFSK modulation, refactoring subghz_chat * SubGhz: off echo subghz_chat * SubGhz: subghz_chat add sending and receiving formatted text, translation of the chat to events * SubGhz: add UTF support in subghz_chat_worker_alloc Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
@@ -18,6 +18,7 @@ typedef enum {
|
||||
CliSymbolAsciiBell = 0x07,
|
||||
CliSymbolAsciiBackspace = 0x08,
|
||||
CliSymbolAsciiTab = 0x09,
|
||||
CliSymbolAsciiLF = 0x0A,
|
||||
CliSymbolAsciiCR = 0x0D,
|
||||
CliSymbolAsciiEsc = 0x1B,
|
||||
CliSymbolAsciiUS = 0x1F,
|
||||
|
141
applications/subghz/helpers/subghz_chat.c
Normal file
141
applications/subghz/helpers/subghz_chat.c
Normal file
@@ -0,0 +1,141 @@
|
||||
#include "subghz_chat.h"
|
||||
#include <lib/subghz/subghz_tx_rx_worker.h>
|
||||
|
||||
#define TAG "SubGhzChat"
|
||||
#define SUBGHZ_CHAT_WORKER_TIMEOUT_BETWEEN_MESSAGES 500
|
||||
|
||||
struct SubGhzChatWorker {
|
||||
FuriThread* thread;
|
||||
SubGhzTxRxWorker* subghz_txrx;
|
||||
|
||||
volatile bool worker_running;
|
||||
volatile bool worker_stoping;
|
||||
osMessageQueueId_t event_queue;
|
||||
uint32_t last_time_rx_data;
|
||||
};
|
||||
|
||||
/** Worker thread
|
||||
*
|
||||
* @param context
|
||||
* @return exit code
|
||||
*/
|
||||
static int32_t subghz_chat_worker_thread(void* context) {
|
||||
SubGhzChatWorker* instance = context;
|
||||
FURI_LOG_I(TAG, "Worker start");
|
||||
char c;
|
||||
SubghzChatEvent event;
|
||||
event.event = SubghzChatEventUserEntrance;
|
||||
osMessageQueuePut(instance->event_queue, &event, 0, 0);
|
||||
while(instance->worker_running) {
|
||||
if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, osWaitForever) == 1) {
|
||||
event.event = SubghzChatEventInputData;
|
||||
event.c = c;
|
||||
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
|
||||
}
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Worker stop");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void subghz_chat_worker_update_rx_event_chat(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzChatWorker* instance = context;
|
||||
SubghzChatEvent event;
|
||||
if((millis() - instance->last_time_rx_data) > SUBGHZ_CHAT_WORKER_TIMEOUT_BETWEEN_MESSAGES) {
|
||||
event.event = SubghzChatEventNewMessage;
|
||||
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
|
||||
}
|
||||
instance->last_time_rx_data = millis();
|
||||
event.event = SubghzChatEventRXData;
|
||||
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
|
||||
}
|
||||
|
||||
SubGhzChatWorker* subghz_chat_worker_alloc() {
|
||||
SubGhzChatWorker* instance = furi_alloc(sizeof(SubGhzChatWorker));
|
||||
|
||||
instance->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(instance->thread, "SubghzChat");
|
||||
furi_thread_set_stack_size(instance->thread, 2048);
|
||||
furi_thread_set_context(instance->thread, instance);
|
||||
furi_thread_set_callback(instance->thread, subghz_chat_worker_thread);
|
||||
instance->subghz_txrx = subghz_tx_rx_worker_alloc();
|
||||
instance->event_queue = osMessageQueueNew(80, sizeof(SubghzChatEvent), NULL);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void subghz_chat_worker_free(SubGhzChatWorker* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(!instance->worker_running);
|
||||
osMessageQueueDelete(instance->event_queue);
|
||||
subghz_tx_rx_worker_free(instance->subghz_txrx);
|
||||
furi_thread_free(instance->thread);
|
||||
|
||||
free(instance);
|
||||
}
|
||||
|
||||
bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency) {
|
||||
furi_assert(instance);
|
||||
furi_assert(!instance->worker_running);
|
||||
bool res = false;
|
||||
|
||||
if(subghz_tx_rx_worker_start(instance->subghz_txrx, frequency)) {
|
||||
osMessageQueueReset(instance->event_queue);
|
||||
subghz_tx_rx_worker_set_callback_have_read(
|
||||
instance->subghz_txrx, subghz_chat_worker_update_rx_event_chat, instance);
|
||||
|
||||
instance->worker_running = true;
|
||||
instance->last_time_rx_data = 0;
|
||||
|
||||
res = furi_thread_start(instance->thread);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void subghz_chat_worker_stop(SubGhzChatWorker* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->worker_running);
|
||||
if(subghz_tx_rx_worker_is_running(instance->subghz_txrx)) {
|
||||
subghz_tx_rx_worker_stop(instance->subghz_txrx);
|
||||
}
|
||||
|
||||
instance->worker_running = false;
|
||||
|
||||
furi_thread_join(instance->thread);
|
||||
}
|
||||
|
||||
bool subghz_chat_worker_is_running(SubGhzChatWorker* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->worker_running;
|
||||
}
|
||||
|
||||
SubghzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance) {
|
||||
furi_assert(instance);
|
||||
SubghzChatEvent event;
|
||||
if(osMessageQueueGet(instance->event_queue, &event, NULL, osWaitForever) == osOK) {
|
||||
return event;
|
||||
} else {
|
||||
event.event = SubghzChatEventNoEvent;
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubghzChatEvent* event) {
|
||||
furi_assert(instance);
|
||||
osMessageQueuePut(instance->event_queue, event, 0, osWaitForever);
|
||||
}
|
||||
|
||||
size_t subghz_chat_worker_available(SubGhzChatWorker* instance) {
|
||||
furi_assert(instance);
|
||||
return subghz_tx_rx_worker_available(instance->subghz_txrx);
|
||||
}
|
||||
|
||||
size_t subghz_chat_worker_read(SubGhzChatWorker* instance, uint8_t* data, size_t size) {
|
||||
furi_assert(instance);
|
||||
return subghz_tx_rx_worker_read(instance->subghz_txrx, data, size);
|
||||
}
|
||||
|
||||
bool subghz_chat_worker_write(SubGhzChatWorker* instance, uint8_t* data, size_t size) {
|
||||
furi_assert(instance);
|
||||
return subghz_tx_rx_worker_write(instance->subghz_txrx, data, size);
|
||||
}
|
29
applications/subghz/helpers/subghz_chat.h
Normal file
29
applications/subghz/helpers/subghz_chat.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include "../subghz_i.h"
|
||||
|
||||
typedef struct SubGhzChatWorker SubGhzChatWorker;
|
||||
|
||||
typedef enum {
|
||||
SubghzChatEventNoEvent,
|
||||
SubghzChatEventUserEntrance,
|
||||
SubghzChatEventUserExit,
|
||||
SubghzChatEventInputData,
|
||||
SubghzChatEventRXData,
|
||||
SubghzChatEventNewMessage,
|
||||
} SubghzChatEventType;
|
||||
|
||||
typedef struct {
|
||||
SubghzChatEventType event;
|
||||
char c;
|
||||
} SubghzChatEvent;
|
||||
|
||||
SubGhzChatWorker* subghz_chat_worker_alloc();
|
||||
void subghz_chat_worker_free(SubGhzChatWorker* instance);
|
||||
bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency);
|
||||
void subghz_chat_worker_stop(SubGhzChatWorker* instance);
|
||||
bool subghz_chat_worker_is_running(SubGhzChatWorker* instance);
|
||||
SubghzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance);
|
||||
void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubghzChatEvent* event);
|
||||
size_t subghz_chat_worker_available(SubGhzChatWorker* instance);
|
||||
size_t subghz_chat_worker_read(SubGhzChatWorker* instance, uint8_t* data, size_t size);
|
||||
bool subghz_chat_worker_write(SubGhzChatWorker* instance, uint8_t* data, size_t size);
|
@@ -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) {
|
||||
|
Reference in New Issue
Block a user