[FL-1758] SubGhz refactoring part 1 (#689)

* SubGhz: refactoring
* WeGet: Add support for outputting formatted lines, events center button pressed, center button released
* Variable Item: slightly changed the display of data on the screen
* SubGhz: add show errors, add show preset, refactoring
* SubGhz: refactoring transmitter
* SubGhz: removed unused modules
* SubGhz: Add FuriHalSubGhzPresetOok270Async setting menu
* SubGhz: fix annotation
* SubGhz: add support Nero Radio

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Skorpionm 2021-09-10 04:29:57 +04:00 committed by GitHub
parent fbccb9fbaf
commit f385340b2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1493 additions and 801 deletions

View File

@ -68,10 +68,10 @@ static void variable_item_list_draw_callback(Canvas* canvas, void* _model) {
canvas_draw_str(canvas, 73, item_text_y, "<");
}
canvas_draw_str(canvas, 84, item_text_y, string_get_cstr(item->current_value_text));
canvas_draw_str(canvas, 80, item_text_y, string_get_cstr(item->current_value_text));
if(item->current_value_index < (item->values_count - 1)) {
canvas_draw_str(canvas, 113, item_text_y, ">");
canvas_draw_str(canvas, 115, item_text_y, ">");
}
}
@ -235,6 +235,21 @@ void variable_item_list_free(VariableItemList* variable_item_list) {
free(variable_item_list);
}
void variable_item_list_clean(VariableItemList* variable_item_list) {
furi_assert(variable_item_list);
with_view_model(
variable_item_list->view, (VariableItemListModel * model) {
VariableItemArray_it_t it;
for(VariableItemArray_it(it, model->items); !VariableItemArray_end_p(it);
VariableItemArray_next(it)) {
string_clean(VariableItemArray_ref(it)->current_value_text);
}
VariableItemArray_clean(model->items);
return false;
});
}
View* variable_item_list_get_view(VariableItemList* variable_item_list) {
furi_assert(variable_item_list);
return variable_item_list->view;

View File

@ -18,6 +18,9 @@ VariableItemList* variable_item_list_alloc();
* @param variable_item_list VariableItemList instance
*/
void variable_item_list_free(VariableItemList* variable_item_list);
void variable_item_list_clean(VariableItemList* variable_item_list);
View* variable_item_list_get_view(VariableItemList* variable_item_list);
/** Add item to VariableItemList

View File

@ -118,6 +118,20 @@ static void widget_add_element(Widget* widget, WidgetElement* element) {
});
}
void widget_add_string_multi_element(
Widget* widget,
uint8_t x,
uint8_t y,
Align horizontal,
Align vertical,
Font font,
const char* text) {
furi_assert(widget);
WidgetElement* string_multi_element =
widget_element_string_multi_create(x, y, horizontal, vertical, font, text);
widget_add_element(widget, string_multi_element);
}
void widget_add_string_element(
Widget* widget,
uint8_t x,

View File

@ -26,6 +26,23 @@ void widget_clear(Widget* widget);
*/
View* widget_get_view(Widget* widget);
/** Add Multi String Element
* @param widget Widget instance
* @param x - x coordinate
* @param y - y coordinate
* @param horizontal - Align instance
* @param vertical - Align instance
* @param font Font instance
*/
void widget_add_string_multi_element(
Widget* widget,
uint8_t x,
uint8_t y,
Align horizontal,
Align vertical,
Font font,
const char* text);
/** Add String Element
* @param widget Widget instance
* @param x - x coordinate

View File

@ -30,7 +30,18 @@ static bool gui_button_input(InputEvent* event, WidgetElement* element) {
GuiButtonModel* model = element->model;
bool consumed = false;
if((event->type == InputTypeShort) && model->callback) {
if(model->callback == NULL) return consumed;
if(event->key == InputKeyOk && event->type == InputTypePress &&
model->button_type == GuiButtonTypeCenter) {
model->callback(GuiButtonTypeCenterPress, model->context);
consumed = true;
} else if(
event->key == InputKeyOk && event->type == InputTypeRelease &&
model->button_type == GuiButtonTypeCenter) {
model->callback(GuiButtonTypeCenterRelease, model->context);
consumed = true;
} else if(event->type == InputTypeShort) {
if((model->button_type == GuiButtonTypeLeft) && (event->key == InputKeyLeft)) {
model->callback(model->button_type, model->context);
consumed = true;

View File

@ -6,6 +6,8 @@ typedef enum {
GuiButtonTypeLeft,
GuiButtonTypeCenter,
GuiButtonTypeRight,
GuiButtonTypeCenterPress,
GuiButtonTypeCenterRelease,
} GuiButtonType;
typedef void (*ButtonCallback)(GuiButtonType result, void* context);
@ -28,6 +30,15 @@ struct WidgetElement {
Widget* parent;
};
/* Create multi string element */
WidgetElement* widget_element_string_multi_create(
uint8_t x,
uint8_t y,
Align horizontal,
Align vertical,
Font font,
const char* text);
/* Create string element */
WidgetElement* widget_element_string_create(
uint8_t x,

View File

@ -0,0 +1,67 @@
#include "widget_element_i.h"
#include <m-string.h>
#include <gui/elements.h>
typedef struct {
uint8_t x;
uint8_t y;
Align horizontal;
Align vertical;
Font font;
string_t text;
} GuiStringMultiModel;
static void gui_string_multi_draw(Canvas* canvas, WidgetElement* element) {
furi_assert(canvas);
furi_assert(element);
GuiStringMultiModel* model = element->model;
if(string_size(model->text)) {
canvas_set_font(canvas, model->font);
elements_multiline_text_aligned(
canvas,
model->x,
model->y,
model->horizontal,
model->vertical,
string_get_cstr(model->text));
}
}
static void gui_string_multi_free(WidgetElement* gui_string) {
furi_assert(gui_string);
GuiStringMultiModel* model = gui_string->model;
string_clear(model->text);
free(gui_string->model);
free(gui_string);
}
WidgetElement* widget_element_string_multi_create(
uint8_t x,
uint8_t y,
Align horizontal,
Align vertical,
Font font,
const char* text) {
furi_assert(text);
// Allocate and init model
GuiStringMultiModel* model = furi_alloc(sizeof(GuiStringMultiModel));
model->x = x;
model->y = y;
model->horizontal = horizontal;
model->vertical = vertical;
model->font = font;
string_init_set_str(model->text, text);
// Allocate and init Element
WidgetElement* gui_string = furi_alloc(sizeof(WidgetElement));
gui_string->parent = NULL;
gui_string->input = NULL;
gui_string->draw = gui_string_multi_draw;
gui_string->free = gui_string_multi_free;
gui_string->model = model;
return gui_string;
}

View File

@ -1,10 +1,12 @@
ADD_SCENE(subghz, start, Start)
ADD_SCENE(subghz, receiver, Receiver)
ADD_SCENE(subghz, receiver_config, ReceiverConfig)
ADD_SCENE(subghz, receiver_info, ReceiverInfo)
ADD_SCENE(subghz, save_name, SaveName)
ADD_SCENE(subghz, save_success, SaveSuccess)
ADD_SCENE(subghz, saved, Saved)
ADD_SCENE(subghz, transmitter, Transmitter)
ADD_SCENE(subghz, no_man, NoMan)
ADD_SCENE(subghz, show_error, ShowError)
ADD_SCENE(subghz, test, Test)
ADD_SCENE(subghz, test_static, TestStatic)
ADD_SCENE(subghz, test_carrier, TestCarrier)

View File

@ -1,21 +1,102 @@
#include "../subghz_i.h"
#include "../views/subghz_receiver.h"
static void subghz_scene_receiver_update_statusbar(void* context) {
SubGhz* subghz = context;
char frequency_str[20];
char preset_str[10];
string_t history_stat_str;
string_init(history_stat_str);
if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) {
snprintf(
frequency_str,
sizeof(frequency_str),
"%03ld.%02ld",
subghz->txrx->frequency / 1000000 % 1000,
subghz->txrx->frequency / 10000 % 100);
if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async ||
subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) {
snprintf(preset_str, sizeof(preset_str), "AM");
} else if(subghz->txrx->preset == FuriHalSubGhzPreset2FSKAsync) {
snprintf(preset_str, sizeof(preset_str), "FM");
} else {
furi_check(0);
}
subghz_receiver_add_data_statusbar(
subghz->subghz_receiver, frequency_str, preset_str, string_get_cstr(history_stat_str));
} else {
subghz_receiver_add_data_statusbar(
subghz->subghz_receiver, string_get_cstr(history_stat_str), "", "");
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
}
string_clear(history_stat_str);
}
void subghz_scene_receiver_callback(SubghzReceverEvent event, void* context) {
furi_assert(context);
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
}
void subghz_scene_add_to_history_callback(SubGhzProtocolCommon* parser, 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, parser, subghz->txrx->frequency, subghz->txrx->preset)) {
subghz_protocol_reset(subghz->txrx->protocol);
string_clean(str_buff);
subghz_history_get_text_item_menu(
subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1);
subghz_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);
}
string_clear(str_buff);
}
const void subghz_scene_receiver_on_enter(void* context) {
SubGhz* subghz = context;
SubghzReceiver* subghz_receiver = subghz->subghz_receiver;
subghz_receiver_set_callback(subghz_receiver, subghz_scene_receiver_callback, subghz);
string_t str_buff;
string_init(str_buff);
//Load history to receiver
subghz_receiver_exit(subghz->subghz_receiver);
for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) {
string_clean(str_buff);
subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i);
subghz_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_scene_receiver_update_statusbar(subghz);
subghz_receiver_set_callback(subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
subghz_protocol_enable_dump(
subghz->txrx->protocol, subghz_scene_add_to_history_callback, subghz);
subghz_receiver_set_protocol(subghz_receiver, subghz->protocol_result, subghz->protocol);
subghz_receiver_set_worker(subghz_receiver, subghz->worker);
subghz->state_notifications = NOTIFICATION_RX_STATE;
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(subghz->txrx->worker);
//subghz_sleep();
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
};
if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) {
subghz_begin(subghz->txrx->preset);
subghz_rx(subghz->txrx->worker, subghz->txrx->frequency);
subghz->txrx->txrx_state = SubGhzTxRxStateRx;
}
if(subghz->txrx->idx_menu_chosen != 0) {
subghz_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
}
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver);
}
@ -24,51 +105,43 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case SubghzReceverEventSave:
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
subghz->frequency = subghz_receiver_get_frequency(subghz->subghz_receiver);
subghz->preset = subghz_receiver_get_preset(subghz->subghz_receiver);
subghz->protocol_result = subghz_receiver_get_protocol(subghz->subghz_receiver);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
return true;
break;
case SubghzReceverEventBack:
scene_manager_previous_scene(subghz->scene_manager);
// Stop CC1101 Rx
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(subghz->txrx->worker);
subghz_sleep();
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
};
subghz_history_clean(subghz->txrx->history);
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
subghz->txrx->idx_menu_chosen = 0;
subghz_protocol_enable_dump(subghz->txrx->protocol, NULL, subghz);
scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart);
return true;
break;
case SubghzReceverEventSendStart:
subghz->state_notifications = NOTIFICATION_TX_STATE;
subghz->frequency = subghz_receiver_get_frequency(subghz->subghz_receiver);
subghz->preset = subghz_receiver_get_preset(subghz->subghz_receiver);
subghz->protocol_result = subghz_receiver_get_protocol(subghz->subghz_receiver);
subghz_transmitter_tx_start(subghz);
return true;
break;
case SubghzReceverEventSendStop:
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
subghz_transmitter_tx_stop(subghz);
return true;
break;
case SubghzReceverEventMain:
subghz->state_notifications = NOTIFICATION_RX_STATE;
case SubghzReceverEventOK:
subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
return true;
break;
case SubghzReceverEventConfig:
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
return true;
break;
case SubghzReceverEventSendHistoryFull:
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
return true;
break;
default:
break;
}
} else if(event.type == SceneManagerEventTypeTick) {
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
subghz_hopper_update(subghz->txrx);
subghz_scene_receiver_update_statusbar(subghz);
}
switch(subghz->state_notifications) {
case NOTIFICATION_TX_STATE:
notification_message(subghz->notifications, &sequence_blink_red_10);
break;
case NOTIFICATION_RX_STATE:
notification_message(subghz->notifications, &sequence_blink_blue_10);
break;

View File

@ -0,0 +1,156 @@
#include "../subghz_i.h"
#define PRESET_COUNT 3
const char* const preset_text[PRESET_COUNT] = {
"AM270",
"AM650",
"FM",
};
const uint32_t preset_value[PRESET_COUNT] = {
FuriHalSubGhzPresetOok270Async, /** OOK, bandwidth 270kHz, asynchronous */
FuriHalSubGhzPresetOok650Async, /** OOK, bandwidth 650kHz, asynchronous */
FuriHalSubGhzPreset2FSKAsync, /** FM, asynchronous */
};
#define HOPPING_COUNT 2
const char* const hopping_text[HOPPING_COUNT] = {
"OFF",
"ON",
};
const uint32_t hopping_value[HOPPING_COUNT] = {
SubGhzHopperStateOFF,
SubGhzHopperStateRunnig,
};
uint8_t subghz_scene_receiver_config_uint32_value_index(
const uint32_t value,
const uint32_t values[],
uint8_t values_count) {
int64_t last_value = INT64_MIN;
uint8_t index = 0;
for(uint8_t i = 0; i < values_count; i++) {
if((value >= last_value) && (value <= values[i])) {
index = i;
break;
}
last_value = values[i];
}
return index;
}
uint8_t subghz_scene_receiver_config_hopper_value_index(
const uint32_t value,
const uint32_t values[],
uint8_t values_count,
void* context) {
furi_assert(context);
SubGhz* subghz = context;
if(value == values[0]) {
return 0;
} else {
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
" -----");
return 1;
}
}
static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) {
variable_item_set_current_value_text(item, subghz_frequencies_text[index]);
subghz->txrx->frequency = subghz_frequencies[index];
}
}
static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, preset_text[index]);
subghz->txrx->preset = preset_value[index];
}
static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, hopping_text[index]);
if(hopping_value[index] == SubGhzHopperStateOFF) {
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
subghz_frequencies_text[subghz_frequencies_433_92]);
subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
} else {
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
" -----");
}
subghz->txrx->hopper_state = hopping_value[index];
}
void subghz_scene_receiver_config_callback(SubghzReceverEvent event, void* context) {
furi_assert(context);
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
}
const void subghz_scene_receiver_config_on_enter(void* context) {
SubGhz* subghz = context;
VariableItem* item;
uint8_t value_index;
item = variable_item_list_add(
subghz->variable_item_list,
"Frequency:",
subghz_frequencies_count,
subghz_scene_receiver_config_set_frequency,
subghz);
value_index = subghz_scene_receiver_config_uint32_value_index(
subghz->txrx->frequency, subghz_frequencies, subghz_frequencies_count);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, subghz_frequencies_text[value_index]);
item = variable_item_list_add(
subghz->variable_item_list,
"Hopping:",
HOPPING_COUNT,
subghz_scene_receiver_config_set_hopping_runing,
subghz);
value_index = subghz_scene_receiver_config_hopper_value_index(
subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, hopping_text[value_index]);
item = variable_item_list_add(
subghz->variable_item_list,
"Modulation:",
PRESET_COUNT,
subghz_scene_receiver_config_set_preset,
subghz);
value_index = subghz_scene_receiver_config_uint32_value_index(
subghz->txrx->preset, preset_value, PRESET_COUNT);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, preset_text[value_index]);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewVariableItemList);
}
const bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent event) {
//SubGhz* subghz = context;
return false;
}
const void subghz_scene_receiver_config_on_exit(void* context) {
SubGhz* subghz = context;
variable_item_list_clean(subghz->variable_item_list);
}

View File

@ -0,0 +1,163 @@
#include "../subghz_i.h"
void subghz_scene_receiver_info_callback(GuiButtonType result, void* context) {
furi_assert(context);
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, result);
}
static bool subghz_scene_receiver_info_update_parser(void* context) {
SubGhz* subghz = context;
subghz->txrx->protocol_result = subghz_protocol_get_by_name(
subghz->txrx->protocol,
subghz_history_get_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
if(subghz->txrx->protocol_result->to_load_protocol != NULL) {
subghz->txrx->protocol_result->to_load_protocol(
subghz->txrx->protocol_result,
subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
subghz->txrx->frequency =
subghz_history_get_frequency(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
subghz->txrx->preset =
subghz_history_get_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
return true;
}
return false;
}
const void subghz_scene_receiver_info_on_enter(void* context) {
SubGhz* subghz = context;
if(subghz_scene_receiver_info_update_parser(subghz)) {
char buffer_str[16];
snprintf(
buffer_str,
sizeof(buffer_str),
"%03ld.%02ld",
subghz->txrx->frequency / 1000000 % 1000,
subghz->txrx->frequency / 10000 % 100);
widget_add_string_element(
subghz->widget, 78, 0, AlignLeft, AlignTop, FontSecondary, buffer_str);
if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async ||
subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) {
snprintf(buffer_str, sizeof(buffer_str), "AM");
} else if(subghz->txrx->preset == FuriHalSubGhzPreset2FSKAsync) {
snprintf(buffer_str, sizeof(buffer_str), "FM");
} else {
furi_check(0);
}
widget_add_string_element(
subghz->widget, 113, 0, AlignLeft, AlignTop, FontSecondary, buffer_str);
string_t text;
string_init(text);
subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text);
widget_add_string_multi_element(
subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text));
string_clear(text);
if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_string &&
strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) {
widget_add_button_element(
subghz->widget,
GuiButtonTypeRight,
"Save",
subghz_scene_receiver_info_callback,
subghz);
widget_add_button_element(
subghz->widget,
GuiButtonTypeCenter,
"Send",
subghz_scene_receiver_info_callback,
subghz);
}
} else {
widget_add_icon_element(subghz->widget, 32, 12, &I_DolphinFirstStart7_61x51);
widget_add_string_element(
subghz->widget, 13, 8, AlignLeft, AlignBottom, FontSecondary, "Error history parse.");
}
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget);
}
const bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeCenterPress) {
//CC1101 Stop RX -> Start TX
subghz->state_notifications = NOTIFICATION_TX_STATE;
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
subghz->txrx->hopper_state = SubGhzHopperStatePause;
}
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(subghz->txrx->worker);
//subghz_sleep();
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
}
if(!subghz_scene_receiver_info_update_parser(subghz)) {
return false;
}
if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) {
subghz_tx_start(subghz);
subghz->txrx->txrx_state = SubGhzTxRxStateTx;
}
return true;
} else if(event.event == GuiButtonTypeCenterRelease) {
//CC1101 Stop Tx -> Start RX
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
subghz_tx_stop(subghz);
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
}
if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) {
subghz_begin(subghz->txrx->preset);
subghz_rx(subghz->txrx->worker, subghz->txrx->frequency);
subghz->txrx->txrx_state = SubGhzTxRxStateRx;
}
if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
}
subghz->state_notifications = NOTIFICATION_RX_STATE;
return true;
} else if(event.event == GuiButtonTypeRight) {
//CC1101 Stop RX -> Save
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
}
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(subghz->txrx->worker);
subghz_sleep();
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
}
if(!subghz_scene_receiver_info_update_parser(subghz)) {
return false;
}
if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_string &&
strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
}
return true;
}
} else if(event.type == SceneManagerEventTypeTick) {
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
subghz_hopper_update(subghz->txrx);
}
switch(subghz->state_notifications) {
case NOTIFICATION_TX_STATE:
notification_message(subghz->notifications, &sequence_blink_red_10);
break;
case NOTIFICATION_RX_STATE:
notification_message(subghz->notifications, &sequence_blink_blue_10);
break;
default:
break;
}
}
return false;
}
const void subghz_scene_receiver_info_on_exit(void* context) {
SubGhz* subghz = context;
widget_clear(subghz->widget);
}

View File

@ -35,11 +35,13 @@ const bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent even
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) {
if(subghz_save_protocol_to_file(subghz, subghz->text_store)) {
if(strcmp(subghz->text_store, "") &&
subghz_save_protocol_to_file(subghz, subghz->text_store)) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess);
return true;
} else {
//Error save
string_set(subghz->error_str, "No name file");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
return true;
}
}

View File

@ -8,15 +8,18 @@ enum SubmenuIndex {
SubmenuIndexCAME12bit,
SubmenuIndexCAME24bit,
SubmenuIndexNeroSketch,
SubmenuIndexNeroRadio,
SubmenuIndexGateTX,
SubmenuIndexDoorHan,
};
bool subghz_scene_set_type_submenu_to_find_protocol(void* context, const char* protocol_name) {
SubGhz* subghz = context;
subghz->protocol_result = subghz_protocol_get_by_name(subghz->protocol, protocol_name);
if(subghz->protocol_result == NULL) {
//show error
subghz->txrx->protocol_result =
subghz_protocol_get_by_name(subghz->txrx->protocol, protocol_name);
if(subghz->txrx->protocol_result == NULL) {
string_set(subghz->error_str, "Protocol not found");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
return false;
}
return true;
@ -62,6 +65,8 @@ const void subghz_scene_set_type_on_enter(void* context) {
subghz);
// submenu_add_item(
// subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz);
// submenu_add_item(
// subghz->submenu, "Nero Radio", SubmenuIndexNeroRadio, subghz_scene_set_type_submenu_callback, subghz);
submenu_add_item(
subghz->submenu,
"Gate TX_433",
@ -90,81 +95,86 @@ const bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event
switch(event.event) {
case SubmenuIndexPricenton:
if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Princeton")) {
subghz->protocol_result->code_last_count_bit = 24;
subghz->txrx->protocol_result->code_last_count_bit = 24;
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
subghz->protocol_result->code_last_found = key;
subghz->txrx->protocol_result->code_last_found = key;
generated_protocol = true;
}
break;
case SubmenuIndexNiceFlo12bit:
if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Nice FLO")) {
subghz->protocol_result->code_last_count_bit = 12;
subghz->txrx->protocol_result->code_last_count_bit = 12;
key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
subghz->protocol_result->code_last_found = key;
subghz->txrx->protocol_result->code_last_found = key;
generated_protocol = true;
}
break;
case SubmenuIndexNiceFlo24bit:
if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Nice FLO")) {
subghz->protocol_result->code_last_count_bit = 24;
subghz->txrx->protocol_result->code_last_count_bit = 24;
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
subghz->protocol_result->code_last_found = key;
subghz->txrx->protocol_result->code_last_found = key;
generated_protocol = true;
}
break;
case SubmenuIndexCAME12bit:
if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME")) {
subghz->protocol_result->code_last_count_bit = 12;
subghz->txrx->protocol_result->code_last_count_bit = 12;
key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
subghz->protocol_result->code_last_found = key;
subghz->txrx->protocol_result->code_last_found = key;
generated_protocol = true;
}
break;
case SubmenuIndexCAME24bit:
if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME")) {
subghz->protocol_result->code_last_count_bit = 24;
subghz->txrx->protocol_result->code_last_count_bit = 24;
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
subghz->protocol_result->code_last_found = key;
subghz->txrx->protocol_result->code_last_found = key;
generated_protocol = true;
}
break;
// case SubmenuIndexNeroSketch:
// /* code */
// break;
// case SubmenuIndexNeroRadio:
// /* code */
// break;
case SubmenuIndexGateTX:
if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "GateTX")) {
subghz->protocol_result->code_last_count_bit = 24;
subghz->txrx->protocol_result->code_last_count_bit = 24;
key = (key & 0x00F0FFFF) | 0xF << 16; //btn 0xF, 0xC, 0xA, 0x6
subghz->protocol_result->code_last_found = subghz_protocol_common_reverse_key(
key, subghz->protocol_result->code_last_count_bit);
subghz->txrx->protocol_result->code_last_found =
subghz_protocol_common_reverse_key(
key, subghz->txrx->protocol_result->code_last_count_bit);
generated_protocol = true;
}
break;
case SubmenuIndexDoorHan:
if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "KeeLoq")) {
subghz->protocol_result->code_last_count_bit = 64;
subghz->protocol_result->serial = key & 0x0FFFFFFF;
subghz->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
subghz->protocol_result->cnt = 0x0003;
subghz->txrx->protocol_result->code_last_count_bit = 64;
subghz->txrx->protocol_result->serial = key & 0x0FFFFFFF;
subghz->txrx->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
subghz->txrx->protocol_result->cnt = 0x0003;
if(subghz_protocol_keeloq_set_manufacture_name(
subghz->protocol_result, "DoorHan")) {
subghz->protocol_result->code_last_found =
subghz_protocol_keeloq_gen_key(subghz->protocol_result);
subghz->txrx->protocol_result, "DoorHan")) {
subghz->txrx->protocol_result->code_last_found =
subghz_protocol_keeloq_gen_key(subghz->txrx->protocol_result);
generated_protocol = true;
} else {
generated_protocol = false;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNoMan);
string_set(subghz->error_str, "No manufactory key");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
}
break;
default:
return false;
break;
}
if(generated_protocol) {
subghz->frequency = subghz_frequencies[subghz_frequencies_433_92];
subghz->preset = FuriHalSubGhzPresetOok650Async;
subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
return true;
}

View File

@ -2,26 +2,26 @@
#define SCENE_NO_MAN_CUSTOM_EVENT (11UL)
void subghz_scene_no_man_popup_callback(void* context) {
void subghz_scene_show_error_popup_callback(void* context) {
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, SCENE_NO_MAN_CUSTOM_EVENT);
}
const void subghz_scene_no_man_on_enter(void* context) {
const void subghz_scene_show_error_on_enter(void* context) {
SubGhz* subghz = context;
// Setup view
Popup* popup = subghz->popup;
popup_set_icon(popup, 32, 12, &I_DolphinFirstStart7_61x51);
popup_set_header(popup, "No manufactory key", 13, 8, AlignLeft, AlignBottom);
popup_set_header(popup, string_get_cstr(subghz->error_str), 64, 8, AlignCenter, AlignBottom);
popup_set_timeout(popup, 1500);
popup_set_context(popup, subghz);
popup_set_callback(popup, subghz_scene_no_man_popup_callback);
popup_set_callback(popup, subghz_scene_show_error_popup_callback);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup);
}
const bool subghz_scene_no_man_on_event(void* context, SceneManagerEvent event) {
const bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SCENE_NO_MAN_CUSTOM_EVENT) {
@ -33,7 +33,7 @@ const bool subghz_scene_no_man_on_event(void* context, SceneManagerEvent event)
return false;
}
const void subghz_scene_no_man_on_exit(void* context) {
const void subghz_scene_show_error_on_exit(void* context) {
SubGhz* subghz = context;
// Clear view
@ -45,4 +45,5 @@ const void subghz_scene_no_man_on_exit(void* context) {
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);
string_clean(subghz->error_str);
}

View File

@ -1,5 +1,6 @@
#include "../subghz_i.h"
#include "../views/subghz_transmitter.h"
#include <lib/subghz/protocols/subghz_protocol_keeloq.h>
void subghz_scene_transmitter_callback(SubghzTransmitterEvent event, void* context) {
furi_assert(context);
@ -7,42 +8,90 @@ void subghz_scene_transmitter_callback(SubghzTransmitterEvent event, void* conte
view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
}
static void subghz_scene_transmitter_update_data_show(void* context) {
SubGhz* subghz = context;
if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->get_upload_protocol) {
string_t key_str;
string_init(key_str);
char frequency_str[10];
char preset_str[6];
uint8_t show_button = 0;
subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, key_str);
if((!strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) &&
(!strcmp(
subghz_protocol_keeloq_get_manufacture_name(subghz->txrx->protocol_result),
"Unknown"))) {
show_button = 0;
} else {
show_button = 1;
}
snprintf(
frequency_str,
sizeof(frequency_str),
"%03ld.%02ld",
subghz->txrx->frequency / 1000000 % 1000,
subghz->txrx->frequency / 10000 % 100);
if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async ||
subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) {
snprintf(preset_str, sizeof(preset_str), "AM");
} else if(subghz->txrx->preset == FuriHalSubGhzPreset2FSKAsync) {
snprintf(preset_str, sizeof(preset_str), "FM");
} else {
furi_check(0);
}
subghz_transmitter_add_data_to_show(
subghz->subghz_transmitter,
string_get_cstr(key_str),
frequency_str,
preset_str,
show_button);
string_clear(key_str);
} else {
string_set(subghz->error_str, "Protocol not found");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
}
const void subghz_scene_transmitter_on_enter(void* context) {
SubGhz* subghz = context;
SubghzTransmitter* subghz_transmitter = subghz->subghz_transmitter;
subghz_transmitter_set_callback(subghz_transmitter, subghz_scene_transmitter_callback, subghz);
subghz_transmitter_set_protocol(subghz_transmitter, subghz->protocol_result);
subghz_transmitter_set_frequency_preset(subghz_transmitter, subghz->frequency, subghz->preset);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter);
subghz_transmitter_set_callback(
subghz->subghz_transmitter, subghz_scene_transmitter_callback, subghz);
subghz_scene_transmitter_update_data_show(subghz);
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter);
}
const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubghzTransmitterEventSendStart) {
subghz->state_notifications = NOTIFICATION_TX_STATE;
subghz_transmitter_tx_start(subghz);
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(subghz->txrx->worker);
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
}
if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) {
subghz_tx_start(subghz);
subghz_scene_transmitter_update_data_show(subghz);
subghz->txrx->txrx_state = SubGhzTxRxStateTx;
}
return true;
} else if(event.event == SubghzTransmitterEventSendStop) {
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
subghz_transmitter_tx_stop(subghz);
subghz_sleep();
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
subghz_tx_stop(subghz);
subghz_sleep();
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
}
return true;
} else if(event.event == SubghzTransmitterEventBack) {
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart);
return true;
} else if(event.event == SubghzTransmitterEventNoMan) {
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneNoMan);
return true;
}
} else if(event.type == SceneManagerEventTypeTick) {
if(subghz->state_notifications == NOTIFICATION_TX_STATE) {
@ -55,7 +104,6 @@ const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent ev
const void subghz_scene_transmitter_on_exit(void* context) {
SubGhz* subghz = context;
SubghzTransmitter* subghz_transmitter = subghz->subghz_transmitter;
subghz_transmitter_set_callback(subghz_transmitter, NULL, subghz);
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
}

View File

@ -1,5 +1,22 @@
#include "subghz_i.h"
const char* const subghz_frequencies_text[] = {
"300.00",
"315.00",
"348.00",
"387.00",
"433.08",
"433.92",
"434.78",
"438.90",
"464.00",
"779.00",
"868.35",
"915.00",
"925.00",
"928.00",
};
const uint32_t subghz_frequencies[] = {
/* 300 - 348 */
300000000,
@ -20,7 +37,15 @@ const uint32_t subghz_frequencies[] = {
928000000,
};
const uint32_t subghz_hopper_frequencies[] = {
315000000,
433920000,
868350000,
};
const uint32_t subghz_frequencies_count = sizeof(subghz_frequencies) / sizeof(uint32_t);
const uint32_t subghz_hopper_frequencies_count =
sizeof(subghz_hopper_frequencies) / sizeof(uint32_t);
const uint32_t subghz_frequencies_433_92 = 5;
bool subghz_custom_event_callback(void* context, uint32_t event) {
@ -77,11 +102,6 @@ SubGhz* subghz_alloc() {
SubGhzViewReceiver,
subghz_receiver_get_view(subghz->subghz_receiver));
// Dialog
subghz->dialog_ex = dialog_ex_alloc();
view_dispatcher_add_view(
subghz->view_dispatcher, SubGhzViewDialogEx, dialog_ex_get_view(subghz->dialog_ex));
// Popup
subghz->popup = popup_alloc();
view_dispatcher_add_view(
@ -92,6 +112,11 @@ SubGhz* subghz_alloc() {
view_dispatcher_add_view(
subghz->view_dispatcher, SubGhzViewTextInput, text_input_get_view(subghz->text_input));
// Custom Widget
subghz->widget = widget_alloc();
view_dispatcher_add_view(
subghz->view_dispatcher, SubGhzViewWidget, widget_get_view(subghz->widget));
// Transmitter
subghz->subghz_transmitter = subghz_transmitter_alloc();
view_dispatcher_add_view(
@ -99,6 +124,13 @@ SubGhz* subghz_alloc() {
SubGhzViewTransmitter,
subghz_transmitter_get_view(subghz->subghz_transmitter));
// Variable Item List
subghz->variable_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
subghz->view_dispatcher,
SubGhzViewVariableItemList,
variable_item_list_get_view(subghz->variable_item_list));
// Carrier Test Module
subghz->subghz_test_carrier = subghz_test_carrier_alloc();
view_dispatcher_add_view(
@ -120,17 +152,26 @@ SubGhz* subghz_alloc() {
SubGhzViewStatic,
subghz_test_static_get_view(subghz->subghz_test_static));
//init Worker & Protocol
subghz->worker = subghz_worker_alloc();
subghz->protocol = subghz_protocol_alloc();
//init Worker & Protocol & History
subghz->txrx = furi_alloc(sizeof(SubGhzTxRx));
subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
subghz->txrx->history = subghz_history_alloc();
subghz->txrx->worker = subghz_worker_alloc();
subghz->txrx->protocol = subghz_protocol_alloc();
subghz_worker_set_overrun_callback(
subghz->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset);
subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset);
subghz_worker_set_pair_callback(
subghz->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse);
subghz_worker_set_context(subghz->worker, subghz->protocol);
subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse);
subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->protocol);
subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/subghz/keeloq_mfcodes");
subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/subghz/nice_floor_s_rx");
//Init Error_str
string_init(subghz->error_str);
subghz_protocol_load_keeloq_file(subghz->txrx->protocol, "/ext/subghz/keeloq_mfcodes");
subghz_protocol_load_nice_flor_s_file(subghz->txrx->protocol, "/ext/subghz/nice_floor_s_rx");
//subghz_protocol_enable_dump_text(subghz->protocol, subghz_text_callback, subghz);
@ -160,18 +201,22 @@ void subghz_free(SubGhz* subghz) {
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTextInput);
text_input_free(subghz->text_input);
// Receiver
// Custom Widget
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewWidget);
widget_free(subghz->widget);
// Transmitter
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTransmitter);
subghz_transmitter_free(subghz->subghz_transmitter);
// Variable Item List
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewVariableItemList);
variable_item_list_free(subghz->variable_item_list);
// Submenu
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewMenu);
submenu_free(subghz->submenu);
// DialogEx
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewDialogEx);
dialog_ex_free(subghz->dialog_ex);
// Popup
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewPopup);
popup_free(subghz->popup);
@ -186,9 +231,14 @@ void subghz_free(SubGhz* subghz) {
furi_record_close("gui");
subghz->gui = NULL;
//Worker & Protocol
subghz_protocol_free(subghz->protocol);
subghz_worker_free(subghz->worker);
//Worker & Protocol & History
subghz_protocol_free(subghz->txrx->protocol);
subghz_worker_free(subghz->txrx->worker);
subghz_history_free(subghz->txrx->history);
free(subghz->txrx);
//Error string
string_clear(subghz->error_str);
// Notifications
furi_record_close("notification");

View File

@ -128,21 +128,27 @@ void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output,
}
}
void subghz_history_add_to_history(SubGhzHistory* instance, void* context) {
bool subghz_history_add_to_history(
SubGhzHistory* instance,
void* context,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
furi_assert(instance);
furi_assert(context);
SubGhzProtocolCommon* protocol = context;
if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return;
if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return false;
if((instance->code_last_found == (protocol->code_last_found & 0xFFFF0FFFFFFFFFFF)) &&
((millis() - instance->last_update_timestamp) < 500)) {
instance->last_update_timestamp = millis();
return;
return false;
}
instance->code_last_found = protocol->code_last_found & 0xFFFF0FFFFFFFFFFF;
instance->last_update_timestamp = millis();
instance->history[instance->last_index_write].real_frequency = frequency;
instance->history[instance->last_index_write].preset = preset;
instance->history[instance->last_index_write].te = 0;
instance->history[instance->last_index_write].manufacture_name = NULL;
instance->history[instance->last_index_write].name = protocol->name;
@ -161,4 +167,5 @@ void subghz_history_add_to_history(SubGhzHistory* instance, void* context) {
instance->history[instance->last_index_write].type_protocol = protocol->type_protocol;
instance->last_index_write++;
return true;
}

View File

@ -1,3 +1,4 @@
#pragma once
#include <lib/subghz/protocols/subghz_protocol_common.h>
@ -94,8 +95,15 @@ bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output
*
* @param instance - SubGhzHistory instance
* @param context - SubGhzProtocolCommon context
* @param frequency - frequency Hz
* @param preset - FuriHalSubGhzPreset preset
* @return bool;
*/
void subghz_history_add_to_history(SubGhzHistory* instance, void* context);
bool subghz_history_add_to_history(
SubGhzHistory* instance,
void* context,
uint32_t frequency,
FuriHalSubGhzPreset preset);
/** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data
*
@ -104,3 +112,5 @@ void subghz_history_add_to_history(SubGhzHistory* instance, void* context);
* @return SubGhzProtocolCommonLoad*
*/
SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);
void subghz_hopper_update(void* context);

View File

@ -19,6 +19,9 @@ void subghz_begin(FuriHalSubGhzPreset preset) {
uint32_t subghz_rx(void* context, uint32_t frequency) {
furi_assert(context);
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
furi_check(0);
}
SubGhzWorker* worker = context;
furi_hal_subghz_idle();
@ -33,6 +36,9 @@ uint32_t subghz_rx(void* context, uint32_t frequency) {
}
uint32_t subghz_tx(uint32_t frequency) {
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
furi_check(0);
}
furi_hal_subghz_idle();
uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
@ -53,6 +59,7 @@ void subghz_rx_end(void* context) {
subghz_worker_stop(worker);
furi_hal_subghz_stop_async_rx();
}
furi_hal_subghz_idle();
}
void subghz_sleep(void) {
@ -66,41 +73,46 @@ void subghz_frequency_preset_to_str(void* context, string_t output) {
output,
"Frequency: %d\n"
"Preset: %d\n",
(int)subghz->frequency,
(int)subghz->preset);
(int)subghz->txrx->frequency,
(int)subghz->txrx->preset);
}
void subghz_transmitter_tx_start(void* context) {
void subghz_tx_start(void* context) {
furi_assert(context);
SubGhz* subghz = context;
subghz->encoder = subghz_protocol_encoder_common_alloc();
subghz->encoder->repeat = 200; //max repeat with the button held down
subghz->txrx->encoder = subghz_protocol_encoder_common_alloc();
subghz->txrx->encoder->repeat = 200; //max repeat with the button held down
//get upload
if(subghz->protocol_result->get_upload_protocol) {
if(subghz->protocol_result->get_upload_protocol(subghz->protocol_result, subghz->encoder)) {
if(subghz->preset) {
subghz_begin(subghz->preset);
if(subghz->txrx->protocol_result->get_upload_protocol) {
if(subghz->txrx->protocol_result->get_upload_protocol(
subghz->txrx->protocol_result, subghz->txrx->encoder)) {
if(subghz->txrx->preset) {
subghz_begin(subghz->txrx->preset);
} else {
subghz_begin(FuriHalSubGhzPresetOok650Async);
subghz_begin(FuriHalSubGhzPresetOok270Async);
}
if(subghz->frequency) {
subghz_tx(subghz->frequency);
if(subghz->txrx->frequency) {
subghz_tx(subghz->txrx->frequency);
} else {
subghz_tx(433920000);
}
//Start TX
furi_hal_subghz_start_async_tx(subghz_protocol_encoder_common_yield, subghz->encoder);
furi_hal_subghz_start_async_tx(
subghz_protocol_encoder_common_yield, subghz->txrx->encoder);
}
}
}
void subghz_transmitter_tx_stop(void* context) {
void subghz_tx_stop(void* context) {
furi_assert(context);
SubGhz* subghz = context;
//Stop TX
furi_hal_subghz_stop_async_tx();
subghz_protocol_encoder_common_free(subghz->encoder);
subghz_protocol_encoder_common_free(subghz->txrx->encoder);
furi_hal_subghz_idle();
//if protocol dynamic then we save the last upload
if(subghz->protocol_result->type_protocol == TYPE_PROTOCOL_DYNAMIC) {
if(subghz->txrx->protocol_result->type_protocol == TYPE_PROTOCOL_DYNAMIC) {
subghz_save_protocol_to_file(subghz, subghz->text_store);
}
notification_message(subghz->notifications, &sequence_reset_red);
@ -133,7 +145,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) {
if(res != 1) {
break;
}
subghz->frequency = (uint32_t)data;
subghz->txrx->frequency = (uint32_t)data;
// Read and parse preset from 2st line
if(!file_worker_read_until(file_worker, temp_str, '\n')) {
@ -143,7 +155,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) {
if(res != 1) {
break;
}
subghz->preset = (FuriHalSubGhzPreset)data;
subghz->txrx->preset = (FuriHalSubGhzPreset)data;
// Read and parse name protocol from 2st line
if(!file_worker_read_until(file_worker, temp_str, '\n')) {
@ -151,13 +163,13 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) {
}
// strlen("Protocol: ") = 10
string_right(temp_str, 10);
subghz->protocol_result =
subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str));
if(subghz->protocol_result == NULL) {
subghz->txrx->protocol_result =
subghz_protocol_get_by_name(subghz->txrx->protocol, string_get_cstr(temp_str));
if(subghz->txrx->protocol_result == NULL) {
break;
}
if(!subghz->protocol_result->to_load_protocol_from_file(
file_worker, subghz->protocol_result)) {
if(!subghz->txrx->protocol_result->to_load_protocol_from_file(
file_worker, subghz->txrx->protocol_result)) {
break;
}
loaded = true;
@ -175,8 +187,9 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) {
}
bool subghz_save_protocol_to_file(void* context, const char* dev_name) {
furi_assert(context);
SubGhz* subghz = context;
furi_assert(subghz->protocol_result);
furi_assert(subghz->txrx->protocol_result);
FileWorker* file_worker = file_worker_alloc(false);
string_t dev_file_name;
string_init(dev_file_name);
@ -210,7 +223,7 @@ bool subghz_save_protocol_to_file(void* context, const char* dev_name) {
break;
}
//Get string save
subghz->protocol_result->to_save_string(subghz->protocol_result, temp_str);
subghz->txrx->protocol_result->to_save_string(subghz->txrx->protocol_result, temp_str);
// Prepare and write data to file
if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_size(temp_str))) {
break;
@ -276,7 +289,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) {
if(sscanf_res != 1) {
break;
}
subghz->frequency = (uint32_t)data;
subghz->txrx->frequency = (uint32_t)data;
// Read and parse preset from 2st line
if(!file_worker_read_until(file_worker, temp_str, '\n')) {
@ -286,7 +299,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) {
if(sscanf_res != 1) {
break;
}
subghz->preset = (FuriHalSubGhzPreset)data;
subghz->txrx->preset = (FuriHalSubGhzPreset)data;
// Read and parse name protocol from 3st line
if(!file_worker_read_until(file_worker, temp_str, '\n')) {
@ -294,13 +307,13 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) {
}
// strlen("Protocol: ") = 10
string_right(temp_str, 10);
subghz->protocol_result =
subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str));
if(subghz->protocol_result == NULL) {
subghz->txrx->protocol_result =
subghz_protocol_get_by_name(subghz->txrx->protocol, string_get_cstr(temp_str));
if(subghz->txrx->protocol_result == NULL) {
break;
}
if(!subghz->protocol_result->to_load_protocol_from_file(
file_worker, subghz->protocol_result)) {
if(!subghz->txrx->protocol_result->to_load_protocol_from_file(
file_worker, subghz->txrx->protocol_result)) {
break;
}
res = true;
@ -328,3 +341,57 @@ uint32_t subghz_random_serial(void) {
}
return (uint32_t)rand();
}
void subghz_hopper_update(void* context) {
furi_assert(context);
SubGhzTxRx* txrx = context;
switch(txrx->hopper_state) {
case SubGhzHopperStateOFF:
return;
break;
case SubGhzHopperStatePause:
return;
break;
case SubGhzHopperStateRSSITimeOut:
if(txrx->hopper_timeout != 0) {
txrx->hopper_timeout--;
return;
}
break;
default:
break;
}
float rssi = -127.0f;
if(txrx->hopper_state != SubGhzHopperStateRSSITimeOut) {
// See RSSI Calculation timings in CC1101 17.3 RSSI
rssi = furi_hal_subghz_get_rssi();
// Stay if RSSI is high enough
if(rssi > -90.0f) {
txrx->hopper_timeout = 10;
txrx->hopper_state = SubGhzHopperStateRSSITimeOut;
return;
}
} else {
txrx->hopper_state = SubGhzHopperStateRunnig;
}
// Select next frequency
if(txrx->hopper_idx_frequency < subghz_hopper_frequencies_count - 1) {
txrx->hopper_idx_frequency++;
} else {
txrx->hopper_idx_frequency = 0;
}
if(txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(txrx->worker);
txrx->txrx_state = SubGhzTxRxStateIdle;
};
if(txrx->txrx_state == SubGhzTxRxStateIdle) {
subghz_protocol_reset(txrx->protocol);
txrx->frequency = subghz_hopper_frequencies[txrx->hopper_idx_frequency];
subghz_rx(txrx->worker, txrx->frequency);
txrx->txrx_state = SubGhzTxRxStateRx;
}
}

View File

@ -15,9 +15,9 @@
#include <notification/notification-messages.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/submenu.h>
#include <gui/modules/dialog_ex.h>
#include <gui/modules/popup.h>
#include <gui/modules/text_input.h>
#include <gui/modules/widget.h>
#include <subghz/scenes/subghz_scene.h>
@ -26,6 +26,8 @@
#include <lib/subghz/protocols/subghz_protocol_common.h>
#include "subghz_history.h"
#include <gui/modules/variable-item-list.h>
#define SUBGHZ_TEXT_STORE_SIZE 128
#define NOTIFICATION_STARTING_STATE 0u
@ -33,48 +35,81 @@
#define NOTIFICATION_TX_STATE 2u
#define NOTIFICATION_RX_STATE 3u
extern const char* const subghz_frequencies_text[];
extern const uint32_t subghz_frequencies[];
extern const uint32_t subghz_hopper_frequencies[];
extern const uint32_t subghz_frequencies_count;
extern const uint32_t subghz_hopper_frequencies_count;
extern const uint32_t subghz_frequencies_433_92;
struct SubGhz {
Gui* gui;
NotificationApp* notifications;
/** SubGhzTxRx state */
typedef enum {
SubGhzTxRxStateIdle,
SubGhzTxRxStateRx,
SubGhzTxRxStateTx,
} SubGhzTxRxState;
/** SubGhzHopperState state */
typedef enum {
SubGhzHopperStateOFF,
SubGhzHopperStateRunnig,
SubGhzHopperStatePause,
SubGhzHopperStateRSSITimeOut,
} SubGhzHopperState;
struct SubGhzTxRx {
SubGhzWorker* worker;
SubGhzProtocol* protocol;
SubGhzProtocolCommon* protocol_result;
SubGhzProtocolCommonEncoder* encoder;
uint32_t frequency;
FuriHalSubGhzPreset preset;
SubGhzHistory* history;
uint16_t idx_menu_chosen;
SubGhzTxRxState txrx_state;
//bool hopper_runing;
SubGhzHopperState hopper_state;
uint8_t hopper_timeout;
uint8_t hopper_idx_frequency;
};
typedef struct SubGhzTxRx SubGhzTxRx;
struct SubGhz {
Gui* gui;
NotificationApp* notifications;
SubGhzTxRx* txrx;
SceneManager* scene_manager;
ViewDispatcher* view_dispatcher;
Submenu* submenu;
DialogEx* dialog_ex;
Popup* popup;
TextInput* text_input;
Widget* widget;
char text_store[SUBGHZ_TEXT_STORE_SIZE + 1];
uint8_t state_notifications;
SubghzReceiver* subghz_receiver;
SubghzTransmitter* subghz_transmitter;
VariableItemList* variable_item_list;
SubghzTestStatic* subghz_test_static;
SubghzTestCarrier* subghz_test_carrier;
SubghzTestPacket* subghz_test_packet;
string_t error_str;
};
typedef enum {
SubGhzViewMenu,
SubGhzViewDialogEx,
SubGhzViewReceiver,
SubGhzViewPopup,
SubGhzViewTextInput,
SubGhzViewWidget,
SubGhzViewTransmitter,
SubGhzViewVariableItemList,
SubGhzViewStatic,
SubGhzViewTestCarrier,
SubGhzViewTestPacket,
@ -86,8 +121,8 @@ uint32_t subghz_tx(uint32_t frequency);
void subghz_idle(void);
void subghz_rx_end(void* context);
void subghz_sleep(void);
void subghz_transmitter_tx_start(void* context);
void subghz_transmitter_tx_stop(void* context);
void subghz_tx_start(void* context);
void subghz_tx_stop(void* context);
bool subghz_key_load(SubGhz* subghz, const char* file_path);
bool subghz_save_protocol_to_file(void* context, const char* dev_name);
bool subghz_load_protocol_from_file(SubGhz* subghz);

View File

@ -1,42 +1,32 @@
#include "subghz_receiver.h"
#include "../subghz_i.h"
#include <math.h>
#include <furi.h>
#include <furi-hal.h>
#include <input/input.h>
#include <gui/elements.h>
#include <notification/notification-messages.h>
#include <lib/subghz/protocols/subghz_protocol_princeton.h>
#include <assets_icons.h>
#include <m-string.h>
#include <m-array.h>
#define FRAME_HEIGHT 12
#define MAX_LEN_PX 100
#define MENU_ITEMS 4
#define COUNT_FREQUNCY_HOPPER 3
const uint32_t subghz_frequencies_hopper[] = {
/* 300 - 348 */
315000000,
/* 387 - 464 */
433920000, /* LPD433 mid */
/* 779 - 928 */
868350000,
typedef struct {
string_t item_str;
uint8_t type;
} SubGhzReceiverMenuItem;
ARRAY_DEF(SubGhzReceiverMenuItemArray, SubGhzReceiverMenuItem, M_POD_OPLIST)
#define M_OPL_SubGhzReceiverMenuItemArray_t() \
ARRAY_OPLIST(SubGhzReceiverMenuItemArray, M_POD_OPLIST)
struct SubGhzReceiverHistory {
SubGhzReceiverMenuItemArray_t data;
};
typedef enum {
ReceiverSceneStart,
ReceiverSceneMain,
ReceiverSceneConfig,
ReceiverSceneInfo,
} SubghzReceiverScene;
typedef enum {
SubGhzHopperStateOFF,
SubGhzHopperStatePause,
SubGhzHopperStateRunnig,
SubGhzHopperStateRSSITimeOut,
} SubGhzHopperState;
typedef struct SubGhzReceiverHistory SubGhzReceiverHistory;
static const Icon* ReceiverItemIcons[] = {
[TYPE_PROTOCOL_UNKNOWN] = &I_Quest_7x8,
@ -48,27 +38,16 @@ struct SubghzReceiver {
View* view;
SubghzReceiverCallback callback;
void* context;
SubGhzWorker* worker;
SubGhzProtocol* protocol;
osTimerId timer;
SubGhzHopperState hopper_state;
uint8_t hopper_timeout;
uint32_t event_key_sequence;
};
typedef struct {
string_t text;
uint16_t scene;
SubGhzProtocolCommon* protocol_result;
SubGhzHistory* history;
uint8_t frequency;
uint8_t temp_frequency;
uint32_t real_frequency;
string_t frequency_str;
string_t preset_str;
string_t history_stat_str;
SubGhzReceiverHistory* history;
uint16_t idx;
uint16_t list_offset;
uint16_t history_item;
bool menu;
} SubghzReceiverModel;
void subghz_receiver_set_callback(
@ -81,35 +60,6 @@ void subghz_receiver_set_callback(
subghz_receiver->context = context;
}
void subghz_receiver_set_protocol(
SubghzReceiver* subghz_receiver,
SubGhzProtocolCommon* protocol_result,
SubGhzProtocol* protocol) {
furi_assert(subghz_receiver);
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
model->protocol_result = protocol_result;
return true;
});
subghz_receiver->protocol = protocol;
}
SubGhzProtocolCommon* subghz_receiver_get_protocol(SubghzReceiver* subghz_receiver) {
furi_assert(subghz_receiver);
SubGhzProtocolCommon* result = NULL;
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
result = model->protocol_result;
return false;
});
return result;
}
void subghz_receiver_set_worker(SubghzReceiver* subghz_receiver, SubGhzWorker* worker) {
furi_assert(subghz_receiver);
subghz_receiver->worker = worker;
}
static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) {
furi_assert(subghz_receiver);
@ -129,6 +79,38 @@ static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) {
});
}
void subghz_receiver_add_item_to_menu(
SubghzReceiver* subghz_receiver,
const char* name,
uint8_t type) {
furi_assert(subghz_receiver);
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
SubGhzReceiverMenuItem* item_menu =
SubGhzReceiverMenuItemArray_push_raw(model->history->data);
string_init_set_str(item_menu->item_str, name);
item_menu->type = type;
model->history_item++;
return true;
});
subghz_receiver_update_offset(subghz_receiver);
}
void subghz_receiver_add_data_statusbar(
SubghzReceiver* subghz_receiver,
const char* frequency_str,
const char* preset_str,
const char* history_stat_str) {
furi_assert(subghz_receiver);
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
string_set(model->frequency_str, frequency_str);
string_set(model->preset_str, preset_str);
string_set(model->history_stat_str, history_stat_str);
return true;
});
}
static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT);
@ -144,462 +126,113 @@ static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scroll
}
void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
bool scrollbar = model->history_item > 4;
string_t str_buff;
char buffer[64];
uint32_t frequency;
string_init(str_buff);
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
switch(model->scene) {
case ReceiverSceneMain:
for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
size_t idx = CLAMP(i + model->list_offset, model->history_item, 0);
subghz_history_get_text_item_menu(model->history, str_buff, idx);
elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX);
if(model->idx == idx) {
subghz_receiver_draw_frame(canvas, i, scrollbar);
} else {
canvas_set_color(canvas, ColorBlack);
}
canvas_draw_icon(
canvas,
1,
2 + i * FRAME_HEIGHT,
ReceiverItemIcons[subghz_history_get_type_protocol(model->history, idx)]);
canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, string_get_cstr(str_buff));
string_clean(str_buff);
}
if(scrollbar) {
elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item);
}
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
elements_button_left(canvas, "Config");
elements_button_left(canvas, "Config");
canvas_draw_line(canvas, 46, 51, 125, 51);
if(subghz_history_get_text_space_left(model->history, str_buff)) {
canvas_draw_str(canvas, 54, 62, string_get_cstr(str_buff));
} else {
if((model->real_frequency / 1000 % 10) > 4) {
frequency = model->real_frequency + 10000;
} else {
frequency = model->real_frequency;
}
snprintf(
buffer,
sizeof(buffer),
"%03ld.%02ld",
frequency / 1000000 % 1000,
frequency / 10000 % 100);
canvas_draw_str(canvas, 44, 62, buffer);
canvas_draw_str(canvas, 79, 62, "AM");
canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff));
}
break;
case ReceiverSceneStart:
canvas_draw_str(canvas, 44, 62, string_get_cstr(model->frequency_str));
canvas_draw_str(canvas, 79, 62, string_get_cstr(model->preset_str));
canvas_draw_str(canvas, 96, 62, string_get_cstr(model->history_stat_str));
if(model->history_item == 0) {
canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 63, 46, "Scanning...");
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
elements_button_left(canvas, "Config");
if((model->real_frequency / 1000 % 10) > 4) {
frequency = model->real_frequency + 10000;
} else {
frequency = model->real_frequency;
}
snprintf(
buffer,
sizeof(buffer),
"%03ld.%02ld",
frequency / 1000000 % 1000,
frequency / 10000 % 100);
canvas_draw_str(canvas, 44, 62, buffer);
canvas_draw_str(canvas, 79, 62, "AM");
subghz_history_get_text_space_left(model->history, str_buff);
canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff));
canvas_draw_line(canvas, 46, 51, 125, 51);
break;
case ReceiverSceneConfig:
if(model->frequency < subghz_frequencies_count) {
snprintf(
buffer,
sizeof(buffer),
"Frequency: < %03ld.%03ldMHz >",
model->real_frequency / 1000000 % 1000,
model->real_frequency / 1000 % 1000);
canvas_draw_str(canvas, 0, 8, buffer);
canvas_draw_str(canvas, 0, 18, "Frequency Hopping: <OFF>");
} else {
canvas_draw_str(canvas, 0, 8, "Frequency: < --- >");
canvas_draw_str(canvas, 0, 18, "Frequency Hopping: <ON>");
}
canvas_draw_str(canvas, 0, 28, "Modulation: <AM>");
elements_button_center(canvas, "Save");
break;
case ReceiverSceneInfo:
canvas_set_font(canvas, FontSecondary);
elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text));
snprintf(
buffer,
sizeof(buffer),
"%03ld.%03ld",
subghz_history_get_frequency(model->history, model->idx) / 1000000 % 1000,
subghz_history_get_frequency(model->history, model->idx) / 1000 % 1000);
canvas_draw_str(canvas, 90, 8, buffer);
if(model->protocol_result && model->protocol_result->to_save_string &&
strcmp(model->protocol_result->name, "KeeLoq")) {
elements_button_right(canvas, "Save");
elements_button_center(canvas, "Send");
}
break;
default:
break;
return;
}
canvas_draw_line(canvas, 46, 51, 125, 51);
bool scrollbar = model->history_item > 4;
string_t str_buff;
string_init(str_buff);
SubGhzReceiverMenuItem* item_menu;
for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
size_t idx = CLAMP(i + model->list_offset, model->history_item, 0);
item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx);
string_set(str_buff, item_menu->item_str);
elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX);
if(model->idx == idx) {
subghz_receiver_draw_frame(canvas, i, scrollbar);
} else {
canvas_set_color(canvas, ColorBlack);
}
canvas_draw_icon(canvas, 1, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]);
canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, string_get_cstr(str_buff));
string_clean(str_buff);
}
if(scrollbar) {
elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item);
}
string_clear(str_buff);
}
void subghz_receiver_history_full(void* context) {
furi_assert(context);
SubghzReceiver* subghz_receiver = context;
subghz_receiver->callback(SubghzReceverEventSendHistoryFull, subghz_receiver->context);
subghz_receiver->hopper_state = SubGhzHopperStateOFF;
}
bool subghz_receiver_input(InputEvent* event, void* context) {
furi_assert(context);
uint8_t scene = 0;
SubghzReceiver* subghz_receiver = context;
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
scene = model->scene;
return false;
});
bool can_be_saved = false;
switch(scene) {
case ReceiverSceneMain:
if(event->key == InputKeyBack && event->type == InputTypeShort) {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
model->idx = 0;
model->list_offset = 0;
model->history_item = 0;
subghz_history_clean(model->history);
return true;
});
return false;
} else if(
event->key == InputKeyUp &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
if(model->idx != 0) model->idx--;
return true;
});
} else if(
event->key == InputKeyDown &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
if(model->idx != subghz_history_get_item(model->history) - 1) model->idx++;
return true;
});
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
subghz_receiver->hopper_state = SubGhzHopperStatePause;
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
model->scene = ReceiverSceneConfig;
model->temp_frequency = model->frequency;
return true;
});
subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
subghz_receiver->event_key_sequence = event->sequence;
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
string_clean(model->text);
model->protocol_result = subghz_protocol_get_by_name(
subghz_receiver->protocol,
subghz_history_get_name(model->history, model->idx));
if(model->protocol_result->to_load_protocol != NULL) {
model->protocol_result->to_load_protocol(
model->protocol_result,
subghz_history_get_raw_data(model->history, model->idx));
model->protocol_result->to_string(model->protocol_result, model->text);
model->scene = ReceiverSceneInfo;
}
return true;
});
}
break;
case ReceiverSceneInfo:
if(event->key == InputKeyBack && event->type == InputTypeShort) {
subghz_receiver->callback(SubghzReceverEventBack, subghz_receiver->context);
} else if(
event->key == InputKeyUp &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
can_be_saved =
(model->protocol_result && model->protocol_result->to_save_string &&
strcmp(model->protocol_result->name, "KeeLoq"));
return false;
if(model->idx != 0) model->idx--;
return true;
});
if(event->key == InputKeyBack && event->type == InputTypeShort) {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
subghz_rx_end(subghz_receiver->worker);
model->real_frequency =
subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]);
subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
model->scene = ReceiverSceneMain;
return true;
});
subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
} else if(can_be_saved && event->key == InputKeyRight) {
subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context);
return false;
} else if(
can_be_saved && event->key == InputKeyOk && event->type == InputTypePress &&
subghz_receiver->event_key_sequence != event->sequence) {
subghz_receiver->hopper_state = SubGhzHopperStatePause;
subghz_rx_end(subghz_receiver->worker);
subghz_receiver->callback(SubghzReceverEventSendStart, subghz_receiver->context);
return true;
} else if(
can_be_saved && event->key == InputKeyOk && event->type == InputTypeRelease &&
subghz_receiver->event_key_sequence != event->sequence) {
subghz_receiver->callback(SubghzReceverEventSendStop, subghz_receiver->context);
return true;
}
break;
case ReceiverSceneConfig:
if(event->type != InputTypeShort) return false;
if(event->key == InputKeyBack) {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
model->frequency = model->temp_frequency;
model->real_frequency = subghz_frequencies[model->frequency];
subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
if(subghz_history_get_item(model->history) == 0) {
model->scene = ReceiverSceneStart;
} else {
model->scene = ReceiverSceneMain;
}
return true;
});
subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
} else if(event->key == InputKeyOk) {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
if(model->frequency < subghz_frequencies_count) {
subghz_rx_end(subghz_receiver->worker);
model->real_frequency = subghz_rx(
subghz_receiver->worker, subghz_frequencies[model->frequency]);
subghz_receiver->hopper_state = SubGhzHopperStateOFF;
} else {
osTimerStart(subghz_receiver->timer, 1024 / 10);
subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
}
if(subghz_history_get_item(model->history) == 0) {
model->scene = ReceiverSceneStart;
} else {
model->scene = ReceiverSceneMain;
}
return true;
});
subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
} else {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
bool model_updated = false;
if(event->key == InputKeyLeft) {
if(model->frequency > 0) model->frequency--;
model_updated = true;
} else if(event->key == InputKeyRight) {
if(model->frequency < subghz_frequencies_count) model->frequency++;
model_updated = true;
}
if(model_updated) {
model->real_frequency = subghz_frequencies[model->frequency];
}
return model_updated;
});
}
break;
case ReceiverSceneStart:
if(event->type != InputTypeShort) return false;
if(event->key == InputKeyBack) {
return false;
} else if(event->key == InputKeyLeft) {
subghz_receiver->hopper_state = SubGhzHopperStatePause;
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
model->temp_frequency = model->frequency;
model->scene = ReceiverSceneConfig;
return true;
});
subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
}
break;
default:
break;
}
subghz_receiver_update_offset(subghz_receiver);
if(scene != ReceiverSceneInfo) {
} else if(
event->key == InputKeyDown &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
if(subghz_history_get_text_space_left(model->history, NULL)) {
subghz_receiver_history_full(subghz_receiver);
if(model->idx != model->history_item - 1) model->idx++;
return true;
});
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
if(model->history_item != 0) {
subghz_receiver->callback(SubghzReceverEventOK, subghz_receiver->context);
}
return false;
});
}
subghz_receiver_update_offset(subghz_receiver);
return true;
}
void subghz_receiver_text_callback(string_t text, void* context) {
furi_assert(context);
SubghzReceiver* subghz_receiver = context;
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
string_set(model->text, text);
model->scene = ReceiverSceneMain;
return true;
});
}
void subghz_receiver_protocol_callback(SubGhzProtocolCommon* parser, void* context) {
furi_assert(context);
SubghzReceiver* subghz_receiver = context;
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
model->protocol_result = parser;
subghz_history_set_frequency_preset(
model->history,
model->history_item,
model->real_frequency,
FuriHalSubGhzPresetOok650Async);
subghz_history_add_to_history(model->history, parser);
model->history_item = subghz_history_get_item(model->history);
model->scene = ReceiverSceneMain;
if(subghz_history_get_text_space_left(model->history, NULL)) {
subghz_receiver_history_full(subghz_receiver);
}
return true;
});
subghz_protocol_reset(subghz_receiver->protocol);
subghz_receiver_update_offset(subghz_receiver);
}
static void subghz_receiver_timer_callback(void* context) {
furi_assert(context);
SubghzReceiver* subghz_receiver = context;
switch(subghz_receiver->hopper_state) {
case SubGhzHopperStatePause:
return;
break;
case SubGhzHopperStateOFF:
osTimerStop(subghz_receiver->timer);
return;
break;
case SubGhzHopperStateRSSITimeOut:
if(subghz_receiver->hopper_timeout != 0) {
subghz_receiver->hopper_timeout--;
return;
}
break;
default:
break;
}
float rssi = -127.0f;
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
if(subghz_receiver->hopper_state != SubGhzHopperStateRSSITimeOut) {
// See RSSI Calculation timings in CC1101 17.3 RSSI
rssi = furi_hal_subghz_get_rssi();
// Stay if RSSI is high enough
if(rssi > -90.0f) {
subghz_receiver->hopper_timeout = 10;
subghz_receiver->hopper_state = SubGhzHopperStateRSSITimeOut;
return false;
}
} else {
subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
}
// Select next frequency
if(model->frequency < COUNT_FREQUNCY_HOPPER - 1) {
model->frequency++;
} else {
model->frequency = 0;
}
// Restart radio
furi_hal_subghz_idle();
subghz_protocol_reset(subghz_receiver->protocol);
model->real_frequency = furi_hal_subghz_set_frequency_and_path(
subghz_frequencies_hopper[model->frequency]);
furi_hal_subghz_rx();
return true;
});
}
void subghz_receiver_enter(void* context) {
furi_assert(context);
SubghzReceiver* subghz_receiver = context;
//Start CC1101 Rx
subghz_begin(FuriHalSubGhzPresetOok650Async);
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
subghz_rx_end(subghz_receiver->worker);
model->frequency = subghz_frequencies_433_92;
model->real_frequency =
subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]);
if(subghz_history_get_item(model->history) == 0) {
model->scene = ReceiverSceneStart;
} else {
model->scene = ReceiverSceneMain;
}
return true;
});
subghz_protocol_enable_dump(
subghz_receiver->protocol, subghz_receiver_protocol_callback, subghz_receiver);
//SubghzReceiver* subghz_receiver = context;
}
void subghz_receiver_exit(void* context) {
furi_assert(context);
SubghzReceiver* subghz_receiver = context;
osTimerStop(subghz_receiver->timer);
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
string_clean(model->text);
return true;
string_clean(model->frequency_str);
string_clean(model->preset_str);
string_clean(model->history_stat_str);
for
M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) {
string_clear(item_menu->item_str);
item_menu->type = 0;
}
SubGhzReceiverMenuItemArray_clean(model->history->data);
model->idx = 0;
model->list_offset = 0;
model->history_item = 0;
return false;
});
// Stop CC1101 Rx
subghz_rx_end(subghz_receiver->worker);
subghz_sleep();
}
SubghzReceiver* subghz_receiver_alloc() {
@ -616,14 +249,14 @@ SubghzReceiver* subghz_receiver_alloc() {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
string_init(model->text);
model->history = subghz_history_alloc();
string_init(model->frequency_str);
string_init(model->preset_str);
string_init(model->history_stat_str);
model->history = furi_alloc(sizeof(SubGhzReceiverHistory));
SubGhzReceiverMenuItemArray_init(model->history->data);
return true;
});
subghz_receiver->timer =
osTimerNew(subghz_receiver_timer_callback, osTimerPeriodic, subghz_receiver, NULL);
subghz_receiver->hopper_state = SubGhzHopperStateOFF;
return subghz_receiver;
}
@ -632,11 +265,18 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver) {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
string_clear(model->text);
subghz_history_free(model->history);
return false;
string_clear(model->frequency_str);
string_clear(model->preset_str);
string_clear(model->history_stat_str);
for
M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) {
string_clear(item_menu->item_str);
item_menu->type = 0;
}
SubGhzReceiverMenuItemArray_clear(model->history->data);
free(model->history);
return false;
});
osTimerDelete(subghz_receiver->timer);
view_free(subghz_receiver->view);
free(subghz_receiver);
}
@ -646,43 +286,24 @@ View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) {
return subghz_receiver->view;
}
uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver) {
uint16_t subghz_receiver_get_idx_menu(SubghzReceiver* subghz_receiver) {
furi_assert(subghz_receiver);
uint32_t frequency;
uint32_t idx = 0;
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
frequency = subghz_history_get_frequency(model->history, model->idx);
idx = model->idx;
return false;
});
return frequency;
return idx;
}
FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver) {
void subghz_receiver_set_idx_menu(SubghzReceiver* subghz_receiver, uint16_t idx) {
furi_assert(subghz_receiver);
FuriHalSubGhzPreset preset;
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
preset = subghz_history_get_preset(model->history, model->idx);
return false;
model->idx = idx;
if(model->idx > 2) model->list_offset = idx - 2;
return true;
});
return preset;
}
void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output) {
furi_assert(subghz_receiver);
uint32_t frequency;
uint32_t preset;
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
frequency = subghz_history_get_frequency(model->history, model->idx);
preset = (uint32_t)subghz_history_get_preset(model->history, model->idx);
return false;
});
string_cat_printf(
output,
"Frequency: %d\n"
"Preset: %d\n",
(int)frequency,
(int)preset);
subghz_receiver_update_offset(subghz_receiver);
}

View File

@ -1,21 +1,11 @@
#pragma once
#include <gui/view.h>
#include <lib/subghz/protocols/subghz_protocol_common.h>
#include <lib/subghz/protocols/subghz_protocol.h>
#include <lib/subghz/subghz_worker.h>
#include "../subghz_history.h"
typedef enum {
SubghzReceverEventOK,
SubghzReceverEventConfig,
SubghzReceverEventMain,
SubghzReceverEventSave,
SubghzReceverEventBack,
SubghzReceverEventMore,
SubghzReceverEventSendStart,
SubghzReceverEventSendStop,
SubghzReceverEventSendHistoryFull,
} SubghzReceverEvent;
typedef struct SubghzReceiver SubghzReceiver;
@ -33,17 +23,19 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver);
View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver);
void subghz_receiver_set_protocol(
void subghz_receiver_add_data_statusbar(
SubghzReceiver* subghz_receiver,
SubGhzProtocolCommon* protocol_result,
SubGhzProtocol* protocol);
const char* frequency_str,
const char* preset_str,
const char* history_stat_str);
SubGhzProtocolCommon* subghz_receiver_get_protocol(SubghzReceiver* subghz_receiver);
void subghz_receiver_add_item_to_menu(
SubghzReceiver* subghz_receiver,
const char* name,
uint8_t type);
void subghz_receiver_set_worker(SubghzReceiver* subghz_receiver, SubGhzWorker* worker);
uint16_t subghz_receiver_get_idx_menu(SubghzReceiver* subghz_receiver);
uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver);
void subghz_receiver_set_idx_menu(SubghzReceiver* subghz_receiver, uint16_t idx);
FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver);
void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output);
void subghz_receiver_exit(void* context);

View File

@ -1,13 +1,8 @@
#include "subghz_transmitter.h"
#include "../subghz_i.h"
#include <math.h>
#include <furi.h>
#include <furi-hal.h>
#include <input/input.h>
#include <gui/elements.h>
#include <notification/notification-messages.h>
#include <lib/subghz/protocols/subghz_protocol_keeloq.h>
struct SubghzTransmitter {
View* view;
@ -16,11 +11,10 @@ struct SubghzTransmitter {
};
typedef struct {
string_t text;
uint16_t scene;
uint32_t real_frequency;
FuriHalSubGhzPreset preset;
SubGhzProtocolCommon* protocol;
string_t frequency_str;
string_t preset_str;
string_t key_str;
uint8_t show_button;
} SubghzTransmitterModel;
void subghz_transmitter_set_callback(
@ -33,24 +27,19 @@ void subghz_transmitter_set_callback(
subghz_transmitter->context = context;
}
void subghz_transmitter_set_protocol(
void subghz_transmitter_add_data_to_show(
SubghzTransmitter* subghz_transmitter,
SubGhzProtocolCommon* protocol) {
const char* key_str,
const char* frequency_str,
const char* preset_str,
uint8_t show_button) {
furi_assert(subghz_transmitter);
with_view_model(
subghz_transmitter->view, (SubghzTransmitterModel * model) {
model->protocol = protocol;
return true;
});
}
void subghz_transmitter_set_frequency_preset(
SubghzTransmitter* subghz_transmitter,
uint32_t frequency,
FuriHalSubGhzPreset preset) {
with_view_model(
subghz_transmitter->view, (SubghzTransmitterModel * model) {
model->real_frequency = frequency;
model->preset = preset;
string_set(model->key_str, key_str);
string_set(model->frequency_str, frequency_str);
string_set(model->preset_str, preset_str);
model->show_button = show_button;
return true;
});
}
@ -87,26 +76,13 @@ static void subghz_transmitter_button_right(Canvas* canvas, const char* str) {
}
void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) {
char buffer[64];
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text));
snprintf(
buffer,
sizeof(buffer),
"%03ld.%03ld",
model->real_frequency / 1000000 % 1000,
model->real_frequency / 1000 % 1000);
canvas_draw_str(canvas, 90, 8, buffer);
if(model->protocol && model->protocol->get_upload_protocol) {
if((!strcmp(model->protocol->name, "KeeLoq")) &&
(!strcmp(subghz_protocol_keeloq_get_manufacture_name(model->protocol), "Unknown"))) {
return;
}
subghz_transmitter_button_right(canvas, "Send");
}
elements_multiline_text(canvas, 0, 8, string_get_cstr(model->key_str));
canvas_draw_str(canvas, 78, 8, string_get_cstr(model->frequency_str));
canvas_draw_str(canvas, 113, 8, string_get_cstr(model->preset_str));
if(model->show_button) subghz_transmitter_button_right(canvas, "Send");
}
bool subghz_transmitter_input(InputEvent* event, void* context) {
@ -114,26 +90,25 @@ bool subghz_transmitter_input(InputEvent* event, void* context) {
SubghzTransmitter* subghz_transmitter = context;
bool can_be_sent = false;
if(event->key == InputKeyBack) {
if(event->key == InputKeyBack && event->type == InputTypeShort) {
with_view_model(
subghz_transmitter->view, (SubghzTransmitterModel * model) {
string_clean(model->frequency_str);
string_clean(model->preset_str);
string_clean(model->key_str);
model->show_button = 0;
return false;
});
return false;
}
with_view_model(
subghz_transmitter->view, (SubghzTransmitterModel * model) {
if(model->protocol && model->protocol->get_upload_protocol) {
if((!strcmp(model->protocol->name, "KeeLoq")) &&
(!strcmp(
subghz_protocol_keeloq_get_manufacture_name(model->protocol), "Unknown"))) {
return false;
}
if(model->show_button) {
can_be_sent = true;
}
//can_be_sent = (model->protocol && model->protocol->get_upload_protocol);
string_clean(model->text);
model->protocol->to_string(model->protocol, model->text);
return true;
});
//if(event->type != InputTypeShort) return false;
if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context);
@ -146,37 +121,14 @@ bool subghz_transmitter_input(InputEvent* event, void* context) {
return true;
}
void subghz_transmitter_text_callback(string_t text, void* context) {
furi_assert(context);
SubghzTransmitter* subghz_transmitter = context;
with_view_model(
subghz_transmitter->view, (SubghzTransmitterModel * model) {
string_set(model->text, text);
model->scene = 0;
return true;
});
}
void subghz_transmitter_enter(void* context) {
furi_assert(context);
SubghzTransmitter* subghz_transmitter = context;
with_view_model(
subghz_transmitter->view, (SubghzTransmitterModel * model) {
string_clean(model->text);
model->protocol->to_string(model->protocol, model->text);
return true;
});
// SubghzTransmitter* subghz_transmitter = context;
}
void subghz_transmitter_exit(void* context) {
furi_assert(context);
SubghzTransmitter* subghz_transmitter = context;
with_view_model(
subghz_transmitter->view, (SubghzTransmitterModel * model) {
string_clean(model->text);
return true;
});
// SubghzTransmitter* subghz_transmitter = context;
}
SubghzTransmitter* subghz_transmitter_alloc() {
@ -194,7 +146,9 @@ SubghzTransmitter* subghz_transmitter_alloc() {
with_view_model(
subghz_transmitter->view, (SubghzTransmitterModel * model) {
string_init(model->text);
string_init(model->frequency_str);
string_init(model->preset_str);
string_init(model->key_str);
return true;
});
return subghz_transmitter;
@ -205,7 +159,9 @@ void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter) {
with_view_model(
subghz_transmitter->view, (SubghzTransmitterModel * model) {
string_clear(model->text);
string_clear(model->frequency_str);
string_clear(model->preset_str);
string_clear(model->key_str);
return true;
});
view_free(subghz_transmitter->view);

View File

@ -1,7 +1,6 @@
#pragma once
#include <gui/view.h>
#include <lib/subghz/protocols/subghz_protocol_common.h>
typedef enum {
SubghzTransmitterEventSendStart,
@ -25,10 +24,9 @@ void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter);
View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter);
void subghz_transmitter_set_protocol(
void subghz_transmitter_add_data_to_show(
SubghzTransmitter* subghz_transmitter,
SubGhzProtocolCommon* protocol);
void subghz_transmitter_set_frequency_preset(
SubghzTransmitter* subghz_transmitter,
uint32_t frequency,
FuriHalSubGhzPreset preset);
const char* key_str,
const char* frequency_str,
const char* preset_str,
uint8_t show_button);

View File

@ -10,6 +10,7 @@
#include "subghz_protocol_faac_slh.h"
#include "subghz_protocol_nero_sketch.h"
#include "subghz_protocol_star_line.h"
#include "subghz_protocol_nero_radio.h"
#include "../subghz_keystore.h"
@ -27,6 +28,7 @@ typedef enum {
SubGhzProtocolTypeFaacSLH,
SubGhzProtocolTypeNeroSketch,
SubGhzProtocolTypeStarLine,
SubGhzProtocolTypeNeroRadio,
SubGhzProtocolTypeMax,
} SubGhzProtocolType;
@ -88,6 +90,8 @@ SubGhzProtocol* subghz_protocol_alloc() {
(SubGhzProtocolCommon*)subghz_protocol_nero_sketch_alloc();
instance->protocols[SubGhzProtocolTypeStarLine] =
(SubGhzProtocolCommon*)subghz_protocol_star_line_alloc(instance->keystore);
instance->protocols[SubGhzProtocolTypeNeroRadio] =
(SubGhzProtocolCommon*)subghz_protocol_nero_radio_alloc();
return instance;
}
@ -113,6 +117,8 @@ void subghz_protocol_free(SubGhzProtocol* instance) {
(SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]);
subghz_protocol_star_line_free(
(SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]);
subghz_protocol_nero_radio_free(
(SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio]);
subghz_keystore_free(instance->keystore);
@ -163,7 +169,6 @@ void subghz_protocol_enable_dump(
}
void subghz_protocol_load_nice_flor_s_file(SubGhzProtocol* instance, const char* file_name) {
// subghz_protocol_nice_flor_s_name_file(instance->nice_flor_s, file_name);
subghz_protocol_nice_flor_s_name_file(
(SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS], file_name);
}
@ -191,6 +196,8 @@ void subghz_protocol_reset(SubGhzProtocol* instance) {
(SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]);
subghz_protocol_star_line_reset(
(SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]);
subghz_protocol_nero_radio_reset(
(SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio]);
}
void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t duration) {
@ -220,4 +227,8 @@ void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t durati
duration);
subghz_protocol_star_line_parse(
(SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine], level, duration);
subghz_protocol_nero_radio_parse(
(SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio],
level,
duration);
}

View File

@ -18,7 +18,7 @@ void subghz_protocol_gate_tx_free(SubGhzProtocolGateTX* instance);
/** Get upload protocol
*
* @param instance - SubGhzProtocolCame instance
* @param instance - SubGhzProtocolGateTX instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/

View File

@ -398,9 +398,9 @@ void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t outp
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%lX\r\n"
"Fix:0x%08lX Cnt:%04X\r\n"
"Hop:0x%08lX Btn:%02lX\r\n"
"Key:%08lX%08lX\r\n"
"Fix:0x%08lX Cnt:%04X\r\n"
"Hop:0x%08lX Btn:%02lX\r\n"
"MF:%s\r\n"
"Sn:0x%07lX \r\n",
instance->common.name,

View File

@ -49,7 +49,7 @@ uint64_t subghz_protocol_keeloq_gen_key(void* context);
/** Get upload protocol
*
* @param instance - SubGhzProtocolCame instance
* @param instance - SubGhzProtocolKeeloq instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/

View File

@ -0,0 +1,280 @@
#include "subghz_protocol_nero_radio.h"
struct SubGhzProtocolNeroRadio {
SubGhzProtocolCommon common;
};
SubGhzProtocolNeroRadio* subghz_protocol_nero_radio_alloc(void) {
SubGhzProtocolNeroRadio* instance = furi_alloc(sizeof(SubGhzProtocolNeroRadio));
instance->common.name = "Nero Radio";
instance->common.code_min_count_bit_for_found = 55;
instance->common.te_short = 200;
instance->common.te_long = 400;
instance->common.te_delta = 80;
instance->common.type_protocol = TYPE_PROTOCOL_STATIC;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nero_radio_to_str;
instance->common.to_save_string =
(SubGhzProtocolCommonGetStrSave)subghz_protocol_nero_radio_to_save_str;
instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_nero_radio_to_load_protocol_from_file;
instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nero_radio_to_load_protocol;
instance->common.get_upload_protocol =
(SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_nero_radio_send_key;
return instance;
}
void subghz_protocol_nero_radio_free(SubGhzProtocolNeroRadio* instance) {
furi_assert(instance);
free(instance);
}
bool subghz_protocol_nero_radio_send_key(
SubGhzProtocolNeroRadio* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance);
furi_assert(encoder);
size_t index = 0;
encoder->size_upload = 2 + 47 * 2 + 2 + (instance->common.code_last_count_bit * 2);
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send header
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short * 37);
for(uint8_t i = 0; i < 47; i++) {
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
}
//Send start bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short * 4);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
//Send key data
for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_long);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short);
} else {
//send bit 0
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_long);
}
}
return true;
}
void subghz_protocol_nero_radio_reset(SubGhzProtocolNeroRadio* instance) {
instance->common.parser_step = 0;
}
/** Analysis of received data
*
* @param instance SubGhzProtocolNeroRadio instance
*/
// void subghz_protocol_nero_radio_check_remote_controller(SubGhzProtocolNeroRadio* instance) {
// //пока не понятно с серийником, но код статический
// // uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_found, instance->common.code_count_bit);
// // uint32_t code_fix = code_found_reverse & 0xFFFFFFFF;
// // //uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFF;
// // instance->common.serial = code_fix & 0xFFFFFFF;
// // instance->common.btn = (code_fix >> 28) & 0x0F;
// //if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
// }
void subghz_protocol_nero_radio_parse(
SubGhzProtocolNeroRadio* instance,
bool level,
uint32_t duration) {
switch(instance->common.parser_step) {
case 0:
if((level) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
instance->common.parser_step = 1;
instance->common.te_last = duration;
instance->common.header_count = 0;
} else {
instance->common.parser_step = 0;
}
break;
case 1:
if(level) {
if((DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) ||
(DURATION_DIFF(duration, instance->common.te_short * 4) <
instance->common.te_delta)) {
instance->common.te_last = duration;
} else {
instance->common.parser_step = 0;
}
} else if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
if(DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) {
// Found header
instance->common.header_count++;
break;
} else if(
DURATION_DIFF(instance->common.te_last, instance->common.te_short * 4) <
instance->common.te_delta) {
// Found start bit
if(instance->common.header_count > 40) {
instance->common.parser_step = 2;
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
} else {
instance->common.parser_step = 0;
}
} else {
instance->common.parser_step = 0;
}
} else {
instance->common.parser_step = 0;
}
break;
case 2:
if(level) {
instance->common.te_last = duration;
instance->common.parser_step = 3;
} else {
instance->common.parser_step = 0;
}
break;
case 3:
if(!level) {
if(duration >= (instance->common.te_short * 10 + instance->common.te_delta * 2)) {
//Found stop bit
instance->common.parser_step = 0;
if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) {
instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit;
if(instance->common.callback)
instance->common.callback(
(SubGhzProtocolCommon*)instance, instance->common.context);
}
instance->common.code_found = 0;
instance->common.code_count_bit = 0;
instance->common.parser_step = 0;
break;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 0);
instance->common.parser_step = 2;
} else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = 2;
} else {
instance->common.parser_step = 0;
}
} else {
instance->common.parser_step = 0;
}
break;
}
}
void subghz_protocol_nero_radio_to_str(SubGhzProtocolNeroRadio* instance, string_t output) {
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Yek:0x%lX%08lX\r\n",
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo,
code_found_reverse_hi,
code_found_reverse_lo);
}
void subghz_protocol_nero_radio_to_save_str(SubGhzProtocolNeroRadio* instance, string_t output) {
uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
string_printf(
output,
"Protocol: %s\n"
"Bit: %d\n"
"Key: %08lX%08lX\n",
instance->common.name,
instance->common.code_last_count_bit,
code_found_hi,
code_found_lo);
}
bool subghz_protocol_nero_radio_to_load_protocol_from_file(
FileWorker* file_worker,
SubGhzProtocolNeroRadio* instance) {
bool loaded = false;
string_t temp_str;
string_init(temp_str);
int res = 0;
int data = 0;
do {
// Read and parse bit data from 2nd line
if(!file_worker_read_until(file_worker, temp_str, '\n')) {
break;
}
res = sscanf(string_get_cstr(temp_str), "Bit: %d\n", &data);
if(res != 1) {
break;
}
instance->common.code_last_count_bit = (uint8_t)data;
// Read and parse key data from 3nd line
if(!file_worker_read_until(file_worker, temp_str, '\n')) {
break;
}
// strlen("Key: ") = 5
string_right(temp_str, 5);
uint8_t buf_key[8] = {0};
if(!subghz_protocol_common_read_hex(temp_str, buf_key, 8)) {
break;
}
for(uint8_t i = 0; i < 8; i++) {
instance->common.code_last_found = instance->common.code_last_found << 8 | buf_key[i];
}
loaded = true;
} while(0);
string_clear(temp_str);
return loaded;
}
void subghz_decoder_nero_radio_to_load_protocol(SubGhzProtocolNeroRadio* instance, void* context) {
furi_assert(context);
furi_assert(instance);
SubGhzProtocolCommonLoad* data = context;
instance->common.code_last_found = data->code_found;
instance->common.code_last_count_bit = data->code_count_bit;
}

View File

@ -0,0 +1,72 @@
#pragma once
#include "subghz_protocol_common.h"
typedef struct SubGhzProtocolNeroRadio SubGhzProtocolNeroRadio;
/** Allocate SubGhzProtocolNeroRadio
*
* @return SubGhzProtocolNeroRadio*
*/
SubGhzProtocolNeroRadio* subghz_protocol_nero_radio_alloc();
/** Free SubGhzProtocolNeroRadio
*
* @param instance
*/
void subghz_protocol_nero_radio_free(SubGhzProtocolNeroRadio* instance);
/** Get upload protocol
*
* @param instance - SubGhzProtocolNeroRadio instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/
bool subghz_protocol_nero_radio_send_key(SubGhzProtocolNeroRadio* instance, SubGhzProtocolCommonEncoder* encoder);
/** Reset internal state
* @param instance - SubGhzProtocolNeroRadio instance
*/
void subghz_protocol_nero_radio_reset(SubGhzProtocolNeroRadio* instance);
/** Analysis of received data
*
* @param instance SubGhzProtocolNeroRadio instance
*/
void subghz_protocol_nero_radio_check_remote_controller(SubGhzProtocolNeroRadio* instance);
/** Parse accepted duration
*
* @param instance - SubGhzProtocolNeroRadio instance
* @param data - LevelDuration level_duration
*/
void subghz_protocol_nero_radio_parse(SubGhzProtocolNeroRadio* instance, bool level, uint32_t duration);
/** Outputting information from the parser
*
* @param instance - SubGhzProtocolNeroRadio* instance
* @param output - output string
*/
void subghz_protocol_nero_radio_to_str(SubGhzProtocolNeroRadio* instance, string_t output);
/** Get a string to save the protocol
*
* @param instance - SubGhzProtocolNeroRadio instance
* @param output - the resulting string
*/
void subghz_protocol_nero_radio_to_save_str(SubGhzProtocolNeroRadio* instance, string_t output);
/** Loading protocol from file
*
* @param file_worker - FileWorker file_worker
* @param instance - SubGhzProtocolNeroRadio instance
* @return bool
*/
bool subghz_protocol_nero_radio_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNeroRadio* instance);
/** Loading protocol from bin data
*
* @param instance - SubGhzProtocolNeroRadio instance
* @param context - SubGhzProtocolCommonLoad context
*/
void subghz_decoder_nero_radio_to_load_protocol(SubGhzProtocolNeroRadio* instance, void* context);

View File

@ -18,7 +18,7 @@ void subghz_protocol_nero_sketch_free(SubGhzProtocolNeroSketch* instance);
/** Get upload protocol
*
* @param instance - SubGhzProtocolCame instance
* @param instance - SubGhzProtocolNeroSketch instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/

View File

@ -18,7 +18,7 @@ void subghz_protocol_nice_flo_free(SubGhzProtocolNiceFlo* instance);
/** Get upload protocol
*
* @param instance - SubGhzProtocolCame instance
* @param instance - SubGhzProtocolNiceFlo instance
* @param encoder - SubGhzProtocolCommonEncoder encoder
* @return bool
*/

View File

@ -172,7 +172,7 @@ void subghz_decoder_princeton_parse(
if(!level) {
if(duration >= (instance->common.te_short * 10 + instance->common.te_delta)) {
instance->common.parser_step = 1;
if(instance->common.code_count_bit >=
if(instance->common.code_count_bit ==
instance->common.code_min_count_bit_for_found) {
if(instance->common.code_last_found == instance->common.code_found) {
//instance->te = (instance->te+instance->common.te_last)/2; //Option 1 TE averaging

View File

@ -282,9 +282,9 @@ void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%lX\r\n"
"Fix:0x%08lX Cnt:%04X\r\n"
"Hop:0x%08lX Btn:%02lX\r\n"
"Key:%08lX%08lX\r\n"
"Fix:0x%08lX Cnt:%04X\r\n"
"Hop:0x%08lX Btn:%02lX\r\n"
"MF:%s\r\n"
"Sn:0x%07lX \r\n",
instance->common.name,