Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions applications/subghz/helpers/subghz_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,8 @@ struct SubGhzPresetDefinition {
};

typedef struct SubGhzPresetDefinition SubGhzPresetDefinition;

typedef enum {
SubGhzViewReceiverModeLive,
SubGhzViewReceiverModeFile,
} SubGhzViewReceiverMode;
1 change: 1 addition & 0 deletions applications/subghz/scenes/subghz_scene_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ ADD_SCENE(subghz, set_type, SetType)
ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer)
ADD_SCENE(subghz, read_raw, ReadRAW)
ADD_SCENE(subghz, more_raw, MoreRAW)
ADD_SCENE(subghz, decode_raw, DecodeRAW)
ADD_SCENE(subghz, delete_raw, DeleteRAW)
ADD_SCENE(subghz, need_saving, NeedSaving)
ADD_SCENE(subghz, rpc, Rpc)
272 changes: 272 additions & 0 deletions applications/subghz/scenes/subghz_scene_decode_raw.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
#include "../subghz_i.h"
#include "../views/receiver.h"

#include <lib/subghz/subghz_file_encoder_worker.h>

#define TAG "SubGhzDecodeRaw"
#define SAMPLES_TO_READ_PER_TICK 400

// TODO:
// [X] Remember RAW file after decoding
// [X] Decode in tick events instead of on_enter
// [X] Make "Config" label optional in subghz_view_receiver_draw (../views/receiver.c)
// [X] Make "Scanning..." label optional in subghz_view_receiver_draw (../views/receiver.c)
// [X] Add Decoding logo
// [ ] Design nicer Decoding logo
// [X] Check progress in stream_buffer, instead of raw stream
// [X] Blink led while decoding
// [X] Stop rx blink (blue, fast) on history item view
// [X] Don't reparse file on back
// [X] Fix: RX animation+LED returning from decoded detail view
// [X] Find good value for SAMPLES_TO_READ_PER_TICK
// [X] Fix: read errors (slow flash) after aborting decode read

typedef enum {
SubGhzDecodeRawStateStart,
SubGhzDecodeRawStateLoading,
SubGhzDecodeRawStateLoaded,
} SubGhzDecodeRawState;

SubGhzDecodeRawState decode_raw_state = SubGhzDecodeRawStateStart;
SubGhzFileEncoderWorker* file_worker_encoder;

static void subghz_scene_receiver_update_statusbar(void* context) {
SubGhz* subghz = context;
string_t history_stat_str;
string_init(history_stat_str);
if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) {
string_t frequency_str;
string_t modulation_str;

string_init(frequency_str);
string_init(modulation_str);

subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);

subghz_view_receiver_add_data_statusbar(
subghz->subghz_receiver,
string_get_cstr(frequency_str),
string_get_cstr(modulation_str),
string_get_cstr(history_stat_str));

string_clear(frequency_str);
string_clear(modulation_str);
} else {
subghz_view_receiver_add_data_statusbar(
subghz->subghz_receiver, string_get_cstr(history_stat_str), "", "");
}
string_clear(history_stat_str);
}

void subghz_scene_decode_raw_callback(SubGhzCustomEvent event, void* context) {
furi_assert(context);
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
}

static void subghz_scene_add_to_history_callback(
SubGhzReceiver* receiver,
SubGhzProtocolDecoderBase* decoder_base,
void* context) {
furi_assert(context);
SubGhz* subghz = context;
string_t str_buff;
string_init(str_buff);

if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) {
string_reset(str_buff);

subghz->state_notifications = SubGhzNotificationStateRxDone;

subghz_history_get_text_item_menu(
subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1);
subghz_view_receiver_add_item_to_menu(
subghz->subghz_receiver,
string_get_cstr(str_buff),
subghz_history_get_type_protocol(
subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1));

subghz_scene_receiver_update_statusbar(subghz);
}
subghz_receiver_reset(receiver);
string_clear(str_buff);
}

bool subghz_scene_decode_raw_start(SubGhz* subghz) {
string_t file_name;
string_init(file_name);
bool success = false;
do {
if(!flipper_format_rewind(subghz->txrx->fff_data)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}

if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", file_name)) {
FURI_LOG_E(TAG, "Missing File_name");
break;
}

success = true;
} while(false);

if(success) {
FURI_LOG_I(TAG, "Listening at \033[0;33m%s\033[0m.", string_get_cstr(file_name));

file_worker_encoder = subghz_file_encoder_worker_alloc();
if(subghz_file_encoder_worker_start(file_worker_encoder, string_get_cstr(file_name))) {
//the worker needs a file in order to open and read part of the file
furi_delay_ms(100);
} else {
success = false;
}

if(!success) {
subghz_file_encoder_worker_free(file_worker_encoder);
}
}

string_clear(file_name);
return success;
}

bool subghz_scene_decode_raw_next(SubGhz* subghz) {
LevelDuration level_duration;

for(uint32_t read = SAMPLES_TO_READ_PER_TICK; read > 0; --read) {
level_duration = subghz_file_encoder_worker_get_level_duration(file_worker_encoder);
if(!level_duration_is_reset(level_duration)) {
bool level = level_duration_get_level(level_duration);
uint32_t duration = level_duration_get_duration(level_duration);
subghz_receiver_decode(subghz->txrx->receiver, level, duration);
} else {
decode_raw_state = SubGhzDecodeRawStateLoaded;
subghz->state_notifications = SubGhzNotificationStateIDLE;

subghz_view_receiver_add_data_progress(subghz->subghz_receiver, "100%");
return false; // No more samples available
}
}

// Update progress info
string_t progress_str;
string_init(progress_str);
subghz_file_encoder_worker_get_text_progress(file_worker_encoder, progress_str);

subghz_view_receiver_add_data_progress(subghz->subghz_receiver, string_get_cstr(progress_str));

string_clear(progress_str);

return true; // More samples available
}

void subghz_scene_decode_raw_on_enter(void* context) {
SubGhz* subghz = context;

string_t str_buff;
string_init(str_buff);

subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock);
subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile);
subghz_view_receiver_set_callback(
subghz->subghz_receiver, subghz_scene_decode_raw_callback, subghz);

subghz_receiver_set_rx_callback(
subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz);

if(decode_raw_state == SubGhzDecodeRawStateStart) {
//Decode RAW to history
subghz_history_reset(subghz->txrx->history);
if(subghz_scene_decode_raw_start(subghz)) {
decode_raw_state = SubGhzDecodeRawStateLoading;
subghz->state_notifications = SubGhzNotificationStateRx;
}
} else {
//Load history to receiver
subghz_view_receiver_exit(subghz->subghz_receiver);
for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) {
string_reset(str_buff);
subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i);
subghz_view_receiver_add_item_to_menu(
subghz->subghz_receiver,
string_get_cstr(str_buff),
subghz_history_get_type_protocol(subghz->txrx->history, i));
}
string_clear(str_buff);
subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
}

subghz_scene_receiver_update_statusbar(subghz);

view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver);
}

bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case SubGhzCustomEventViewReceiverBack:
decode_raw_state = SubGhzDecodeRawStateStart;
subghz->txrx->idx_menu_chosen = 0;
subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);

if(subghz_file_encoder_worker_is_running(file_worker_encoder)) {
subghz_file_encoder_worker_stop(file_worker_encoder);
}
subghz_file_encoder_worker_free(file_worker_encoder);

subghz->state_notifications = SubGhzNotificationStateIDLE;
scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneMoreRAW);
consumed = true;
break;
case SubGhzCustomEventViewReceiverOK:
subghz->txrx->idx_menu_chosen =
subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
subghz->state_notifications = SubGhzNotificationStateIDLE;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
consumed = true;
break;
case SubGhzCustomEventViewReceiverConfig:
FURI_LOG_I(TAG, "No config options");
consumed = true;
break;
case SubGhzCustomEventViewReceiverOffDisplay:
notification_message(subghz->notifications, &sequence_display_backlight_off);
consumed = true;
break;
case SubGhzCustomEventViewReceiverUnlock:
subghz->lock = SubGhzLockOff;
consumed = true;
break;
default:
break;
}
} else if(event.type == SceneManagerEventTypeTick) {
switch(subghz->state_notifications) {
case SubGhzNotificationStateRx:
notification_message(subghz->notifications, &sequence_blink_cyan_10);
break;
case SubGhzNotificationStateRxDone:
notification_message(subghz->notifications, &subghs_sequence_rx);
subghz->state_notifications = SubGhzNotificationStateRx;
break;
default:
break;
}

switch(decode_raw_state) {
case SubGhzDecodeRawStateLoading:
subghz_scene_decode_raw_next(subghz);
break;
default:
break;
}
}
return consumed;
}

void subghz_scene_decode_raw_on_exit(void* context) {
UNUSED(context);
}
13 changes: 13 additions & 0 deletions applications/subghz/scenes/subghz_scene_more_raw.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "../subghz_i.h"

enum SubmenuIndex {
SubmenuIndexDecode,
SubmenuIndexEdit,
SubmenuIndexDelete,
};
Expand All @@ -13,6 +14,13 @@ void subghz_scene_more_raw_submenu_callback(void* context, uint32_t index) {
void subghz_scene_more_raw_on_enter(void* context) {
SubGhz* subghz = context;

submenu_add_item(
subghz->submenu,
"Decode",
SubmenuIndexDecode,
subghz_scene_more_raw_submenu_callback,
subghz);

submenu_add_item(
subghz->submenu,
"Rename",
Expand Down Expand Up @@ -50,6 +58,11 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) {
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
return true;
} else if(event.event == SubmenuIndexDecode) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDecode);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDecodeRAW);
return true;
}
}
return false;
Expand Down
5 changes: 3 additions & 2 deletions applications/subghz/scenes/subghz_scene_receiver.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "../subghz_i.h"
#include "../views/receiver.h"

static const NotificationSequence subghs_sequence_rx = {
const NotificationSequence subghs_sequence_rx = {
&message_green_255,

&message_vibro_on,
Expand All @@ -14,7 +14,7 @@ static const NotificationSequence subghs_sequence_rx = {
NULL,
};

static const NotificationSequence subghs_sequence_rx_locked = {
const NotificationSequence subghs_sequence_rx_locked = {
&message_green_255,

&message_display_backlight_on,
Expand Down Expand Up @@ -109,6 +109,7 @@ void subghz_scene_receiver_on_enter(void* context) {
}

subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock);
subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeLive);

//Load history to receiver
subghz_view_receiver_exit(subghz->subghz_receiver);
Expand Down
3 changes: 3 additions & 0 deletions applications/subghz/subghz_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,6 @@ void subghz_file_name_clear(SubGhz* subghz);
bool subghz_path_is_file(string_t path);
uint32_t subghz_random_serial(void);
void subghz_hopper_update(SubGhz* subghz);

extern const NotificationSequence subghs_sequence_rx;
extern const NotificationSequence subghs_sequence_rx_locked;
Loading