|
@@ -9,6 +9,8 @@
|
|
|
#include <gui/scene_manager.h>
|
|
#include <gui/scene_manager.h>
|
|
|
#include <toolbox/sha256.h>
|
|
#include <toolbox/sha256.h>
|
|
|
#include <notification/notification_messages.h>
|
|
#include <notification/notification_messages.h>
|
|
|
|
|
+#include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
|
|
|
|
|
+#include <lib/subghz/subghz_tx_rx_worker.h>
|
|
|
|
|
|
|
|
#include "esubghz_chat_icons.h"
|
|
#include "esubghz_chat_icons.h"
|
|
|
|
|
|
|
@@ -28,7 +30,7 @@
|
|
|
#define TEXT_INPUT_STORE_SIZE 512
|
|
#define TEXT_INPUT_STORE_SIZE 512
|
|
|
|
|
|
|
|
#define TICK_INTERVAL 50
|
|
#define TICK_INTERVAL 50
|
|
|
-#define MESSAGE_COMPLETION_TIMEOUT 200
|
|
|
|
|
|
|
+#define MESSAGE_COMPLETION_TIMEOUT 500
|
|
|
#define TIMEOUT_BETWEEN_MESSAGES 500
|
|
#define TIMEOUT_BETWEEN_MESSAGES 500
|
|
|
|
|
|
|
|
#define KBD_UNLOCK_CNT 3
|
|
#define KBD_UNLOCK_CNT 3
|
|
@@ -45,8 +47,12 @@ typedef struct {
|
|
|
TextInput *text_input;
|
|
TextInput *text_input;
|
|
|
char text_input_store[TEXT_INPUT_STORE_SIZE + 1];
|
|
char text_input_store[TEXT_INPUT_STORE_SIZE + 1];
|
|
|
|
|
|
|
|
- // selected frequency
|
|
|
|
|
|
|
+ // for Sub-GHz
|
|
|
uint32_t frequency;
|
|
uint32_t frequency;
|
|
|
|
|
+ SubGhzTxRxWorker *subghz_worker;
|
|
|
|
|
+#ifdef FW_ORIGIN_Official
|
|
|
|
|
+ const SubGhzDevice *subghz_device;
|
|
|
|
|
+#endif /* FW_ORIGIN_Official */
|
|
|
|
|
|
|
|
// message assembly before TX
|
|
// message assembly before TX
|
|
|
FuriString *name_prefix;
|
|
FuriString *name_prefix;
|
|
@@ -60,8 +66,7 @@ typedef struct {
|
|
|
uint8_t rx_buffer[RX_TX_BUFFER_SIZE];
|
|
uint8_t rx_buffer[RX_TX_BUFFER_SIZE];
|
|
|
uint8_t tx_buffer[RX_TX_BUFFER_SIZE];
|
|
uint8_t tx_buffer[RX_TX_BUFFER_SIZE];
|
|
|
char rx_str_buffer[RX_TX_BUFFER_SIZE + 1];
|
|
char rx_str_buffer[RX_TX_BUFFER_SIZE + 1];
|
|
|
- FuriStreamBuffer *rx_collection_buffer;
|
|
|
|
|
- uint32_t last_time_rx_data;
|
|
|
|
|
|
|
+ volatile uint32_t last_time_rx_data;
|
|
|
|
|
|
|
|
// for locking
|
|
// for locking
|
|
|
ViewPortDrawCallback orig_draw_cb;
|
|
ViewPortDrawCallback orig_draw_cb;
|
|
@@ -98,6 +103,36 @@ static void esubghz_chat_explicit_bzero(void *s, size_t len)
|
|
|
asm volatile("" ::: "memory");
|
|
asm volatile("" ::: "memory");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/* Callback for RX events from the Sub-GHz worker. Records the current ticks as
|
|
|
|
|
+ * the time of the last reception. */
|
|
|
|
|
+static void have_read_cb(void* context)
|
|
|
|
|
+{
|
|
|
|
|
+ furi_assert(context);
|
|
|
|
|
+ ESubGhzChatState* state = context;
|
|
|
|
|
+
|
|
|
|
|
+ state->last_time_rx_data = furi_get_tick();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Decrypts a message for post_rx(). */
|
|
|
|
|
+static bool post_rx_decrypt(ESubGhzChatState *state, size_t rx_size)
|
|
|
|
|
+{
|
|
|
|
|
+ if (rx_size < IV_BYTES + TAG_BYTES + 1) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int ret = gcm_auth_decrypt(&(state->gcm_ctx),
|
|
|
|
|
+ state->rx_buffer, IV_BYTES,
|
|
|
|
|
+ NULL, 0,
|
|
|
|
|
+ state->rx_buffer + IV_BYTES,
|
|
|
|
|
+ (uint8_t *) state->rx_str_buffer,
|
|
|
|
|
+ rx_size - (IV_BYTES + TAG_BYTES),
|
|
|
|
|
+ state->rx_buffer + rx_size - TAG_BYTES,
|
|
|
|
|
+ TAG_BYTES);
|
|
|
|
|
+ state->rx_str_buffer[rx_size - (IV_BYTES + TAG_BYTES)] = 0;
|
|
|
|
|
+
|
|
|
|
|
+ return (ret == 0);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/* Post RX handler, decrypts received messages, displays them in the text box
|
|
/* Post RX handler, decrypts received messages, displays them in the text box
|
|
|
* and sends a notification. */
|
|
* and sends a notification. */
|
|
|
static void post_rx(ESubGhzChatState *state, size_t rx_size)
|
|
static void post_rx(ESubGhzChatState *state, size_t rx_size)
|
|
@@ -115,29 +150,15 @@ static void post_rx(ESubGhzChatState *state, size_t rx_size)
|
|
|
memcpy(state->rx_str_buffer, state->rx_buffer, rx_size);
|
|
memcpy(state->rx_str_buffer, state->rx_buffer, rx_size);
|
|
|
state->rx_str_buffer[rx_size] = 0;
|
|
state->rx_str_buffer[rx_size] = 0;
|
|
|
} else {
|
|
} else {
|
|
|
- if (rx_size < IV_BYTES + TAG_BYTES + 1) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int ret = gcm_auth_decrypt(&(state->gcm_ctx),
|
|
|
|
|
- state->rx_buffer, IV_BYTES,
|
|
|
|
|
- NULL, 0,
|
|
|
|
|
- state->rx_buffer + IV_BYTES,
|
|
|
|
|
- (uint8_t *) state->rx_str_buffer,
|
|
|
|
|
- rx_size - (IV_BYTES + TAG_BYTES),
|
|
|
|
|
- state->rx_buffer + rx_size - TAG_BYTES,
|
|
|
|
|
- TAG_BYTES);
|
|
|
|
|
- state->rx_str_buffer[rx_size - (IV_BYTES + TAG_BYTES)] = 0;
|
|
|
|
|
-
|
|
|
|
|
/* if decryption fails output an error message */
|
|
/* if decryption fails output an error message */
|
|
|
- if (ret != 0) {
|
|
|
|
|
|
|
+ if (!post_rx_decrypt(state, rx_size)) {
|
|
|
strcpy(state->rx_str_buffer, "ERR: Decryption failed!");
|
|
strcpy(state->rx_str_buffer, "ERR: Decryption failed!");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* append message to text box */
|
|
/* append message to text box */
|
|
|
- furi_string_cat_printf(state->chat_box_store, "\n%s",
|
|
|
|
|
- state->rx_str_buffer);
|
|
|
|
|
|
|
+ furi_string_cat_printf(state->chat_box_store, "\n%s [%u]",
|
|
|
|
|
+ state->rx_str_buffer, rx_size);
|
|
|
|
|
|
|
|
/* send notification (make the flipper vibrate) */
|
|
/* send notification (make the flipper vibrate) */
|
|
|
notification_message(state->notification, &sequence_single_vibro);
|
|
notification_message(state->notification, &sequence_single_vibro);
|
|
@@ -178,7 +199,8 @@ static bool freq_input_validator(const char *text, FuriString *error,
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (!furi_hal_subghz_is_frequency_valid(state->frequency)) {
|
|
|
|
|
|
|
+ if (!subghz_devices_is_frequency_valid(state->subghz_device,
|
|
|
|
|
+ state->frequency)) {
|
|
|
furi_string_printf(error, "Frequency\n%lu\n is invalid!",
|
|
furi_string_printf(error, "Frequency\n%lu\n is invalid!",
|
|
|
state->frequency);
|
|
state->frequency);
|
|
|
return false;
|
|
return false;
|
|
@@ -199,7 +221,7 @@ static bool freq_input_validator(const char *text, FuriString *error,
|
|
|
|
|
|
|
|
/* Sends PassEntered event to scene manager and displays whether or not
|
|
/* Sends PassEntered event to scene manager and displays whether or not
|
|
|
* encryption has been enabled in the text box. Also clears the text input
|
|
* encryption has been enabled in the text box. Also clears the text input
|
|
|
- * buffer to remove the password. */
|
|
|
|
|
|
|
+ * buffer to remove the password and starts the Sub-GHz worker. */
|
|
|
static void pass_input_cb(void *context)
|
|
static void pass_input_cb(void *context)
|
|
|
{
|
|
{
|
|
|
furi_assert(context);
|
|
furi_assert(context);
|
|
@@ -212,6 +234,9 @@ static void pass_input_cb(void *context)
|
|
|
esubghz_chat_explicit_bzero(state->text_input_store,
|
|
esubghz_chat_explicit_bzero(state->text_input_store,
|
|
|
sizeof(state->text_input_store));
|
|
sizeof(state->text_input_store));
|
|
|
|
|
|
|
|
|
|
+ subghz_tx_rx_worker_start(state->subghz_worker, state->subghz_device,
|
|
|
|
|
+ state->frequency);
|
|
|
|
|
+
|
|
|
scene_manager_handle_custom_event(state->scene_manager,
|
|
scene_manager_handle_custom_event(state->scene_manager,
|
|
|
ESubGhzChatEvent_PassEntered);
|
|
ESubGhzChatEvent_PassEntered);
|
|
|
}
|
|
}
|
|
@@ -229,6 +254,11 @@ static bool pass_input_validator(const char *text, FuriString *error,
|
|
|
ESubGhzChatState* state = context;
|
|
ESubGhzChatState* state = context;
|
|
|
|
|
|
|
|
#ifdef FW_ORIGIN_Official
|
|
#ifdef FW_ORIGIN_Official
|
|
|
|
|
+ if (strlen(text) == 0) {
|
|
|
|
|
+ furi_string_printf(error, "Enter a\npassword!");
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (strcmp(text, " ") == 0) {
|
|
if (strcmp(text, " ") == 0) {
|
|
|
#else /* FW_ORIGIN_Official */
|
|
#else /* FW_ORIGIN_Official */
|
|
|
if (strlen(text) == 0) {
|
|
if (strlen(text) == 0) {
|
|
@@ -239,8 +269,6 @@ static bool pass_input_validator(const char *text, FuriString *error,
|
|
|
|
|
|
|
|
unsigned char key[KEY_BITS / 8];
|
|
unsigned char key[KEY_BITS / 8];
|
|
|
|
|
|
|
|
- state->encrypted = true;
|
|
|
|
|
-
|
|
|
|
|
/* derive a key from the password */
|
|
/* derive a key from the password */
|
|
|
sha256((unsigned char *) text, strlen(text), key);
|
|
sha256((unsigned char *) text, strlen(text), key);
|
|
|
|
|
|
|
@@ -264,6 +292,8 @@ static bool pass_input_validator(const char *text, FuriString *error,
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ state->encrypted = true;
|
|
|
|
|
+
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -332,12 +362,9 @@ static void chat_input_cb(void *context)
|
|
|
state->tx_buffer[i]);
|
|
state->tx_buffer[i]);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // TODO: remove this
|
|
|
|
|
- state->last_time_rx_data = furi_get_tick();
|
|
|
|
|
- furi_stream_buffer_send(state->rx_collection_buffer,
|
|
|
|
|
- state->tx_buffer, tx_size, 0);
|
|
|
|
|
-
|
|
|
|
|
- // TODO: actually transmit
|
|
|
|
|
|
|
+ /* transmit */
|
|
|
|
|
+ subghz_tx_rx_worker_write(state->subghz_worker, state->tx_buffer,
|
|
|
|
|
+ tx_size);
|
|
|
|
|
|
|
|
/* switch to text box view */
|
|
/* switch to text box view */
|
|
|
scene_manager_handle_custom_event(state->scene_manager,
|
|
scene_manager_handle_custom_event(state->scene_manager,
|
|
@@ -718,7 +745,7 @@ static bool esubghz_chat_navigation_event_callback(void* context)
|
|
|
|
|
|
|
|
/* Tick event callback for view dispatcher. Called every TICK_INTERVAL. Resets
|
|
/* Tick event callback for view dispatcher. Called every TICK_INTERVAL. Resets
|
|
|
* the locked message if necessary. Retrieves a received message from the
|
|
* the locked message if necessary. Retrieves a received message from the
|
|
|
- * rx_collection_buffer and calls post_rx(). Then calls the scene manager. */
|
|
|
|
|
|
|
+ * Sub-GHz worker and calls post_rx(). Then calls the scene manager. */
|
|
|
static void esubghz_chat_tick_event_callback(void* context)
|
|
static void esubghz_chat_tick_event_callback(void* context)
|
|
|
{
|
|
{
|
|
|
FURI_LOG_T(APPLICATION_NAME, "esubghz_chat_tick_event_callback");
|
|
FURI_LOG_T(APPLICATION_NAME, "esubghz_chat_tick_event_callback");
|
|
@@ -734,20 +761,19 @@ static void esubghz_chat_tick_event_callback(void* context)
|
|
|
/* if the maximum message size was reached or the
|
|
/* if the maximum message size was reached or the
|
|
|
* MESSAGE_COMPLETION_TIMEOUT has expired, retrieve a message and call
|
|
* MESSAGE_COMPLETION_TIMEOUT has expired, retrieve a message and call
|
|
|
* post_rx() */
|
|
* post_rx() */
|
|
|
- size_t avail = furi_stream_buffer_bytes_available(
|
|
|
|
|
- state->rx_collection_buffer);
|
|
|
|
|
- if (avail > 0) {
|
|
|
|
|
- uint32_t since_last_rx = furi_get_tick() -
|
|
|
|
|
|
|
+ size_t avail = 0;
|
|
|
|
|
+ while ((avail = subghz_tx_rx_worker_available(state->subghz_worker)) >
|
|
|
|
|
+ 0) {
|
|
|
|
|
+ volatile uint32_t since_last_rx = furi_get_tick() -
|
|
|
state->last_time_rx_data;
|
|
state->last_time_rx_data;
|
|
|
- if (avail == RX_TX_BUFFER_SIZE || since_last_rx >
|
|
|
|
|
|
|
+ if (avail < RX_TX_BUFFER_SIZE && since_last_rx <
|
|
|
MESSAGE_COMPLETION_TIMEOUT) {
|
|
MESSAGE_COMPLETION_TIMEOUT) {
|
|
|
- size_t rx_size = furi_stream_buffer_receive(
|
|
|
|
|
- state->rx_collection_buffer,
|
|
|
|
|
- state->rx_buffer,
|
|
|
|
|
- avail, 0);
|
|
|
|
|
- post_rx(state, rx_size);
|
|
|
|
|
- furi_stream_buffer_reset(state->rx_collection_buffer);
|
|
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ size_t rx_size = subghz_tx_rx_worker_read(state->subghz_worker,
|
|
|
|
|
+ state->rx_buffer, RX_TX_BUFFER_SIZE);
|
|
|
|
|
+ post_rx(state, rx_size);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* call scene manager */
|
|
/* call scene manager */
|
|
@@ -947,13 +973,22 @@ int32_t esubghz_chat(void)
|
|
|
goto err_alloc_cb;
|
|
goto err_alloc_cb;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- state->rx_collection_buffer = furi_stream_buffer_alloc(
|
|
|
|
|
- RX_TX_BUFFER_SIZE,
|
|
|
|
|
- RX_TX_BUFFER_SIZE);
|
|
|
|
|
- if (state->rx_collection_buffer == NULL) {
|
|
|
|
|
- goto err_alloc_rcb;
|
|
|
|
|
|
|
+ state->subghz_worker = subghz_tx_rx_worker_alloc();
|
|
|
|
|
+ if (state->subghz_worker == NULL) {
|
|
|
|
|
+ goto err_alloc_worker;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /* set the have_read callback of the Sub-GHz worker */
|
|
|
|
|
+ subghz_tx_rx_worker_set_callback_have_read(state->subghz_worker,
|
|
|
|
|
+ have_read_cb, state);
|
|
|
|
|
+
|
|
|
|
|
+ /* enter suppress charge mode */
|
|
|
|
|
+ furi_hal_power_suppress_charge_enter();
|
|
|
|
|
+
|
|
|
|
|
+ /* init internal device */
|
|
|
|
|
+ subghz_devices_init();
|
|
|
|
|
+ state->subghz_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME);
|
|
|
|
|
+
|
|
|
/* set chat name prefix */
|
|
/* set chat name prefix */
|
|
|
// TODO: handle escape chars here somehow
|
|
// TODO: handle escape chars here somehow
|
|
|
furi_string_printf(state->name_prefix, "\033[0;33m%s\033[0m: ",
|
|
furi_string_printf(state->name_prefix, "\033[0;33m%s\033[0m: ",
|
|
@@ -1005,6 +1040,11 @@ int32_t esubghz_chat(void)
|
|
|
* application */
|
|
* application */
|
|
|
view_dispatcher_run(state->view_dispatcher);
|
|
view_dispatcher_run(state->view_dispatcher);
|
|
|
|
|
|
|
|
|
|
+ /* if it is running, stop the Sub-GHz worker */
|
|
|
|
|
+ if (subghz_tx_rx_worker_is_running(state->subghz_worker)) {
|
|
|
|
|
+ subghz_tx_rx_worker_stop(state->subghz_worker);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
err = 0;
|
|
err = 0;
|
|
|
|
|
|
|
|
/* close GUI record */
|
|
/* close GUI record */
|
|
@@ -1024,11 +1064,17 @@ int32_t esubghz_chat(void)
|
|
|
sizeof(state->text_input_store));
|
|
sizeof(state->text_input_store));
|
|
|
esubghz_chat_explicit_bzero(&(state->gcm_ctx), sizeof(state->gcm_ctx));
|
|
esubghz_chat_explicit_bzero(&(state->gcm_ctx), sizeof(state->gcm_ctx));
|
|
|
|
|
|
|
|
- /* free everything we allocated*/
|
|
|
|
|
|
|
+ /* deinit devices */
|
|
|
|
|
+ subghz_devices_deinit();
|
|
|
|
|
+
|
|
|
|
|
+ /* exit suppress charge mode */
|
|
|
|
|
+ furi_hal_power_suppress_charge_exit();
|
|
|
|
|
+
|
|
|
|
|
+ /* free everything we allocated */
|
|
|
|
|
|
|
|
- furi_stream_buffer_free(state->rx_collection_buffer);
|
|
|
|
|
|
|
+ subghz_tx_rx_worker_free(state->subghz_worker);
|
|
|
|
|
|
|
|
-err_alloc_rcb:
|
|
|
|
|
|
|
+err_alloc_worker:
|
|
|
chat_box_free(state);
|
|
chat_box_free(state);
|
|
|
|
|
|
|
|
err_alloc_cb:
|
|
err_alloc_cb:
|