[FL-1756, FL-1769, FL-1776, FL-1759] Gui: input events complementary V3, refactoring. SubGhz: read/emulate fixes. Cleanup. (#684)
* Gui: move rotation logic to ViewPort, replace delayed View switch in ViewDispatcher with event filtering and redirection to previous view. * SubGhz: add function description * Gui, Input: add event id to input events. * SubGhz: fix "crashing on ?" * SubGhz: add icon scanning * SubGhz: updated interface read scene, updated interface config scene * Assets: update subghz assets * SubGhz: replaced the picture in the read scene, changed the paths to additional files * SubGhz: fix deadlock in timer callback * SubGhz: fix icon read scene * SubGhz: fix icon read scene * SubGhz: fix duble text transmitter scene * SubGhz: correct spelling. Gui: bigger queue for ViewDispatcher. * SubGhz: fix creation and transmission of dynamic code without the presence of a manufactory key * SubGhz: fix keelog, setting a name in the absence of a manufactory key * SubGhz: fix load bad keelog key * Format sources * Furi: remove garbage from core. GpioTester: fix memory leak and cleanup * Accessor: remove obsolete notification code * MusicPlayer: remove input event injection * Input: rename id to sequence Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
@@ -35,7 +35,6 @@ AccessorApp::AccessorApp()
|
||||
: onewire_master{&ibutton_gpio} {
|
||||
furi_hal_power_insomnia_enter();
|
||||
notification = static_cast<NotificationApp*>(furi_record_open("notification"));
|
||||
notify_init();
|
||||
furi_hal_power_enable_otg();
|
||||
}
|
||||
|
||||
@@ -104,17 +103,6 @@ AccessorApp::Scene AccessorApp::get_previous_scene() {
|
||||
|
||||
/***************************** NOTIFY *******************************/
|
||||
|
||||
void AccessorApp::notify_init() {
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
|
||||
GPIO_InitStruct.Pin = PB3_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
|
||||
HAL_GPIO_Init(PB3_GPIO_Port, &GPIO_InitStruct);
|
||||
}
|
||||
|
||||
void AccessorApp::notify_green_blink() {
|
||||
notification_message(notification, &sequence_blink_green_10);
|
||||
}
|
||||
|
||||
@@ -29,9 +29,7 @@ public:
|
||||
bool switch_to_previous_scene(uint8_t count = 1);
|
||||
Scene get_previous_scene();
|
||||
|
||||
void notify_init();
|
||||
void notify_green_blink();
|
||||
|
||||
void notify_success();
|
||||
|
||||
char* get_text_store();
|
||||
|
||||
@@ -2,143 +2,134 @@
|
||||
#include <furi-hal.h>
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <notification/notification-messages.h>
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
GpioPin pin;
|
||||
const GpioPin* pin;
|
||||
} GpioItem;
|
||||
|
||||
const GpioItem GPIO_PINS[] = {
|
||||
{"1.2: PA7", {GPIOA, GPIO_PIN_7}},
|
||||
{"1.3: PA6", {GPIOA, GPIO_PIN_6}},
|
||||
{"1.4: PA4", {GPIOA, GPIO_PIN_4}},
|
||||
{"1.5: PB3", {GPIOB, GPIO_PIN_3}},
|
||||
{"1.6: PB2", {GPIOB, GPIO_PIN_2}},
|
||||
{"1.7: PC3", {GPIOC, GPIO_PIN_3}},
|
||||
|
||||
{"2.7: PC1", {GPIOC, GPIO_PIN_1}},
|
||||
{"2.8: PC0", {GPIOC, GPIO_PIN_0}},
|
||||
static const GpioItem GPIO_PINS[] = {
|
||||
{"1.2: PA7", &gpio_ext_pa7},
|
||||
{"1.3: PA6", &gpio_ext_pa6},
|
||||
{"1.4: PA4", &gpio_ext_pa4},
|
||||
{"1.5: PB3", &gpio_ext_pb3},
|
||||
{"1.6: PB2", &gpio_ext_pb2},
|
||||
{"1.7: PC3", &gpio_ext_pc3},
|
||||
{"2.7: PC1", &gpio_ext_pc1},
|
||||
{"2.8: PC0", &gpio_ext_pc0},
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
EventTypeTick,
|
||||
EventTypeKey,
|
||||
} EventType;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
InputEvent input;
|
||||
} value;
|
||||
EventType type;
|
||||
} AppEvent;
|
||||
static const size_t GPIO_PINS_COUNT = sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]);
|
||||
|
||||
typedef struct {
|
||||
osMessageQueueId_t input_queue;
|
||||
uint8_t gpio_index;
|
||||
} State;
|
||||
ViewPort* view_port;
|
||||
Gui* gui;
|
||||
NotificationApp* notification;
|
||||
} GpioTest;
|
||||
|
||||
static void render_callback(Canvas* canvas, void* ctx) {
|
||||
State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25);
|
||||
static void gpio_test_render_callback(Canvas* canvas, void* ctx) {
|
||||
GpioTest* gpio_test = ctx;
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 2, 10, "GPIO Control");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 25, GPIO_PINS[state->gpio_index].name);
|
||||
|
||||
release_mutex((ValueMutex*)ctx, state);
|
||||
canvas_draw_str(canvas, 2, 25, GPIO_PINS[gpio_test->gpio_index].name);
|
||||
}
|
||||
|
||||
static void input_callback(InputEvent* input_event, void* ctx) {
|
||||
osMessageQueueId_t event_queue = ctx;
|
||||
static void gpio_test_input_callback(InputEvent* input_event, void* ctx) {
|
||||
GpioTest* gpio_test = ctx;
|
||||
|
||||
AppEvent event;
|
||||
event.type = EventTypeKey;
|
||||
event.value.input = *input_event;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
osMessageQueuePut(gpio_test->input_queue, input_event, 0, 0);
|
||||
}
|
||||
|
||||
static void gpio_test_configure_pins(GpioMode mode) {
|
||||
for(size_t i = 0; i < GPIO_PINS_COUNT; i++) {
|
||||
hal_gpio_write(GPIO_PINS[i].pin, false);
|
||||
hal_gpio_init(GPIO_PINS[i].pin, mode, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
}
|
||||
|
||||
GpioTest* gpio_test_alloc() {
|
||||
GpioTest* instance = furi_alloc(sizeof(GpioTest));
|
||||
|
||||
gpio_test_configure_pins(GpioModeOutputPushPull);
|
||||
|
||||
instance->input_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL);
|
||||
furi_check(instance->input_queue);
|
||||
|
||||
instance->view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(instance->view_port, gpio_test_render_callback, instance);
|
||||
view_port_input_callback_set(instance->view_port, gpio_test_input_callback, instance);
|
||||
|
||||
instance->gui = furi_record_open("gui");
|
||||
gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen);
|
||||
|
||||
instance->notification = furi_record_open("notification");
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void gpio_test_free(GpioTest* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
furi_record_close("notification");
|
||||
|
||||
view_port_enabled_set(instance->view_port, false);
|
||||
gui_remove_view_port(instance->gui, instance->view_port);
|
||||
furi_record_close("gui");
|
||||
|
||||
view_port_free(instance->view_port);
|
||||
|
||||
osMessageQueueDelete(instance->input_queue);
|
||||
|
||||
gpio_test_configure_pins(GpioModeAnalog);
|
||||
|
||||
free(instance);
|
||||
}
|
||||
|
||||
int32_t gpio_test_app(void* p) {
|
||||
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL);
|
||||
furi_check(event_queue);
|
||||
GpioTest* gpio_test = gpio_test_alloc();
|
||||
|
||||
State _state;
|
||||
_state.gpio_index = 0;
|
||||
InputEvent event;
|
||||
while(osMessageQueueGet(gpio_test->input_queue, &event, NULL, osWaitForever) == osOK) {
|
||||
if(event.type == InputTypeShort) {
|
||||
if(event.key == InputKeyBack) {
|
||||
notification_message(gpio_test->notification, &sequence_reset_green);
|
||||
break;
|
||||
}
|
||||
|
||||
ValueMutex state_mutex;
|
||||
if(!init_mutex(&state_mutex, &_state, sizeof(State))) {
|
||||
printf("[gpio-tester] cannot create mutex\r\n");
|
||||
return 255;
|
||||
}
|
||||
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
|
||||
view_port_draw_callback_set(view_port, render_callback, &state_mutex);
|
||||
view_port_input_callback_set(view_port, input_callback, event_queue);
|
||||
|
||||
// Open GUI and register view_port
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
|
||||
// configure pin
|
||||
for(uint8_t i = 0; i < sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]); i++) {
|
||||
hal_gpio_init(
|
||||
(GpioPin*)&GPIO_PINS[i].pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
AppEvent event;
|
||||
while(1) {
|
||||
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, osWaitForever);
|
||||
State* state = (State*)acquire_mutex_block(&state_mutex);
|
||||
|
||||
if(event_status == osOK) {
|
||||
if(event.type == EventTypeKey) {
|
||||
if(event.value.input.type == InputTypeShort &&
|
||||
event.value.input.key == InputKeyBack) {
|
||||
printf("[gpio-tester] bye!\r\n");
|
||||
notification_message(notification, &sequence_reset_green);
|
||||
furi_record_close("notification");
|
||||
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
|
||||
return 0;
|
||||
if(event.key == InputKeyRight) {
|
||||
if(gpio_test->gpio_index < (GPIO_PINS_COUNT - 1)) {
|
||||
gpio_test->gpio_index++;
|
||||
}
|
||||
}
|
||||
|
||||
if(event.value.input.type == InputTypeShort &&
|
||||
event.value.input.key == InputKeyRight) {
|
||||
if(state->gpio_index < (sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]) - 1)) {
|
||||
state->gpio_index++;
|
||||
}
|
||||
if(event.key == InputKeyLeft) {
|
||||
if(gpio_test->gpio_index > 0) {
|
||||
gpio_test->gpio_index--;
|
||||
}
|
||||
|
||||
if(event.value.input.type == InputTypeShort &&
|
||||
event.value.input.key == InputKeyLeft) {
|
||||
if(state->gpio_index > 0) {
|
||||
state->gpio_index--;
|
||||
}
|
||||
}
|
||||
|
||||
if(event.value.input.key == InputKeyOk) {
|
||||
if(event.value.input.type == InputTypePress) {
|
||||
hal_gpio_write((GpioPin*)&GPIO_PINS[state->gpio_index].pin, true);
|
||||
notification_message(notification, &sequence_set_green_255);
|
||||
} else if(event.value.input.type == InputTypeRelease) {
|
||||
hal_gpio_write((GpioPin*)&GPIO_PINS[state->gpio_index].pin, false);
|
||||
notification_message(notification, &sequence_reset_green);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(event.key == InputKeyOk) {
|
||||
if(event.type == InputTypePress) {
|
||||
hal_gpio_write(GPIO_PINS[gpio_test->gpio_index].pin, true);
|
||||
notification_message(gpio_test->notification, &sequence_set_green_255);
|
||||
} else if(event.type == InputTypeRelease) {
|
||||
hal_gpio_write(GPIO_PINS[gpio_test->gpio_index].pin, false);
|
||||
notification_message(gpio_test->notification, &sequence_reset_green);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
release_mutex(&state_mutex, state);
|
||||
view_port_update(view_port);
|
||||
view_port_update(gpio_test->view_port);
|
||||
}
|
||||
|
||||
gpio_test_free(gpio_test);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -309,12 +309,15 @@ void canvas_set_orientation(Canvas* canvas, CanvasOrientation orientation) {
|
||||
furi_assert(canvas);
|
||||
if(canvas->orientation != orientation) {
|
||||
canvas->orientation = orientation;
|
||||
if(canvas->orientation == CanvasOrientationHorizontal)
|
||||
if(canvas->orientation == CanvasOrientationHorizontal) {
|
||||
FURI_SWAP(canvas->width, canvas->height);
|
||||
u8g2_SetDisplayRotation(&canvas->fb, U8G2_R0);
|
||||
else if(canvas->orientation == CanvasOrientationVertical)
|
||||
} else if(canvas->orientation == CanvasOrientationVertical) {
|
||||
FURI_SWAP(canvas->width, canvas->height);
|
||||
u8g2_SetDisplayRotation(&canvas->fb, U8G2_R3);
|
||||
else
|
||||
} else {
|
||||
furi_assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+30
-53
@@ -1,40 +1,5 @@
|
||||
#include "gui_i.h"
|
||||
|
||||
static void gui_rotate_buttons(InputEvent* event) {
|
||||
switch(event->key) {
|
||||
case InputKeyUp:
|
||||
event->key = InputKeyRight;
|
||||
break;
|
||||
case InputKeyDown:
|
||||
event->key = InputKeyLeft;
|
||||
break;
|
||||
case InputKeyRight:
|
||||
event->key = InputKeyDown;
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
event->key = InputKeyUp;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gui_setup_fs_orientation(const ViewPort* view_port, Canvas* canvas) {
|
||||
ViewPortOrientation view_port_orientation = view_port_get_orientation(view_port);
|
||||
CanvasOrientation canvas_orientation = canvas_get_orientation(canvas);
|
||||
if(view_port_orientation == ViewPortOrientationHorizontal) {
|
||||
canvas_frame_set(canvas, 0, 0, GUI_DISPLAY_WIDTH, GUI_DISPLAY_HEIGHT);
|
||||
if(canvas_orientation != CanvasOrientationHorizontal) {
|
||||
canvas_set_orientation(canvas, CanvasOrientationHorizontal);
|
||||
}
|
||||
} else if(view_port_orientation == ViewPortOrientationVertical) {
|
||||
canvas_frame_set(canvas, 0, 0, GUI_DISPLAY_HEIGHT, GUI_DISPLAY_WIDTH);
|
||||
if(canvas_orientation != CanvasOrientationVertical) {
|
||||
canvas_set_orientation(canvas, CanvasOrientationVertical);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) {
|
||||
// Iterating backward
|
||||
ViewPortArray_it_t it;
|
||||
@@ -66,9 +31,10 @@ void gui_input_events_callback(const void* value, void* ctx) {
|
||||
|
||||
// Only Fullscreen supports vertical display for now
|
||||
bool gui_redraw_fs(Gui* gui) {
|
||||
canvas_set_orientation(gui->canvas, CanvasOrientationHorizontal);
|
||||
canvas_frame_set(gui->canvas, 0, 0, GUI_DISPLAY_WIDTH, GUI_DISPLAY_HEIGHT);
|
||||
ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]);
|
||||
if(view_port) {
|
||||
gui_setup_fs_orientation(view_port, gui->canvas);
|
||||
view_port_draw(view_port, gui->canvas);
|
||||
return true;
|
||||
} else {
|
||||
@@ -225,9 +191,10 @@ void gui_input(Gui* gui, InputEvent* input_event) {
|
||||
} else if(!(gui->ongoing_input & key_bit)) {
|
||||
FURI_LOG_W(
|
||||
"Gui",
|
||||
"non-complementary input, discarding key %s type %s",
|
||||
"non-complementary input, discarding key: %s type: %s, sequence: %p",
|
||||
input_get_key_name(input_event->key),
|
||||
input_get_type_name(input_event->type));
|
||||
input_get_type_name(input_event->type),
|
||||
input_event->sequence);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -241,21 +208,27 @@ void gui_input(Gui* gui, InputEvent* input_event) {
|
||||
gui->ongoing_input_view_port = view_port;
|
||||
}
|
||||
|
||||
if(view_port) {
|
||||
if(view_port == gui->ongoing_input_view_port) {
|
||||
if(view_port_get_orientation(view_port) == ViewPortOrientationVertical) {
|
||||
gui_rotate_buttons(input_event);
|
||||
}
|
||||
view_port_input(view_port, input_event);
|
||||
} else {
|
||||
FURI_LOG_W(
|
||||
"Gui",
|
||||
"ViewPort change while key press %x -> %x. Discarding key: %s, type: %s",
|
||||
gui->ongoing_input_view_port,
|
||||
view_port,
|
||||
input_get_key_name(input_event->key),
|
||||
input_get_type_name(input_event->type));
|
||||
}
|
||||
if(view_port && view_port == gui->ongoing_input_view_port) {
|
||||
view_port_input(view_port, input_event);
|
||||
} else if(gui->ongoing_input_view_port && input_event->type == InputTypeRelease) {
|
||||
FURI_LOG_W(
|
||||
"Gui",
|
||||
"ViewPort changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port",
|
||||
gui->ongoing_input_view_port,
|
||||
view_port,
|
||||
input_get_key_name(input_event->key),
|
||||
input_get_type_name(input_event->type),
|
||||
input_event->sequence);
|
||||
view_port_input(gui->ongoing_input_view_port, input_event);
|
||||
} else {
|
||||
FURI_LOG_W(
|
||||
"Gui",
|
||||
"ViewPort changed while key press %p -> %p. Discarding key: %s, type: %s, sequence: %p",
|
||||
gui->ongoing_input_view_port,
|
||||
view_port,
|
||||
input_get_key_name(input_event->key),
|
||||
input_get_type_name(input_event->type),
|
||||
input_event->sequence);
|
||||
}
|
||||
|
||||
gui_unlock(gui);
|
||||
@@ -355,6 +328,10 @@ void gui_remove_view_port(Gui* gui, ViewPort* view_port) {
|
||||
}
|
||||
}
|
||||
|
||||
if(gui->ongoing_input_view_port == view_port) {
|
||||
gui->ongoing_input_view_port = NULL;
|
||||
}
|
||||
|
||||
gui_unlock(gui);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) {
|
||||
void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher) {
|
||||
furi_assert(view_dispatcher);
|
||||
furi_assert(view_dispatcher->queue == NULL);
|
||||
view_dispatcher->queue = osMessageQueueNew(8, sizeof(ViewDispatcherMessage), NULL);
|
||||
view_dispatcher->queue = osMessageQueueNew(16, sizeof(ViewDispatcherMessage), NULL);
|
||||
}
|
||||
|
||||
void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, void* context) {
|
||||
@@ -149,6 +149,10 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_
|
||||
if(view_dispatcher->current_view == view) {
|
||||
view_dispatcher_set_current_view(view_dispatcher, NULL);
|
||||
}
|
||||
// Check if view is recieving input
|
||||
if(view_dispatcher->ongoing_input_view == view) {
|
||||
view_dispatcher->ongoing_input_view = NULL;
|
||||
}
|
||||
// Remove view
|
||||
ViewDict_erase(view_dispatcher->views, view_id);
|
||||
|
||||
@@ -169,12 +173,7 @@ void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t vi
|
||||
} else {
|
||||
View** view_pp = ViewDict_get(view_dispatcher->views, view_id);
|
||||
furi_check(view_pp != NULL);
|
||||
if(view_dispatcher->ongoing_input) {
|
||||
view_dispatcher->delayed_next_view = *view_pp;
|
||||
} else {
|
||||
view_dispatcher->delayed_next_view = NULL;
|
||||
view_dispatcher_set_current_view(view_dispatcher, *view_pp);
|
||||
}
|
||||
view_dispatcher_set_current_view(view_dispatcher, *view_pp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,39 +226,52 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e
|
||||
} else if(!(view_dispatcher->ongoing_input & key_bit)) {
|
||||
FURI_LOG_W(
|
||||
"ViewDispatcher",
|
||||
"non-complementary input, discarding key: %s, type: %s",
|
||||
"non-complementary input, discarding key: %s, type: %s, sequence: %p",
|
||||
input_get_key_name(event->key),
|
||||
input_get_type_name(event->type));
|
||||
input_get_type_name(event->type),
|
||||
event->sequence);
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_consumed = false;
|
||||
if(view_dispatcher->current_view) {
|
||||
is_consumed = view_input(view_dispatcher->current_view, event);
|
||||
}
|
||||
if(!is_consumed && event->type == InputTypeShort) {
|
||||
// TODO remove view navigation handlers
|
||||
uint32_t view_id = VIEW_IGNORE;
|
||||
if(event->key == InputKeyBack) {
|
||||
view_id = view_previous(view_dispatcher->current_view);
|
||||
if((view_id == VIEW_IGNORE) && (view_dispatcher->navigation_event_callback)) {
|
||||
is_consumed =
|
||||
view_dispatcher->navigation_event_callback(view_dispatcher->event_context);
|
||||
if(!is_consumed) {
|
||||
view_dispatcher_stop(view_dispatcher);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!is_consumed) {
|
||||
view_dispatcher_switch_to_view(view_dispatcher, view_id);
|
||||
}
|
||||
// Set ongoing input view if this is event is first press event
|
||||
if(!(view_dispatcher->ongoing_input & ~key_bit) && event->type == InputTypePress) {
|
||||
view_dispatcher->ongoing_input_view = view_dispatcher->current_view;
|
||||
}
|
||||
|
||||
// Delayed view switch
|
||||
if(view_dispatcher->delayed_next_view && !(view_dispatcher->ongoing_input)) {
|
||||
view_dispatcher_set_current_view(view_dispatcher, view_dispatcher->delayed_next_view);
|
||||
view_dispatcher->delayed_next_view = NULL;
|
||||
// Deliver event
|
||||
if(view_dispatcher->ongoing_input_view == view_dispatcher->current_view) {
|
||||
bool is_consumed = false;
|
||||
if(view_dispatcher->current_view) {
|
||||
is_consumed = view_input(view_dispatcher->current_view, event);
|
||||
}
|
||||
if(!is_consumed && event->type == InputTypeShort) {
|
||||
// TODO remove view navigation handlers
|
||||
uint32_t view_id = VIEW_IGNORE;
|
||||
if(event->key == InputKeyBack) {
|
||||
view_id = view_previous(view_dispatcher->current_view);
|
||||
if((view_id == VIEW_IGNORE) && (view_dispatcher->navigation_event_callback)) {
|
||||
is_consumed =
|
||||
view_dispatcher->navigation_event_callback(view_dispatcher->event_context);
|
||||
if(!is_consumed) {
|
||||
view_dispatcher_stop(view_dispatcher);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!is_consumed) {
|
||||
view_dispatcher_switch_to_view(view_dispatcher, view_id);
|
||||
}
|
||||
}
|
||||
} else if(view_dispatcher->ongoing_input_view && event->type == InputTypeRelease) {
|
||||
FURI_LOG_W(
|
||||
"ViewDispatcher",
|
||||
"View changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port",
|
||||
view_dispatcher->ongoing_input_view,
|
||||
view_dispatcher->current_view,
|
||||
input_get_key_name(event->key),
|
||||
input_get_type_name(event->type),
|
||||
event->sequence);
|
||||
view_input(view_dispatcher->ongoing_input_view, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ struct ViewDispatcher {
|
||||
|
||||
View* current_view;
|
||||
|
||||
View* delayed_next_view;
|
||||
View* ongoing_input_view;
|
||||
uint8_t ongoing_input;
|
||||
|
||||
ViewDispatcherCustomEventCallback custom_event_callback;
|
||||
|
||||
@@ -7,6 +7,33 @@
|
||||
|
||||
// TODO add mutex to view_port ops
|
||||
|
||||
static void view_port_rotate_buttons(InputEvent* event) {
|
||||
switch(event->key) {
|
||||
case InputKeyUp:
|
||||
event->key = InputKeyRight;
|
||||
break;
|
||||
case InputKeyDown:
|
||||
event->key = InputKeyLeft;
|
||||
break;
|
||||
case InputKeyRight:
|
||||
event->key = InputKeyDown;
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
event->key = InputKeyUp;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void view_port_setup_canvas_orientation(const ViewPort* view_port, Canvas* canvas) {
|
||||
if(view_port->orientation == ViewPortOrientationHorizontal) {
|
||||
canvas_set_orientation(canvas, CanvasOrientationHorizontal);
|
||||
} else if(view_port->orientation == ViewPortOrientationVertical) {
|
||||
canvas_set_orientation(canvas, CanvasOrientationVertical);
|
||||
}
|
||||
}
|
||||
|
||||
ViewPort* view_port_alloc() {
|
||||
ViewPort* view_port = furi_alloc(sizeof(ViewPort));
|
||||
view_port->orientation = ViewPortOrientationHorizontal;
|
||||
@@ -84,6 +111,7 @@ void view_port_draw(ViewPort* view_port, Canvas* canvas) {
|
||||
furi_check(view_port->gui);
|
||||
|
||||
if(view_port->draw_callback) {
|
||||
view_port_setup_canvas_orientation(view_port, canvas);
|
||||
view_port->draw_callback(canvas, view_port->draw_callback_context);
|
||||
}
|
||||
}
|
||||
@@ -94,6 +122,9 @@ void view_port_input(ViewPort* view_port, InputEvent* event) {
|
||||
furi_check(view_port->gui);
|
||||
|
||||
if(view_port->input_callback) {
|
||||
if(view_port_get_orientation(view_port) == ViewPortOrientationVertical) {
|
||||
view_port_rotate_buttons(event);
|
||||
}
|
||||
view_port->input_callback(event, view_port->input_callback_context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ inline static void input_timer_stop(osTimerId_t timer_id) {
|
||||
void input_press_timer_callback(void* arg) {
|
||||
InputPinState* input_pin = arg;
|
||||
InputEvent event;
|
||||
event.sequence = input_pin->counter;
|
||||
event.key = input_pin->pin->key;
|
||||
input_pin->press_counter++;
|
||||
if(input_pin->press_counter == INPUT_LONG_PRESS_COUNTS) {
|
||||
@@ -158,8 +159,12 @@ int32_t input_srv() {
|
||||
|
||||
// Short / Long / Repeat timer routine
|
||||
if(state) {
|
||||
input->counter++;
|
||||
input->pin_states[i].counter = input->counter;
|
||||
event.sequence = input->pin_states[i].counter;
|
||||
input_timer_start(input->pin_states[i].press_timer, INPUT_PRESS_TICKS);
|
||||
} else {
|
||||
event.sequence = input->pin_states[i].counter;
|
||||
input_timer_stop(input->pin_states[i].press_timer);
|
||||
if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) {
|
||||
event.type = InputTypeShort;
|
||||
|
||||
@@ -15,6 +15,7 @@ typedef enum {
|
||||
|
||||
/* Input Event, dispatches with PubSub */
|
||||
typedef struct {
|
||||
uint32_t sequence;
|
||||
InputKey key;
|
||||
InputType type;
|
||||
} InputEvent;
|
||||
|
||||
@@ -24,6 +24,7 @@ typedef struct {
|
||||
volatile uint8_t debounce;
|
||||
volatile osTimerId_t press_timer;
|
||||
volatile uint8_t press_counter;
|
||||
volatile uint32_t counter;
|
||||
} InputPinState;
|
||||
|
||||
/* Input state */
|
||||
@@ -32,6 +33,7 @@ typedef struct {
|
||||
PubSub event_pubsub;
|
||||
InputPinState* pin_states;
|
||||
Cli* cli;
|
||||
volatile uint32_t counter;
|
||||
} Input;
|
||||
|
||||
/* Input press timer callback */
|
||||
|
||||
@@ -383,11 +383,6 @@ int32_t music_player_app(void* p) {
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// open input record
|
||||
PubSub* input_events_record = furi_record_open("input_events");
|
||||
// prepare "do nothing" event
|
||||
InputEvent input_event = {InputKeyRight, true};
|
||||
|
||||
// start player thread
|
||||
// TODO change to fuirac_start
|
||||
osThreadAttr_t player_attr = {.name = "music_player_thread", .stack_size = 512};
|
||||
@@ -410,14 +405,8 @@ int32_t music_player_app(void* p) {
|
||||
// press events
|
||||
if(event.value.input.type == InputTypeShort &&
|
||||
event.value.input.key == InputKeyBack) {
|
||||
osThreadTerminate(player);
|
||||
hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH);
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
osMessageQueueDelete(event_queue);
|
||||
|
||||
return 0;
|
||||
release_mutex(&state_mutex, state);
|
||||
break;
|
||||
}
|
||||
|
||||
if(event.value.input.type == InputTypePress &&
|
||||
@@ -442,9 +431,6 @@ int32_t music_player_app(void* p) {
|
||||
}
|
||||
|
||||
} else if(event.type == EventTypeNote) {
|
||||
// send "do nothing" event to prevent display backlight off
|
||||
notify_pubsub(input_events_record, &input_event);
|
||||
|
||||
state->note_record = event.value.note_record;
|
||||
|
||||
for(size_t i = note_stack_size - 1; i > 0; i--) {
|
||||
@@ -460,5 +446,14 @@ int32_t music_player_app(void* p) {
|
||||
release_mutex(&state_mutex, state);
|
||||
}
|
||||
|
||||
osThreadTerminate(player);
|
||||
hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH);
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
furi_record_close("gui");
|
||||
view_port_free(view_port);
|
||||
osMessageQueueDelete(event_queue);
|
||||
delete_mutex(&state_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ 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, test, Test)
|
||||
ADD_SCENE(subghz, test_static, TestStatic)
|
||||
ADD_SCENE(subghz, test_carrier, TestCarrier)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "../subghz_i.h"
|
||||
|
||||
#define SCENE_NO_MAN_CUSTOM_EVENT (11UL)
|
||||
|
||||
void subghz_scene_no_man_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) {
|
||||
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_timeout(popup, 1500);
|
||||
popup_set_context(popup, subghz);
|
||||
popup_set_callback(popup, subghz_scene_no_man_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) {
|
||||
SubGhz* subghz = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SCENE_NO_MAN_CUSTOM_EVENT) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneStart);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const void subghz_scene_no_man_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Clear view
|
||||
Popup* popup = subghz->popup;
|
||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 0, NULL);
|
||||
popup_set_callback(popup, NULL);
|
||||
popup_set_context(popup, NULL);
|
||||
popup_set_timeout(popup, 0);
|
||||
popup_disable_timeout(popup);
|
||||
}
|
||||
@@ -57,6 +57,10 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event
|
||||
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
|
||||
return true;
|
||||
break;
|
||||
case SubghzReceverEventSendHistoryFull:
|
||||
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -146,11 +146,15 @@ const bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event
|
||||
subghz->protocol_result->serial = key & 0x0FFFFFFF;
|
||||
subghz->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
|
||||
subghz->protocol_result->cnt = 0x0003;
|
||||
subghz_protocol_keeloq_set_manufacture_name(subghz->protocol_result, "DoorHan");
|
||||
subghz->protocol_result->code_last_found =
|
||||
subghz_protocol_keeloq_gen_key(subghz->protocol_result);
|
||||
|
||||
generated_protocol = true;
|
||||
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);
|
||||
generated_protocol = true;
|
||||
} else {
|
||||
generated_protocol = false;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNoMan);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -38,6 +38,11 @@ const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent ev
|
||||
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) {
|
||||
|
||||
@@ -129,8 +129,8 @@ SubGhz* subghz_alloc() {
|
||||
subghz->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse);
|
||||
subghz_worker_set_context(subghz->worker, subghz->protocol);
|
||||
|
||||
subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/assets/subghz/keeloq_mfcodes");
|
||||
subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/assets/subghz/nice_floor_s_rx");
|
||||
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");
|
||||
|
||||
//subghz_protocol_enable_dump_text(subghz->protocol, subghz_text_callback, subghz);
|
||||
|
||||
|
||||
@@ -206,8 +206,8 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
|
||||
furi_check(instance->stream);
|
||||
|
||||
SubGhzProtocol* protocol = subghz_protocol_alloc();
|
||||
subghz_protocol_load_keeloq_file(protocol, "/ext/assets/subghz/keeloq_mfcodes");
|
||||
subghz_protocol_load_nice_flor_s_file(protocol, "/ext/assets/subghz/nice_floor_s_rx");
|
||||
subghz_protocol_load_keeloq_file(protocol, "/ext/subghz/keeloq_mfcodes");
|
||||
subghz_protocol_load_nice_flor_s_file(protocol, "/ext/subghz/nice_floor_s_rx");
|
||||
subghz_protocol_enable_dump_text(protocol, subghz_cli_command_rx_text_callback, instance);
|
||||
|
||||
// Configure radio
|
||||
|
||||
@@ -88,9 +88,15 @@ SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, u
|
||||
instance->data.param1 = instance->history[idx].te;
|
||||
return &instance->data;
|
||||
}
|
||||
void subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output) {
|
||||
bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output) {
|
||||
furi_assert(instance);
|
||||
string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX);
|
||||
if(instance->last_index_write == SUBGHZ_HISTORY_MAX) {
|
||||
if(output != NULL) string_printf(output, "Memory is FULL");
|
||||
return true;
|
||||
}
|
||||
if(output != NULL)
|
||||
string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX);
|
||||
return false;
|
||||
}
|
||||
void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx) {
|
||||
if(instance->history[idx].code_count_bit < 33) {
|
||||
@@ -144,10 +150,10 @@ void subghz_history_add_to_history(SubGhzHistory* instance, void* context) {
|
||||
instance->history[instance->last_index_write].code_found = protocol->code_last_found;
|
||||
if(strcmp(protocol->name, "KeeLoq") == 0) {
|
||||
instance->history[instance->last_index_write].manufacture_name =
|
||||
subghz_protocol_keeloq_get_manufacture_name(protocol);
|
||||
subghz_protocol_keeloq_find_and_get_manufacture_name(protocol);
|
||||
} else if(strcmp(protocol->name, "Star Line") == 0) {
|
||||
instance->history[instance->last_index_write].manufacture_name =
|
||||
subghz_protocol_star_line_get_manufacture_name(protocol);
|
||||
subghz_protocol_star_line_find_and_get_manufacture_name(protocol);
|
||||
} else if(strcmp(protocol->name, "Princeton") == 0) {
|
||||
instance->history[instance->last_index_write].te =
|
||||
subghz_protocol_princeton_get_te(protocol);
|
||||
|
||||
@@ -4,20 +4,103 @@
|
||||
|
||||
typedef struct SubGhzHistory SubGhzHistory;
|
||||
|
||||
/** Allocate SubGhzHistory
|
||||
*
|
||||
* @return SubGhzHistory*
|
||||
*/
|
||||
SubGhzHistory* subghz_history_alloc(void);
|
||||
|
||||
/** Free SubGhzHistory
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
*/
|
||||
void subghz_history_free(SubGhzHistory* instance);
|
||||
|
||||
/** Clear history
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
*/
|
||||
void subghz_history_clean(SubGhzHistory* instance);
|
||||
|
||||
/** Set frequency and preset to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param idx - record index
|
||||
* @param frequency - frequency Hz
|
||||
* @param preset - FuriHalSubGhzPreset preset
|
||||
*/
|
||||
void subghz_history_set_frequency_preset(
|
||||
SubGhzHistory* instance,
|
||||
uint16_t idx,
|
||||
uint32_t frequency,
|
||||
FuriHalSubGhzPreset preset);
|
||||
|
||||
/** Get frequency to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param idx - record index
|
||||
* @return frequency - frequency Hz
|
||||
*/
|
||||
uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx);
|
||||
|
||||
/** Get preset to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param idx - record index
|
||||
* @return preset - FuriHalSubGhzPreset preset
|
||||
*/
|
||||
FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx);
|
||||
|
||||
/** Get history index write
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @return idx - current record index
|
||||
*/
|
||||
uint16_t subghz_history_get_item(SubGhzHistory* instance);
|
||||
|
||||
/** Get type protocol to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param idx - record index
|
||||
* @return type - type protocol
|
||||
*/
|
||||
uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx);
|
||||
|
||||
/** Get name protocol to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param idx - record index
|
||||
* @return name - const char* name protocol
|
||||
*/
|
||||
const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx);
|
||||
|
||||
/** Get string item menu to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param output - string_t output
|
||||
* @param idx - record index
|
||||
*/
|
||||
void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx);
|
||||
void subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output);
|
||||
|
||||
/** Get string the remaining number of records to history
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param output - string_t output
|
||||
* @return bool - is FUUL
|
||||
*/
|
||||
bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output);
|
||||
|
||||
/** Add protocol to history
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param context - SubGhzProtocolCommon context
|
||||
*/
|
||||
void subghz_history_add_to_history(SubGhzHistory* instance, void* context);
|
||||
|
||||
/** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param idx - record index
|
||||
* @return SubGhzProtocolCommonLoad*
|
||||
*/
|
||||
SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);
|
||||
|
||||
@@ -39,9 +39,9 @@ typedef enum {
|
||||
} SubGhzHopperState;
|
||||
|
||||
static const Icon* ReceiverItemIcons[] = {
|
||||
[TYPE_PROTOCOL_UNKNOWN] = &I_quest_7x8,
|
||||
[TYPE_PROTOCOL_STATIC] = &I_unlock_7x8,
|
||||
[TYPE_PROTOCOL_DYNAMIC] = &I_lock_7x8,
|
||||
[TYPE_PROTOCOL_UNKNOWN] = &I_Quest_7x8,
|
||||
[TYPE_PROTOCOL_STATIC] = &I_Unlock_7x8,
|
||||
[TYPE_PROTOCOL_DYNAMIC] = &I_Lock_7x8,
|
||||
};
|
||||
|
||||
struct SubghzReceiver {
|
||||
@@ -53,6 +53,7 @@ struct SubghzReceiver {
|
||||
osTimerId timer;
|
||||
SubGhzHopperState hopper_state;
|
||||
uint8_t hopper_timeout;
|
||||
uint32_t event_key_sequence;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -172,44 +173,40 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
|
||||
string_clean(str_buff);
|
||||
}
|
||||
if(scrollbar) {
|
||||
elements_scrollbar_pos(canvas, 126, 0, 49, model->idx, model->history_item);
|
||||
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, "Conf");
|
||||
if((model->real_frequency / 1000 % 10) > 4) {
|
||||
frequency = model->real_frequency + 10000;
|
||||
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 {
|
||||
frequency = model->real_frequency;
|
||||
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));
|
||||
}
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"%03ld.%02ld",
|
||||
frequency / 1000000 % 1000,
|
||||
frequency / 10000 % 100);
|
||||
canvas_draw_str(canvas, 40, 62, buffer);
|
||||
canvas_draw_str(canvas, 75, 62, "AM");
|
||||
subghz_history_get_text_space_left(model->history, str_buff);
|
||||
canvas_draw_str(canvas, 94, 62, string_get_cstr(str_buff));
|
||||
canvas_draw_line(canvas, 38, 51, 125, 51);
|
||||
break;
|
||||
|
||||
case ReceiverSceneStart:
|
||||
canvas_draw_icon(canvas, 0, 0, &I_RFIDDolphinReceive_97x61);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_box(canvas, 80, 2, 20, 20);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_icon(canvas, 75, 8, &I_sub1_10px);
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 63, 40, "Scanning...");
|
||||
canvas_draw_str(canvas, 63, 46, "Scanning...");
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_button_left(canvas, "Conf");
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_box(canvas, 38, 52, 10, 10);
|
||||
canvas_invert_color(canvas);
|
||||
elements_button_left(canvas, "Config");
|
||||
if((model->real_frequency / 1000 % 10) > 4) {
|
||||
frequency = model->real_frequency + 10000;
|
||||
} else {
|
||||
@@ -221,11 +218,11 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
|
||||
"%03ld.%02ld",
|
||||
frequency / 1000000 % 1000,
|
||||
frequency / 10000 % 100);
|
||||
canvas_draw_str(canvas, 40, 62, buffer);
|
||||
canvas_draw_str(canvas, 75, 62, "AM");
|
||||
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, 94, 62, string_get_cstr(str_buff));
|
||||
canvas_draw_line(canvas, 48, 51, 125, 51);
|
||||
canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff));
|
||||
canvas_draw_line(canvas, 46, 51, 125, 51);
|
||||
break;
|
||||
|
||||
case ReceiverSceneConfig:
|
||||
@@ -237,9 +234,12 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
|
||||
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: <auto>");
|
||||
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;
|
||||
@@ -269,6 +269,13 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
|
||||
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);
|
||||
|
||||
@@ -280,13 +287,11 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
|
||||
return false;
|
||||
});
|
||||
|
||||
if(scene != ReceiverSceneInfo && event->type != InputTypeShort) return false;
|
||||
|
||||
bool can_be_saved = false;
|
||||
|
||||
switch(scene) {
|
||||
case ReceiverSceneMain:
|
||||
if(event->key == InputKeyBack) {
|
||||
if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
subghz_receiver->view, (SubghzReceiverModel * model) {
|
||||
model->idx = 0;
|
||||
@@ -296,19 +301,23 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
|
||||
return true;
|
||||
});
|
||||
return false;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
} 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) {
|
||||
} 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) {
|
||||
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
|
||||
subghz_receiver->hopper_state = SubGhzHopperStatePause;
|
||||
with_view_model(
|
||||
subghz_receiver->view, (SubghzReceiverModel * model) {
|
||||
@@ -317,7 +326,8 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
|
||||
return true;
|
||||
});
|
||||
subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
|
||||
} else if(event->key == InputKeyOk) {
|
||||
} 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);
|
||||
@@ -358,18 +368,23 @@ bool subghz_receiver_input(InputEvent* event, void* 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) {
|
||||
} 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) {
|
||||
} 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) {
|
||||
@@ -396,7 +411,6 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
|
||||
osTimerStart(subghz_receiver->timer, 1024 / 10);
|
||||
subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
|
||||
}
|
||||
|
||||
if(subghz_history_get_item(model->history) == 0) {
|
||||
model->scene = ReceiverSceneStart;
|
||||
} else {
|
||||
@@ -426,6 +440,7 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
|
||||
break;
|
||||
|
||||
case ReceiverSceneStart:
|
||||
if(event->type != InputTypeShort) return false;
|
||||
if(event->key == InputKeyBack) {
|
||||
return false;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
@@ -445,6 +460,16 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
|
||||
}
|
||||
|
||||
subghz_receiver_update_offset(subghz_receiver);
|
||||
if(scene != ReceiverSceneInfo) {
|
||||
with_view_model(
|
||||
subghz_receiver->view, (SubghzReceiverModel * model) {
|
||||
if(subghz_history_get_text_space_left(model->history, NULL)) {
|
||||
subghz_receiver_history_full(subghz_receiver);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -476,6 +501,9 @@ void subghz_receiver_protocol_callback(SubGhzProtocolCommon* parser, void* conte
|
||||
|
||||
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);
|
||||
@@ -528,10 +556,11 @@ static void subghz_receiver_timer_callback(void* context) {
|
||||
}
|
||||
|
||||
// Restart radio
|
||||
subghz_rx_end(subghz_receiver->worker);
|
||||
furi_hal_subghz_idle();
|
||||
subghz_protocol_reset(subghz_receiver->protocol);
|
||||
model->real_frequency =
|
||||
subghz_rx(subghz_receiver->worker, subghz_frequencies_hopper[model->frequency]);
|
||||
model->real_frequency = furi_hal_subghz_set_frequency_and_path(
|
||||
subghz_frequencies_hopper[model->frequency]);
|
||||
furi_hal_subghz_rx();
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -14,7 +14,8 @@ typedef enum {
|
||||
SubghzReceverEventBack,
|
||||
SubghzReceverEventMore,
|
||||
SubghzReceverEventSendStart,
|
||||
SubghzReceverEventSendStop
|
||||
SubghzReceverEventSendStop,
|
||||
SubghzReceverEventSendHistoryFull,
|
||||
} SubghzReceverEvent;
|
||||
|
||||
typedef struct SubghzReceiver SubghzReceiver;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#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;
|
||||
@@ -100,6 +101,10 @@ void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -107,22 +112,33 @@ void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) {
|
||||
bool subghz_transmitter_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
SubghzTransmitter* subghz_transmitter = context;
|
||||
bool can_be_send = false;
|
||||
bool can_be_sent = false;
|
||||
|
||||
if(event->key == InputKeyBack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
with_view_model(
|
||||
subghz_transmitter->view, (SubghzTransmitterModel * model) {
|
||||
can_be_send = (model->protocol && model->protocol->get_upload_protocol);
|
||||
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;
|
||||
}
|
||||
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(event->key == InputKeyBack) {
|
||||
return false;
|
||||
} else if(can_be_send && event->key == InputKeyOk && event->type == InputTypePress) {
|
||||
if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
|
||||
subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context);
|
||||
return true;
|
||||
} else if(can_be_send && event->key == InputKeyOk && event->type == InputTypeRelease) {
|
||||
} else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) {
|
||||
subghz_transmitter->callback(SubghzTransmitterEventSendStop, subghz_transmitter->context);
|
||||
return true;
|
||||
}
|
||||
@@ -147,6 +163,7 @@ void subghz_transmitter_enter(void* 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;
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ typedef enum {
|
||||
SubghzTransmitterEventSendStart,
|
||||
SubghzTransmitterEventSendStop,
|
||||
SubghzTransmitterEventBack,
|
||||
SubghzTransmitterEventNoMan,
|
||||
} SubghzTransmitterEvent;
|
||||
|
||||
typedef struct SubghzTransmitter SubghzTransmitter;
|
||||
|
||||
Reference in New Issue
Block a user