[FL-1401] Add Universal TV remote (#539)
* Remove excess headers * Add ButtonPanel * Add Popup * Move FileReader to standalone object * Universal remote (part 1) * Universal remote (part 2) * Global rename tranciever/file_parser * Compile assets * syntax fix * English: rename tranceiver to transceiver. Co-authored-by: あく <alleteam@gmail.com>
@ -8,6 +8,42 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void elements_progress_bar(
|
||||||
|
Canvas* canvas,
|
||||||
|
uint8_t x,
|
||||||
|
uint8_t y,
|
||||||
|
uint8_t width,
|
||||||
|
uint8_t progress,
|
||||||
|
uint8_t total) {
|
||||||
|
furi_assert(canvas);
|
||||||
|
furi_assert(total > 0);
|
||||||
|
uint8_t height = 9;
|
||||||
|
uint8_t marker_width = 7;
|
||||||
|
furi_assert(width > marker_width);
|
||||||
|
|
||||||
|
uint8_t progress_length = ((float)progress / total) * (width - marker_width - 2);
|
||||||
|
|
||||||
|
// rframe doesnt work if (radius * 2) > any rect side, so write manually
|
||||||
|
uint8_t x_max = x + width - 1;
|
||||||
|
uint8_t y_max = y + height - 1;
|
||||||
|
canvas_draw_line(canvas, x + 3, y, x_max - 3, y);
|
||||||
|
canvas_draw_line(canvas, x_max - 3, y, x_max, y + 3);
|
||||||
|
canvas_draw_line(canvas, x_max, y + 3, x_max, y_max - 3);
|
||||||
|
canvas_draw_line(canvas, x_max, y_max - 3, x_max - 3, y_max);
|
||||||
|
canvas_draw_line(canvas, x_max - 3, y_max, x + 3, y_max);
|
||||||
|
canvas_draw_line(canvas, x + 3, y_max, x, y_max - 3);
|
||||||
|
canvas_draw_line(canvas, x, y_max - 3, x, y + 3);
|
||||||
|
canvas_draw_line(canvas, x, y + 3, x + 3, y);
|
||||||
|
|
||||||
|
canvas_draw_rbox(canvas, x + 1, y + 1, marker_width + progress_length, height - 2, 3);
|
||||||
|
canvas_invert_color(canvas);
|
||||||
|
canvas_draw_dot(canvas, x + progress_length + 3, y + 2);
|
||||||
|
canvas_draw_dot(canvas, x + progress_length + 4, y + 2);
|
||||||
|
canvas_draw_dot(canvas, x + progress_length + 5, y + 3);
|
||||||
|
canvas_draw_dot(canvas, x + progress_length + 6, y + 4);
|
||||||
|
canvas_invert_color(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
void elements_scrollbar_pos(
|
void elements_scrollbar_pos(
|
||||||
Canvas* canvas,
|
Canvas* canvas,
|
||||||
uint8_t x,
|
uint8_t x,
|
||||||
|
@ -8,6 +8,22 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw progress bar.
|
||||||
|
* @param x - progress bar position on X axis
|
||||||
|
* @param y - progress bar position on Y axis
|
||||||
|
* @param width - progress bar width
|
||||||
|
* @param progress - progress in unnamed metric
|
||||||
|
* @param total - total amount in unnamed metric
|
||||||
|
*/
|
||||||
|
void elements_progress_bar(
|
||||||
|
Canvas* canvas,
|
||||||
|
uint8_t x,
|
||||||
|
uint8_t y,
|
||||||
|
uint8_t width,
|
||||||
|
uint8_t progress,
|
||||||
|
uint8_t total);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Draw scrollbar on canvas at specific position.
|
* Draw scrollbar on canvas at specific position.
|
||||||
* @param x - scrollbar position on X axis
|
* @param x - scrollbar position on X axis
|
||||||
@ -16,7 +32,6 @@ extern "C" {
|
|||||||
* @param pos - current element
|
* @param pos - current element
|
||||||
* @param total - total elements
|
* @param total - total elements
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void elements_scrollbar_pos(
|
void elements_scrollbar_pos(
|
||||||
Canvas* canvas,
|
Canvas* canvas,
|
||||||
uint8_t x,
|
uint8_t x,
|
||||||
|
409
applications/gui/modules/button_panel.c
Normal file
@ -0,0 +1,409 @@
|
|||||||
|
#include "button_panel.h"
|
||||||
|
#include "api-hal-resources.h"
|
||||||
|
#include "gui/canvas.h"
|
||||||
|
#include <m-array.h>
|
||||||
|
#include <m-i-list.h>
|
||||||
|
#include <m-list.h>
|
||||||
|
#include <furi.h>
|
||||||
|
#include <gui/elements.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// uint16_t to support multi-screen, wide button panel
|
||||||
|
uint16_t x;
|
||||||
|
uint16_t y;
|
||||||
|
Font font;
|
||||||
|
const char* str;
|
||||||
|
} LabelElement;
|
||||||
|
|
||||||
|
LIST_DEF(LabelList, LabelElement, M_POD_OPLIST)
|
||||||
|
#define M_OPL_LabelList_t() LIST_OPLIST(LabelList)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t x;
|
||||||
|
uint16_t y;
|
||||||
|
IconName name;
|
||||||
|
IconName name_selected;
|
||||||
|
} IconElement;
|
||||||
|
|
||||||
|
typedef struct ButtonItem {
|
||||||
|
uint32_t index;
|
||||||
|
ButtonItemCallback callback;
|
||||||
|
IconElement icon;
|
||||||
|
void* callback_context;
|
||||||
|
} ButtonItem;
|
||||||
|
|
||||||
|
ARRAY_DEF(ButtonArray, ButtonItem*, M_PTR_OPLIST);
|
||||||
|
#define M_OPL_ButtonArray_t() ARRAY_OPLIST(ButtonArray, M_PTR_OPLIST)
|
||||||
|
ARRAY_DEF(ButtonMatrix, ButtonArray_t);
|
||||||
|
#define M_OPL_ButtonMatrix_t() ARRAY_OPLIST(ButtonMatrix, M_OPL_ButtonArray_t())
|
||||||
|
|
||||||
|
struct ButtonPanel {
|
||||||
|
View* view;
|
||||||
|
ButtonPanelInputCallback input_callback;
|
||||||
|
void* input_context;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ButtonMatrix_t button_matrix;
|
||||||
|
LabelList_t labels;
|
||||||
|
uint16_t reserve_x;
|
||||||
|
uint16_t reserve_y;
|
||||||
|
uint16_t selected_item_x;
|
||||||
|
uint16_t selected_item_y;
|
||||||
|
ButtonPanelDrawCallback draw_callback;
|
||||||
|
void* draw_context;
|
||||||
|
} ButtonPanelModel;
|
||||||
|
|
||||||
|
static ButtonItem** button_panel_get_item(ButtonPanelModel* model, size_t x, size_t y);
|
||||||
|
static void button_panel_process_up(ButtonPanel* button_panel);
|
||||||
|
static void button_panel_process_down(ButtonPanel* button_panel);
|
||||||
|
static void button_panel_process_left(ButtonPanel* button_panel);
|
||||||
|
static void button_panel_process_right(ButtonPanel* button_panel);
|
||||||
|
static void button_panel_process_ok(ButtonPanel* button_panel);
|
||||||
|
static void button_panel_view_draw_callback(Canvas* canvas, void* _model);
|
||||||
|
static bool button_panel_view_input_callback(InputEvent* event, void* context);
|
||||||
|
|
||||||
|
ButtonPanel* button_panel_alloc() {
|
||||||
|
ButtonPanel* button_panel = furi_alloc(sizeof(ButtonPanel));
|
||||||
|
button_panel->view = view_alloc();
|
||||||
|
view_set_orientation(button_panel->view, ViewOrientationVertical);
|
||||||
|
view_set_context(button_panel->view, button_panel);
|
||||||
|
view_allocate_model(button_panel->view, ViewModelTypeLocking, sizeof(ButtonPanelModel));
|
||||||
|
view_set_draw_callback(button_panel->view, button_panel_view_draw_callback);
|
||||||
|
view_set_input_callback(button_panel->view, button_panel_view_input_callback);
|
||||||
|
button_panel->input_callback = NULL;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
model->reserve_x = 0;
|
||||||
|
model->reserve_y = 0;
|
||||||
|
model->selected_item_x = 0;
|
||||||
|
model->selected_item_y = 0;
|
||||||
|
model->draw_callback = NULL;
|
||||||
|
ButtonMatrix_init(model->button_matrix);
|
||||||
|
LabelList_init(model->labels);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return button_panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t reserve_y) {
|
||||||
|
furi_check(reserve_x > 0);
|
||||||
|
furi_check(reserve_y > 0);
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
model->reserve_x = reserve_x;
|
||||||
|
model->reserve_y = reserve_y;
|
||||||
|
ButtonMatrix_reserve(model->button_matrix, model->reserve_y);
|
||||||
|
for(size_t i = 0; i > model->reserve_y; ++i) {
|
||||||
|
ButtonArray_t* array = ButtonMatrix_get(model->button_matrix, i);
|
||||||
|
ButtonArray_init(*array);
|
||||||
|
ButtonArray_reserve(*array, reserve_x);
|
||||||
|
// TODO: do we need to clear allocated memory of ptr-s to ButtonItem ??
|
||||||
|
}
|
||||||
|
LabelList_init(model->labels);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void button_panel_free(ButtonPanel* button_panel) {
|
||||||
|
furi_assert(button_panel);
|
||||||
|
|
||||||
|
button_panel_clean(button_panel);
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
LabelList_clear(model->labels);
|
||||||
|
ButtonMatrix_clear(model->button_matrix);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
view_free(button_panel->view);
|
||||||
|
free(button_panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void button_panel_clean(ButtonPanel* button_panel) {
|
||||||
|
furi_assert(button_panel);
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
for(size_t x = 0; x < model->reserve_x; ++x) {
|
||||||
|
for(size_t y = 0; y < model->reserve_y; ++y) {
|
||||||
|
ButtonItem** button_item = button_panel_get_item(model, x, y);
|
||||||
|
free(*button_item);
|
||||||
|
*button_item = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static ButtonItem** button_panel_get_item(ButtonPanelModel* model, size_t x, size_t y) {
|
||||||
|
furi_assert(model);
|
||||||
|
|
||||||
|
furi_check(x < model->reserve_x);
|
||||||
|
furi_check(y < model->reserve_y);
|
||||||
|
ButtonArray_t* button_array = ButtonMatrix_get_at(model->button_matrix, x);
|
||||||
|
ButtonItem** button_item = ButtonArray_get_at(*button_array, y);
|
||||||
|
return button_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void button_panel_add_item(
|
||||||
|
ButtonPanel* button_panel,
|
||||||
|
uint32_t index,
|
||||||
|
uint16_t matrix_place_x,
|
||||||
|
uint16_t matrix_place_y,
|
||||||
|
uint16_t x,
|
||||||
|
uint16_t y,
|
||||||
|
IconName icon_name,
|
||||||
|
IconName icon_name_selected,
|
||||||
|
ButtonItemCallback callback,
|
||||||
|
void* callback_context) {
|
||||||
|
furi_assert(button_panel);
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
ButtonItem** button_item_ptr =
|
||||||
|
button_panel_get_item(model, matrix_place_x, matrix_place_y);
|
||||||
|
furi_check(*button_item_ptr == NULL);
|
||||||
|
*button_item_ptr = furi_alloc(sizeof(ButtonItem));
|
||||||
|
ButtonItem* button_item = *button_item_ptr;
|
||||||
|
button_item->callback = callback;
|
||||||
|
button_item->callback_context = callback_context;
|
||||||
|
button_item->icon.x = x;
|
||||||
|
button_item->icon.y = y;
|
||||||
|
button_item->icon.name = icon_name;
|
||||||
|
button_item->icon.name_selected = icon_name_selected;
|
||||||
|
button_item->index = index;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
View* button_panel_get_view(ButtonPanel* button_panel) {
|
||||||
|
furi_assert(button_panel);
|
||||||
|
return button_panel->view;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void button_panel_view_draw_callback(Canvas* canvas, void* _model) {
|
||||||
|
furi_assert(canvas);
|
||||||
|
furi_assert(_model);
|
||||||
|
|
||||||
|
ButtonPanelModel* model = _model;
|
||||||
|
|
||||||
|
canvas_clear(canvas);
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
|
for(size_t x = 0; x < model->reserve_x; ++x) {
|
||||||
|
for(size_t y = 0; y < model->reserve_y; ++y) {
|
||||||
|
ButtonItem* button_item = *button_panel_get_item(model, x, y);
|
||||||
|
IconName icon_name = button_item->icon.name;
|
||||||
|
if((model->selected_item_x == x) && (model->selected_item_y == y)) {
|
||||||
|
icon_name = button_item->icon.name_selected;
|
||||||
|
}
|
||||||
|
canvas_draw_icon_name(canvas, button_item->icon.x, button_item->icon.y, icon_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for
|
||||||
|
M_EACH(label, model->labels, LabelList_t) {
|
||||||
|
canvas_set_font(canvas, label->font);
|
||||||
|
canvas_draw_str(canvas, label->x, label->y, label->str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(model->draw_callback) model->draw_callback(canvas, model->draw_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void button_panel_process_down(ButtonPanel* button_panel) {
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
size_t new_selected_item_x = model->selected_item_x;
|
||||||
|
size_t new_selected_item_y = model->selected_item_y;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if(new_selected_item_y >= (model->reserve_y - 1)) return false;
|
||||||
|
|
||||||
|
++new_selected_item_y;
|
||||||
|
|
||||||
|
for(i = 0; i < model->reserve_x; ++i) {
|
||||||
|
new_selected_item_x = (model->selected_item_x + i) % model->reserve_x;
|
||||||
|
if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(i == model->reserve_x) return false;
|
||||||
|
|
||||||
|
model->selected_item_x = new_selected_item_x;
|
||||||
|
model->selected_item_y = new_selected_item_y;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void button_panel_process_up(ButtonPanel* button_panel) {
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
size_t new_selected_item_x = model->selected_item_x;
|
||||||
|
size_t new_selected_item_y = model->selected_item_y;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if(new_selected_item_y <= 0) return false;
|
||||||
|
|
||||||
|
--new_selected_item_y;
|
||||||
|
|
||||||
|
for(i = 0; i < model->reserve_x; ++i) {
|
||||||
|
new_selected_item_x = (model->selected_item_x + i) % model->reserve_x;
|
||||||
|
if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(i == model->reserve_x) return false;
|
||||||
|
|
||||||
|
model->selected_item_x = new_selected_item_x;
|
||||||
|
model->selected_item_y = new_selected_item_y;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void button_panel_process_left(ButtonPanel* button_panel) {
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
size_t new_selected_item_x = model->selected_item_x;
|
||||||
|
size_t new_selected_item_y = model->selected_item_y;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if(new_selected_item_x <= 0) return false;
|
||||||
|
|
||||||
|
--new_selected_item_x;
|
||||||
|
|
||||||
|
for(i = 0; i < model->reserve_y; ++i) {
|
||||||
|
new_selected_item_y = (model->selected_item_y + i) % model->reserve_y;
|
||||||
|
if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(i == model->reserve_y) return false;
|
||||||
|
|
||||||
|
model->selected_item_x = new_selected_item_x;
|
||||||
|
model->selected_item_y = new_selected_item_y;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void button_panel_process_right(ButtonPanel* button_panel) {
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
size_t new_selected_item_x = model->selected_item_x;
|
||||||
|
size_t new_selected_item_y = model->selected_item_y;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if(new_selected_item_x >= (model->reserve_x - 1)) return false;
|
||||||
|
|
||||||
|
++new_selected_item_x;
|
||||||
|
|
||||||
|
for(i = 0; i < model->reserve_y; ++i) {
|
||||||
|
new_selected_item_y = (model->selected_item_y + i) % model->reserve_y;
|
||||||
|
if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(i == model->reserve_y) return false;
|
||||||
|
|
||||||
|
model->selected_item_x = new_selected_item_x;
|
||||||
|
model->selected_item_y = new_selected_item_y;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void button_panel_process_ok(ButtonPanel* button_panel) {
|
||||||
|
ButtonItem* button_item = NULL;
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
button_item =
|
||||||
|
*button_panel_get_item(model, model->selected_item_x, model->selected_item_y);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(button_item && button_item->callback) {
|
||||||
|
button_item->callback(button_item->callback_context, button_item->index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool button_panel_view_input_callback(InputEvent* event, void* context) {
|
||||||
|
ButtonPanel* button_panel = context;
|
||||||
|
furi_assert(button_panel);
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(button_panel->input_callback) {
|
||||||
|
consumed = button_panel->input_callback(event, button_panel->input_context);
|
||||||
|
} else if(event->type == InputTypeShort) {
|
||||||
|
switch(event->key) {
|
||||||
|
case InputKeyUp:
|
||||||
|
consumed = true;
|
||||||
|
button_panel_process_up(button_panel);
|
||||||
|
break;
|
||||||
|
case InputKeyDown:
|
||||||
|
consumed = true;
|
||||||
|
button_panel_process_down(button_panel);
|
||||||
|
break;
|
||||||
|
case InputKeyLeft:
|
||||||
|
consumed = true;
|
||||||
|
button_panel_process_left(button_panel);
|
||||||
|
break;
|
||||||
|
case InputKeyRight:
|
||||||
|
consumed = true;
|
||||||
|
button_panel_process_right(button_panel);
|
||||||
|
break;
|
||||||
|
case InputKeyOk:
|
||||||
|
consumed = true;
|
||||||
|
button_panel_process_ok(button_panel);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void button_panel_add_label(
|
||||||
|
ButtonPanel* button_panel,
|
||||||
|
uint16_t x,
|
||||||
|
uint16_t y,
|
||||||
|
Font font,
|
||||||
|
const char* label_str) {
|
||||||
|
furi_assert(button_panel);
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
LabelElement* label = LabelList_push_raw(model->labels);
|
||||||
|
label->x = x;
|
||||||
|
label->y = y;
|
||||||
|
label->font = font;
|
||||||
|
label->str = label_str;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void button_panel_set_popup_draw_callback(
|
||||||
|
ButtonPanel* button_panel,
|
||||||
|
ButtonPanelDrawCallback callback,
|
||||||
|
void* context) {
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
model->draw_callback = callback;
|
||||||
|
model->draw_context = context;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void button_panel_set_popup_input_callback(
|
||||||
|
ButtonPanel* button_panel,
|
||||||
|
ButtonPanelInputCallback callback,
|
||||||
|
void* context) {
|
||||||
|
button_panel->input_context = context;
|
||||||
|
button_panel->input_callback = callback;
|
||||||
|
}
|
129
applications/gui/modules/button_panel.h
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <gui/view.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Button panel module descriptor */
|
||||||
|
typedef struct ButtonPanel ButtonPanel;
|
||||||
|
|
||||||
|
/** Callback type to call for handling selecting button_panel items */
|
||||||
|
typedef void (*ButtonItemCallback)(void* context, uint32_t index);
|
||||||
|
/** Callback type for additional drawings above main button_panel screen */
|
||||||
|
typedef void (*ButtonPanelDrawCallback)(Canvas* canvas, void* _model);
|
||||||
|
/** Callback type to intercept input events of button_panel */
|
||||||
|
typedef bool (*ButtonPanelInputCallback)(InputEvent* event, void* context);
|
||||||
|
|
||||||
|
/** Allocate new button_panel module.
|
||||||
|
*
|
||||||
|
* @return just-created module
|
||||||
|
*/
|
||||||
|
ButtonPanel* button_panel_alloc(void);
|
||||||
|
|
||||||
|
/** Free button_panel module.
|
||||||
|
*
|
||||||
|
* @param button_panel - module to free
|
||||||
|
*/
|
||||||
|
void button_panel_free(ButtonPanel* button_panel);
|
||||||
|
|
||||||
|
/** Free items from button_panel module. Preallocated matrix stays unchanged.
|
||||||
|
*
|
||||||
|
* @param button_panel - module to clean
|
||||||
|
*/
|
||||||
|
void button_panel_clean(ButtonPanel* button_panel);
|
||||||
|
|
||||||
|
/** Reserve space for adding items.
|
||||||
|
*
|
||||||
|
* One does not simply use button_panel_add_item() without this function.
|
||||||
|
* It should be allocated space for it first.
|
||||||
|
*
|
||||||
|
* @param button_panel - module to modify
|
||||||
|
* @param reserve_x - number of columns in button_panel
|
||||||
|
* @param reserve_y - number of rows in button_panel
|
||||||
|
*/
|
||||||
|
void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t reserve_y);
|
||||||
|
|
||||||
|
/** Add item to button_panel module.
|
||||||
|
*
|
||||||
|
* Have to set element in bounds of allocated size by X and by Y.
|
||||||
|
*
|
||||||
|
* @param button_panel - module
|
||||||
|
* @param index - value to pass to callback
|
||||||
|
* @param matrix_place_x - coordinates by x-axis on virtual grid, it
|
||||||
|
* is only used for naviagation
|
||||||
|
* @param matrix_place_y - coordinates by y-axis on virtual grid, it
|
||||||
|
* is only used for naviagation
|
||||||
|
* @param x - x-coordinate to draw icon on
|
||||||
|
* @param y - y-coordinate to draw icon on
|
||||||
|
* @param icon_name - name of the icon to draw
|
||||||
|
* @param icon_name_selected - name of the icon to draw when current
|
||||||
|
* element is selected
|
||||||
|
* @param callback - function to call when specific element is selected
|
||||||
|
* (pressed Ok on selected item)
|
||||||
|
* @param callback_context - context to pass to callback
|
||||||
|
*/
|
||||||
|
void button_panel_add_item(
|
||||||
|
ButtonPanel* button_panel,
|
||||||
|
uint32_t index,
|
||||||
|
uint16_t matrix_place_x,
|
||||||
|
uint16_t matrix_place_y,
|
||||||
|
uint16_t x,
|
||||||
|
uint16_t y,
|
||||||
|
IconName icon_name,
|
||||||
|
IconName icon_name_selected,
|
||||||
|
ButtonItemCallback callback,
|
||||||
|
void* callback_context);
|
||||||
|
|
||||||
|
/** Get button_panel view.
|
||||||
|
*
|
||||||
|
* @param button_panel - module to get view from
|
||||||
|
* @return acquired view
|
||||||
|
*/
|
||||||
|
View* button_panel_get_view(ButtonPanel* button_panel);
|
||||||
|
|
||||||
|
/** Add label to button_panel module.
|
||||||
|
*
|
||||||
|
* @param x - x-coordinate to place label
|
||||||
|
* @param y - y-coordinate to place label
|
||||||
|
* @param font - font to write label with
|
||||||
|
* @param label_str - string label to write
|
||||||
|
*/
|
||||||
|
void button_panel_add_label(
|
||||||
|
ButtonPanel* button_panel,
|
||||||
|
uint16_t x,
|
||||||
|
uint16_t y,
|
||||||
|
Font font,
|
||||||
|
const char* label_str);
|
||||||
|
|
||||||
|
// TODO: [FL-1445] Have to replace callbacks above with additional popup-layer
|
||||||
|
/** Set popup draw callback for button_panel module.
|
||||||
|
*
|
||||||
|
* Used to add popup drawings after main draw callback is done.
|
||||||
|
*
|
||||||
|
* @param button_panel - module to modify
|
||||||
|
* @param callback - callback function to set for draw event
|
||||||
|
* @param context - context to pass to callback
|
||||||
|
*/
|
||||||
|
void button_panel_set_popup_draw_callback(
|
||||||
|
ButtonPanel* button_panel,
|
||||||
|
ButtonPanelDrawCallback callback,
|
||||||
|
void* context);
|
||||||
|
|
||||||
|
/** Set popup input callback for button_panel module.
|
||||||
|
*
|
||||||
|
* Used to add popup input callback. It will intercept all input
|
||||||
|
* events for current view.
|
||||||
|
*
|
||||||
|
* @param button_panel - module to modify
|
||||||
|
* @param callback - function to overwrite main input callbacks
|
||||||
|
* @param context - context to pass to callback
|
||||||
|
*/
|
||||||
|
void button_panel_set_popup_input_callback(
|
||||||
|
ButtonPanel* button_panel,
|
||||||
|
ButtonPanelInputCallback callback,
|
||||||
|
void* context);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
77
applications/irda/irda-app-brute-force.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include "irda-app-brute-force.hpp"
|
||||||
|
|
||||||
|
void IrdaAppBruteForce::add_record(int index, const char* name) {
|
||||||
|
records[name].index = index;
|
||||||
|
records[name].amount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IrdaAppBruteForce::calculate_messages() {
|
||||||
|
bool fs_res = false;
|
||||||
|
fs_res = file_parser.get_fs_api().file.open(
|
||||||
|
&file, universal_db_filename, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||||
|
if(!fs_res) {
|
||||||
|
file_parser.get_sd_api().show_error(file_parser.get_sd_api().context, "Can't open file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_parser.reset();
|
||||||
|
while(1) {
|
||||||
|
auto message = file_parser.read_message(&file);
|
||||||
|
if(!message) break;
|
||||||
|
auto element = records.find(message->name);
|
||||||
|
if(element != records.cend()) {
|
||||||
|
++element->second.amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file_parser.get_fs_api().file.close(&file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrdaAppBruteForce::stop_bruteforce() {
|
||||||
|
if(current_record.size()) {
|
||||||
|
file_parser.get_fs_api().file.close(&file);
|
||||||
|
current_record.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: [FL-1418] replace with timer-chained consequence of messages.
|
||||||
|
bool IrdaAppBruteForce::send_next_bruteforce(const IrdaAppSignalTransceiver& transceiver) {
|
||||||
|
furi_assert(current_record.size());
|
||||||
|
|
||||||
|
std::unique_ptr<IrdaAppFileParser::IrdaFileMessage> message;
|
||||||
|
|
||||||
|
do {
|
||||||
|
message = file_parser.read_message(&file);
|
||||||
|
} while(message && current_record.compare(message->name));
|
||||||
|
|
||||||
|
if(message) {
|
||||||
|
transceiver.send_message(&message->message);
|
||||||
|
}
|
||||||
|
return !!message;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IrdaAppBruteForce::start_bruteforce(int index, int& record_amount) {
|
||||||
|
file_parser.reset();
|
||||||
|
for(const auto& it : records) {
|
||||||
|
if(it.second.index == index) {
|
||||||
|
record_amount = it.second.amount;
|
||||||
|
current_record = it.first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(record_amount) {
|
||||||
|
bool fs_res = file_parser.get_fs_api().file.open(
|
||||||
|
&file, universal_db_filename, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||||
|
if(fs_res) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
file_parser.get_sd_api().show_error(
|
||||||
|
file_parser.get_sd_api().context, "Can't open file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
38
applications/irda/irda-app-brute-force.hpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "furi/check.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "irda-app-file-parser.hpp"
|
||||||
|
#include "irda-app-transceiver.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class IrdaAppBruteForce {
|
||||||
|
const char* universal_db_filename;
|
||||||
|
IrdaAppFileParser file_parser;
|
||||||
|
File file;
|
||||||
|
std::string current_record;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int index;
|
||||||
|
int amount;
|
||||||
|
} Record;
|
||||||
|
|
||||||
|
// 'key' is record name, because we have to search by both, index and name,
|
||||||
|
// but index search has place once per button press, and should not be
|
||||||
|
// noticed, but name search should occur during entering universal menu,
|
||||||
|
// and will go through container for every record in file, that's why
|
||||||
|
// more critical to have faster search by record name.
|
||||||
|
std::unordered_map<std::string, Record> records;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool calculate_messages();
|
||||||
|
void stop_bruteforce();
|
||||||
|
bool send_next_bruteforce(const IrdaAppSignalTransceiver& receiver);
|
||||||
|
bool start_bruteforce(int index, int& record_amount);
|
||||||
|
void add_record(int index, const char* name);
|
||||||
|
|
||||||
|
IrdaAppBruteForce(const char* filename) : universal_db_filename (filename) {}
|
||||||
|
~IrdaAppBruteForce() {
|
||||||
|
stop_bruteforce();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -1,5 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
|
||||||
#include <irda.h>
|
#include <irda.h>
|
||||||
#include <gui/modules/dialog_ex.h>
|
#include <gui/modules/dialog_ex.h>
|
||||||
|
|
||||||
@ -14,6 +13,8 @@ public:
|
|||||||
IrdaMessageReceived,
|
IrdaMessageReceived,
|
||||||
TextEditDone,
|
TextEditDone,
|
||||||
PopupTimer,
|
PopupTimer,
|
||||||
|
ButtonPanelPressed,
|
||||||
|
ButtonPanelPopupBackPressed,
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
58
applications/irda/irda-app-file-parser.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "irda-app-file-parser.hpp"
|
||||||
|
|
||||||
|
std::unique_ptr<IrdaAppFileParser::IrdaFileMessage> IrdaAppFileParser::read_message(File* file) {
|
||||||
|
while(1) {
|
||||||
|
auto str = getline(file);
|
||||||
|
if(str.empty()) return nullptr;
|
||||||
|
|
||||||
|
auto message = parse_message(str);
|
||||||
|
if(message) return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IrdaAppFileParser::IrdaFileMessage>
|
||||||
|
IrdaAppFileParser::parse_message(const std::string& str) const {
|
||||||
|
char protocol_name[32];
|
||||||
|
uint32_t address;
|
||||||
|
uint32_t command;
|
||||||
|
auto irda_file_message = std::make_unique<IrdaFileMessage>();
|
||||||
|
|
||||||
|
int parsed = std::sscanf(
|
||||||
|
str.c_str(),
|
||||||
|
"%31s %31s A:%lX C:%lX",
|
||||||
|
irda_file_message->name,
|
||||||
|
protocol_name,
|
||||||
|
&address,
|
||||||
|
&command);
|
||||||
|
|
||||||
|
if(parsed != 4) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
IrdaProtocol protocol = irda_get_protocol_by_name(protocol_name);
|
||||||
|
|
||||||
|
if(!irda_is_protocol_valid((IrdaProtocol)protocol)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int address_length = irda_get_protocol_address_length(protocol);
|
||||||
|
uint32_t address_mask = (1LU << (4 * address_length)) - 1;
|
||||||
|
if(address != (address & address_mask)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int command_length = irda_get_protocol_command_length(protocol);
|
||||||
|
uint32_t command_mask = (1LU << (4 * command_length)) - 1;
|
||||||
|
if(command != (command & command_mask)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
irda_file_message->message = {
|
||||||
|
.protocol = protocol,
|
||||||
|
.address = address,
|
||||||
|
.command = command,
|
||||||
|
.repeat = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
return irda_file_message;
|
||||||
|
}
|
17
applications/irda/irda-app-file-parser.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "file_reader/file_reader.hpp"
|
||||||
|
#include "irda.h"
|
||||||
|
|
||||||
|
class IrdaAppFileParser : public FileReader {
|
||||||
|
public:
|
||||||
|
typedef struct {
|
||||||
|
char name[32];
|
||||||
|
IrdaMessage message;
|
||||||
|
} IrdaFileMessage;
|
||||||
|
|
||||||
|
std::unique_ptr<IrdaAppFileParser::IrdaFileMessage> read_message(File* file);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<IrdaFileMessage> parse_message(const std::string& str) const;
|
||||||
|
};
|
||||||
|
|
@ -4,10 +4,10 @@
|
|||||||
#include "furi/check.h"
|
#include "furi/check.h"
|
||||||
#include "gui/modules/button_menu.h"
|
#include "gui/modules/button_menu.h"
|
||||||
#include "irda.h"
|
#include "irda.h"
|
||||||
#include "sys/_stdint.h"
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include "irda-app-file-parser.hpp"
|
||||||
|
|
||||||
const char* IrdaAppRemoteManager::irda_directory = "irda";
|
const char* IrdaAppRemoteManager::irda_directory = "irda";
|
||||||
const char* IrdaAppRemoteManager::irda_extension = ".ir";
|
const char* IrdaAppRemoteManager::irda_extension = ".ir";
|
||||||
@ -33,16 +33,6 @@ find_vacant_name(const std::vector<std::string>& strings, const std::string& nam
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IrdaAppRemoteManager::IrdaAppRemoteManager() {
|
|
||||||
sd_ex_api = static_cast<SdCard_Api*>(furi_record_open("sdcard-ex"));
|
|
||||||
fs_api = static_cast<FS_Api*>(furi_record_open("sdcard"));
|
|
||||||
}
|
|
||||||
|
|
||||||
IrdaAppRemoteManager::~IrdaAppRemoteManager() {
|
|
||||||
furi_record_close("sdcard");
|
|
||||||
furi_record_close("sdcard-ex");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IrdaAppRemoteManager::add_button(const char* button_name, const IrdaMessage* message) {
|
bool IrdaAppRemoteManager::add_button(const char* button_name, const IrdaMessage* message) {
|
||||||
remote->buttons.emplace_back(button_name, message);
|
remote->buttons.emplace_back(button_name, message);
|
||||||
return store();
|
return store();
|
||||||
@ -94,10 +84,12 @@ std::string IrdaAppRemoteManager::make_filename(const std::string& name) const {
|
|||||||
|
|
||||||
bool IrdaAppRemoteManager::delete_remote() {
|
bool IrdaAppRemoteManager::delete_remote() {
|
||||||
FS_Error fs_res;
|
FS_Error fs_res;
|
||||||
|
IrdaAppFileParser file_parser;
|
||||||
|
|
||||||
fs_res = fs_api->common.remove(make_filename(remote->name).c_str());
|
fs_res = file_parser.get_fs_api().common.remove(make_filename(remote->name).c_str());
|
||||||
if(fs_res != FSE_OK) {
|
if(fs_res != FSE_OK) {
|
||||||
show_file_error_message("Error deleting file");
|
file_parser.get_sd_api().show_error(
|
||||||
|
file_parser.get_sd_api().context, "Error deleting file");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
remote.reset();
|
remote.reset();
|
||||||
@ -147,11 +139,13 @@ bool IrdaAppRemoteManager::rename_remote(const char* str) {
|
|||||||
if(!result) return false;
|
if(!result) return false;
|
||||||
|
|
||||||
auto new_name = find_vacant_name(remote_list, str);
|
auto new_name = find_vacant_name(remote_list, str);
|
||||||
FS_Error fs_err = fs_api->common.rename(
|
IrdaAppFileParser file_parser;
|
||||||
|
FS_Error fs_err = file_parser.get_fs_api().common.rename(
|
||||||
make_filename(remote->name).c_str(), make_filename(new_name).c_str());
|
make_filename(remote->name).c_str(), make_filename(new_name).c_str());
|
||||||
remote->name = new_name;
|
remote->name = new_name;
|
||||||
if(fs_err != FSE_OK) {
|
if(fs_err != FSE_OK) {
|
||||||
show_file_error_message("Error renaming\nremote file");
|
file_parser.get_sd_api().show_error(
|
||||||
|
file_parser.get_sd_api().context, "Error renaming\nremote file");
|
||||||
}
|
}
|
||||||
return fs_err == FSE_OK;
|
return fs_err == FSE_OK;
|
||||||
}
|
}
|
||||||
@ -170,26 +164,25 @@ size_t IrdaAppRemoteManager::get_number_of_buttons() {
|
|||||||
return remote->buttons.size();
|
return remote->buttons.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrdaAppRemoteManager::show_file_error_message(const char* error_text) const {
|
|
||||||
sd_ex_api->show_error(sd_ex_api->context, error_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IrdaAppRemoteManager::store(void) {
|
bool IrdaAppRemoteManager::store(void) {
|
||||||
File file;
|
File file;
|
||||||
uint16_t write_count;
|
uint16_t write_count;
|
||||||
std::string dirname(std::string("/") + irda_directory);
|
std::string dirname(std::string("/") + irda_directory);
|
||||||
|
|
||||||
FS_Error fs_err = fs_api->common.mkdir(dirname.c_str());
|
IrdaAppFileParser file_parser;
|
||||||
|
FS_Error fs_err = file_parser.get_fs_api().common.mkdir(dirname.c_str());
|
||||||
if((fs_err != FSE_OK) && (fs_err != FSE_EXIST)) {
|
if((fs_err != FSE_OK) && (fs_err != FSE_EXIST)) {
|
||||||
show_file_error_message("Can't create directory");
|
file_parser.get_sd_api().show_error(
|
||||||
|
file_parser.get_sd_api().context, "Can't create directory");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string filename = dirname + "/" + remote->name + irda_extension;
|
bool res = file_parser.get_fs_api().file.open(
|
||||||
bool res = fs_api->file.open(&file, filename.c_str(), FSAM_WRITE, FSOM_CREATE_ALWAYS);
|
&file, make_filename(remote->name).c_str(), FSAM_WRITE, FSOM_CREATE_ALWAYS);
|
||||||
|
|
||||||
if(!res) {
|
if(!res) {
|
||||||
show_file_error_message("Cannot create\nnew remote file");
|
file_parser.get_sd_api().show_error(
|
||||||
|
file_parser.get_sd_api().context, "Cannot create\nnew remote file");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,103 +203,21 @@ bool IrdaAppRemoteManager::store(void) {
|
|||||||
button.message.command);
|
button.message.command);
|
||||||
|
|
||||||
auto content_len = strlen(content);
|
auto content_len = strlen(content);
|
||||||
write_count = fs_api->file.write(&file, content, content_len);
|
write_count = file_parser.get_fs_api().file.write(&file, content, content_len);
|
||||||
if(file.error_id != FSE_OK || write_count != content_len) {
|
if(file.error_id != FSE_OK || write_count != content_len) {
|
||||||
show_file_error_message("Cannot write\nto key file");
|
file_parser.get_sd_api().show_error(
|
||||||
fs_api->file.close(&file);
|
file_parser.get_sd_api().context, "Cannot write\nto key file");
|
||||||
|
file_parser.get_fs_api().file.close(&file);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fs_api->file.close(&file);
|
file_parser.get_fs_api().file.close(&file);
|
||||||
sd_ex_api->check_error(sd_ex_api->context);
|
file_parser.get_sd_api().check_error(file_parser.get_sd_api().context);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IrdaAppRemoteManager::parse_button(std::string& str) {
|
|
||||||
char button_name[32];
|
|
||||||
char protocol_name[32];
|
|
||||||
uint32_t address;
|
|
||||||
uint32_t command;
|
|
||||||
|
|
||||||
int parsed = std::sscanf(
|
|
||||||
str.c_str(), "%31s %31s A:%lX C:%lX", button_name, protocol_name, &address, &command);
|
|
||||||
|
|
||||||
if(parsed != 4) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IrdaProtocol protocol = irda_get_protocol_by_name(protocol_name);
|
|
||||||
|
|
||||||
if(!irda_is_protocol_valid((IrdaProtocol)protocol)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int address_length = irda_get_protocol_address_length(protocol);
|
|
||||||
uint32_t address_mask = (1LU << (4 * address_length)) - 1;
|
|
||||||
if(address != (address & address_mask)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int command_length = irda_get_protocol_command_length(protocol);
|
|
||||||
uint32_t command_mask = (1LU << (4 * command_length)) - 1;
|
|
||||||
if(command != (command & command_mask)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IrdaMessage irda_message = {
|
|
||||||
.protocol = protocol,
|
|
||||||
.address = address,
|
|
||||||
.command = command,
|
|
||||||
.repeat = false,
|
|
||||||
};
|
|
||||||
remote->buttons.emplace_back(button_name, &irda_message);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getline(
|
|
||||||
const FS_Api* fs_api,
|
|
||||||
File& file,
|
|
||||||
char file_buf[],
|
|
||||||
size_t file_buf_size,
|
|
||||||
size_t& file_buf_cnt) {
|
|
||||||
std::string str;
|
|
||||||
size_t newline_index = 0;
|
|
||||||
bool found_eol = false;
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
if(file_buf_cnt > 0) {
|
|
||||||
size_t end_index = 0;
|
|
||||||
char* endline_ptr = (char*)memchr(file_buf, '\n', file_buf_cnt);
|
|
||||||
newline_index = endline_ptr - file_buf;
|
|
||||||
|
|
||||||
if(endline_ptr == 0) {
|
|
||||||
end_index = file_buf_cnt;
|
|
||||||
} else if(newline_index < file_buf_cnt) {
|
|
||||||
end_index = newline_index + 1;
|
|
||||||
found_eol = true;
|
|
||||||
} else {
|
|
||||||
furi_assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
str.append(file_buf, end_index);
|
|
||||||
memmove(file_buf, &file_buf[end_index], file_buf_cnt - end_index);
|
|
||||||
file_buf_cnt = file_buf_cnt - end_index;
|
|
||||||
if(found_eol) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
file_buf_cnt +=
|
|
||||||
fs_api->file.read(&file, &file_buf[file_buf_cnt], file_buf_size - file_buf_cnt);
|
|
||||||
if(file_buf_cnt == 0) {
|
|
||||||
break; // end of reading
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IrdaAppRemoteManager::get_remote_list(std::vector<std::string>& remote_names) const {
|
bool IrdaAppRemoteManager::get_remote_list(std::vector<std::string>& remote_names) const {
|
||||||
bool fs_res = false;
|
bool fs_res = false;
|
||||||
char name[128];
|
char name[128];
|
||||||
@ -314,17 +225,19 @@ bool IrdaAppRemoteManager::get_remote_list(std::vector<std::string>& remote_name
|
|||||||
std::string dirname(std::string("/") + irda_directory);
|
std::string dirname(std::string("/") + irda_directory);
|
||||||
remote_names.clear();
|
remote_names.clear();
|
||||||
|
|
||||||
fs_res = fs_api->dir.open(&dir, dirname.c_str());
|
IrdaAppFileParser file_parser;
|
||||||
|
fs_res = file_parser.get_fs_api().dir.open(&dir, dirname.c_str());
|
||||||
if(!fs_res) {
|
if(!fs_res) {
|
||||||
if(!check_fs()) {
|
if(!check_fs()) {
|
||||||
show_file_error_message("Cannot open\napplication directory");
|
file_parser.get_sd_api().show_error(
|
||||||
|
file_parser.get_sd_api().context, "Cannot open\napplication directory");
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true; // SD ok, but no files written yet
|
return true; // SD ok, but no files written yet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while(fs_api->dir.read(&dir, nullptr, name, sizeof(name)) && strlen(name)) {
|
while(file_parser.get_fs_api().dir.read(&dir, nullptr, name, sizeof(name)) && strlen(name)) {
|
||||||
std::string filename(name);
|
std::string filename(name);
|
||||||
auto extension_index = filename.rfind(irda_extension);
|
auto extension_index = filename.rfind(irda_extension);
|
||||||
if((extension_index == std::string::npos) ||
|
if((extension_index == std::string::npos) ||
|
||||||
@ -333,36 +246,41 @@ bool IrdaAppRemoteManager::get_remote_list(std::vector<std::string>& remote_name
|
|||||||
}
|
}
|
||||||
remote_names.push_back(filename.erase(extension_index));
|
remote_names.push_back(filename.erase(extension_index));
|
||||||
}
|
}
|
||||||
fs_api->dir.close(&dir);
|
file_parser.get_fs_api().dir.close(&dir);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IrdaAppRemoteManager::load(const std::string& name) {
|
bool IrdaAppRemoteManager::load(const std::string& name) {
|
||||||
bool fs_res = false;
|
bool fs_res = false;
|
||||||
|
IrdaAppFileParser file_parser;
|
||||||
File file;
|
File file;
|
||||||
|
|
||||||
fs_res = fs_api->file.open(&file, make_filename(name).c_str(), FSAM_READ, FSOM_OPEN_EXISTING);
|
fs_res = file_parser.get_fs_api().file.open(
|
||||||
|
&file, make_filename(name).c_str(), FSAM_READ, FSOM_OPEN_EXISTING);
|
||||||
if(!fs_res) {
|
if(!fs_res) {
|
||||||
show_file_error_message("Error opening file");
|
file_parser.get_sd_api().show_error(
|
||||||
|
file_parser.get_sd_api().context, "Error opening file");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
remote = std::make_unique<IrdaAppRemote>(name);
|
remote = std::make_unique<IrdaAppRemote>(name);
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
auto str = getline(fs_api, file, file_buf, sizeof(file_buf), file_buf_cnt);
|
auto message = file_parser.read_message(&file);
|
||||||
if(str.empty()) break;
|
if(!message) break;
|
||||||
parse_button(str);
|
remote->buttons.emplace_back(message->name, &message->message);
|
||||||
}
|
}
|
||||||
fs_api->file.close(&file);
|
file_parser.get_fs_api().file.close(&file);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IrdaAppRemoteManager::check_fs() const {
|
bool IrdaAppRemoteManager::check_fs() const {
|
||||||
// TODO: [FL-1431] Add return value to sd_ex_api->check_error() and replace get_fs_info().
|
// TODO: [FL-1431] Add return value to file_parser.get_sd_api().check_error() and replace get_fs_info().
|
||||||
auto fs_err = fs_api->common.get_fs_info(nullptr, nullptr);
|
IrdaAppFileParser file_parser;
|
||||||
if(fs_err != FSE_OK) show_file_error_message("SD card not found");
|
auto fs_err = file_parser.get_fs_api().common.get_fs_info(nullptr, nullptr);
|
||||||
|
if(fs_err != FSE_OK)
|
||||||
|
file_parser.get_sd_api().show_error(file_parser.get_sd_api().context, "SD card not found");
|
||||||
return fs_err == FSE_OK;
|
return fs_err == FSE_OK;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "sys/_stdint.h"
|
|
||||||
#include <algorithm>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <irda.h>
|
#include <irda.h>
|
||||||
@ -38,14 +35,7 @@ class IrdaAppRemoteManager {
|
|||||||
static const char* irda_directory;
|
static const char* irda_directory;
|
||||||
static const char* irda_extension;
|
static const char* irda_extension;
|
||||||
std::unique_ptr<IrdaAppRemote> remote;
|
std::unique_ptr<IrdaAppRemote> remote;
|
||||||
// TODO: make FS_Api and SdCard_Api unique_ptr
|
|
||||||
SdCard_Api* sd_ex_api;
|
|
||||||
FS_Api* fs_api;
|
|
||||||
void show_file_error_message(const char* error_text) const;
|
|
||||||
bool parse_button(std::string& str);
|
|
||||||
std::string make_filename(const std::string& name) const;
|
std::string make_filename(const std::string& name) const;
|
||||||
char file_buf[48];
|
|
||||||
size_t file_buf_cnt = 0;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool add_remote_with_button(const char* button_name, const IrdaMessage* message);
|
bool add_remote_with_button(const char* button_name, const IrdaMessage* message);
|
||||||
@ -63,8 +53,6 @@ public:
|
|||||||
const IrdaMessage* get_button_data(size_t button_index) const;
|
const IrdaMessage* get_button_data(size_t button_index) const;
|
||||||
bool delete_button(uint32_t index);
|
bool delete_button(uint32_t index);
|
||||||
bool delete_remote();
|
bool delete_remote();
|
||||||
IrdaAppRemoteManager();
|
|
||||||
~IrdaAppRemoteManager();
|
|
||||||
|
|
||||||
bool store();
|
bool store();
|
||||||
bool load(const std::string& name);
|
bool load(const std::string& name);
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
#include "irda.h"
|
#include "irda.h"
|
||||||
#include <api-hal-irda.h>
|
#include <api-hal-irda.h>
|
||||||
|
|
||||||
void IrdaAppSignalReceiver::irda_rx_callback(void* ctx, bool level, uint32_t duration) {
|
void IrdaAppSignalTransceiver::irda_rx_callback(void* ctx, bool level, uint32_t duration) {
|
||||||
IrdaAppEvent event;
|
IrdaAppEvent event;
|
||||||
const IrdaMessage* irda_message;
|
const IrdaMessage* irda_message;
|
||||||
IrdaAppSignalReceiver* this_ = static_cast<IrdaAppSignalReceiver*>(ctx);
|
IrdaAppSignalTransceiver* this_ = static_cast<IrdaAppSignalTransceiver*>(ctx);
|
||||||
|
|
||||||
irda_message = irda_decode(this_->decoder, level, duration);
|
irda_message = irda_decode(this_->decoder, level, duration);
|
||||||
if(irda_message) {
|
if(irda_message) {
|
||||||
@ -17,30 +17,30 @@ void IrdaAppSignalReceiver::irda_rx_callback(void* ctx, bool level, uint32_t dur
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IrdaAppSignalReceiver::IrdaAppSignalReceiver(void)
|
IrdaAppSignalTransceiver::IrdaAppSignalTransceiver(void)
|
||||||
: decoder(irda_alloc_decoder()) {
|
: decoder(irda_alloc_decoder()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
IrdaAppSignalReceiver::~IrdaAppSignalReceiver() {
|
IrdaAppSignalTransceiver::~IrdaAppSignalTransceiver() {
|
||||||
api_hal_irda_rx_irq_deinit();
|
api_hal_irda_rx_irq_deinit();
|
||||||
irda_free_decoder(decoder);
|
irda_free_decoder(decoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrdaAppSignalReceiver::capture_once_start(osMessageQueueId_t queue) {
|
void IrdaAppSignalTransceiver::capture_once_start(osMessageQueueId_t queue) {
|
||||||
event_queue = queue;
|
event_queue = queue;
|
||||||
irda_reset_decoder(decoder);
|
irda_reset_decoder(decoder);
|
||||||
api_hal_irda_rx_irq_init();
|
api_hal_irda_rx_irq_init();
|
||||||
api_hal_irda_rx_irq_set_callback(IrdaAppSignalReceiver::irda_rx_callback, this);
|
api_hal_irda_rx_irq_set_callback(IrdaAppSignalTransceiver::irda_rx_callback, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrdaAppSignalReceiver::capture_stop(void) {
|
void IrdaAppSignalTransceiver::capture_stop(void) {
|
||||||
api_hal_irda_rx_irq_deinit();
|
api_hal_irda_rx_irq_deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
IrdaMessage* IrdaAppSignalReceiver::get_last_message(void) {
|
IrdaMessage* IrdaAppSignalTransceiver::get_last_message(void) {
|
||||||
return &message;
|
return &message;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrdaAppSignalReceiver::send_message(const IrdaMessage* message) {
|
void IrdaAppSignalTransceiver::send_message(const IrdaMessage* message) const {
|
||||||
irda_send(message, 1);
|
irda_send(message, 1);
|
||||||
}
|
}
|
@ -1,14 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <irda.h>
|
#include <irda.h>
|
||||||
|
|
||||||
class IrdaAppSignalReceiver {
|
class IrdaAppSignalTransceiver {
|
||||||
public:
|
public:
|
||||||
IrdaAppSignalReceiver(void);
|
IrdaAppSignalTransceiver(void);
|
||||||
~IrdaAppSignalReceiver(void);
|
~IrdaAppSignalTransceiver(void);
|
||||||
void capture_once_start(osMessageQueueId_t event_queue);
|
void capture_once_start(osMessageQueueId_t event_queue);
|
||||||
void capture_stop(void);
|
void capture_stop(void);
|
||||||
IrdaMessage* get_last_message(void);
|
IrdaMessage* get_last_message(void);
|
||||||
void send_message(const IrdaMessage* message);
|
void send_message(const IrdaMessage* message) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
osMessageQueueId_t event_queue;
|
osMessageQueueId_t event_queue;
|
@ -1,7 +1,5 @@
|
|||||||
#include "furi.h"
|
#include "furi.h"
|
||||||
#include "gui/modules/button_menu.h"
|
#include "gui/modules/button_panel.h"
|
||||||
#include "gui/modules/dialog_ex.h"
|
|
||||||
#include "gui/modules/text_input.h"
|
|
||||||
#include "irda-app.hpp"
|
#include "irda-app.hpp"
|
||||||
#include <callback-connector.h>
|
#include <callback-connector.h>
|
||||||
|
|
||||||
@ -19,13 +17,17 @@ IrdaAppViewManager::IrdaAppViewManager() {
|
|||||||
popup = popup_alloc();
|
popup = popup_alloc();
|
||||||
dialog_ex = dialog_ex_alloc();
|
dialog_ex = dialog_ex_alloc();
|
||||||
text_input = text_input_alloc();
|
text_input = text_input_alloc();
|
||||||
|
button_panel = button_panel_alloc();
|
||||||
|
popup_brut = popup_brut_alloc();
|
||||||
|
|
||||||
|
add_view(ViewType::ButtonPanel, button_panel_get_view(button_panel));
|
||||||
add_view(ViewType::ButtonMenu, button_menu_get_view(button_menu));
|
add_view(ViewType::ButtonMenu, button_menu_get_view(button_menu));
|
||||||
add_view(ViewType::Submenu, submenu_get_view(submenu));
|
add_view(ViewType::Submenu, submenu_get_view(submenu));
|
||||||
add_view(ViewType::Popup, popup_get_view(popup));
|
add_view(ViewType::Popup, popup_get_view(popup));
|
||||||
add_view(ViewType::DialogEx, dialog_ex_get_view(dialog_ex));
|
add_view(ViewType::DialogEx, dialog_ex_get_view(dialog_ex));
|
||||||
add_view(ViewType::TextInput, text_input_get_view(text_input));
|
add_view(ViewType::TextInput, text_input_get_view(text_input));
|
||||||
|
|
||||||
|
view_set_previous_callback(button_panel_get_view(button_panel), callback);
|
||||||
view_set_previous_callback(button_menu_get_view(button_menu), callback);
|
view_set_previous_callback(button_menu_get_view(button_menu), callback);
|
||||||
view_set_previous_callback(submenu_get_view(submenu), callback);
|
view_set_previous_callback(submenu_get_view(submenu), callback);
|
||||||
view_set_previous_callback(popup_get_view(popup), callback);
|
view_set_previous_callback(popup_get_view(popup), callback);
|
||||||
@ -34,6 +36,8 @@ IrdaAppViewManager::IrdaAppViewManager() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IrdaAppViewManager::~IrdaAppViewManager() {
|
IrdaAppViewManager::~IrdaAppViewManager() {
|
||||||
|
view_dispatcher_remove_view(
|
||||||
|
view_dispatcher, static_cast<uint32_t>(IrdaAppViewManager::ViewType::ButtonPanel));
|
||||||
view_dispatcher_remove_view(
|
view_dispatcher_remove_view(
|
||||||
view_dispatcher, static_cast<uint32_t>(IrdaAppViewManager::ViewType::ButtonMenu));
|
view_dispatcher, static_cast<uint32_t>(IrdaAppViewManager::ViewType::ButtonMenu));
|
||||||
view_dispatcher_remove_view(
|
view_dispatcher_remove_view(
|
||||||
@ -47,9 +51,11 @@ IrdaAppViewManager::~IrdaAppViewManager() {
|
|||||||
|
|
||||||
submenu_free(submenu);
|
submenu_free(submenu);
|
||||||
popup_free(popup);
|
popup_free(popup);
|
||||||
|
button_panel_free(button_panel);
|
||||||
button_menu_free(button_menu);
|
button_menu_free(button_menu);
|
||||||
dialog_ex_free(dialog_ex);
|
dialog_ex_free(dialog_ex);
|
||||||
text_input_free(text_input);
|
text_input_free(text_input);
|
||||||
|
popup_brut_free(popup_brut);
|
||||||
|
|
||||||
view_dispatcher_free(view_dispatcher);
|
view_dispatcher_free(view_dispatcher);
|
||||||
furi_record_close("gui");
|
furi_record_close("gui");
|
||||||
@ -80,6 +86,14 @@ ButtonMenu* IrdaAppViewManager::get_button_menu() {
|
|||||||
return button_menu;
|
return button_menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ButtonPanel* IrdaAppViewManager::get_button_panel() {
|
||||||
|
return button_panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
IrdaAppPopupBrut* IrdaAppViewManager::get_popup_brut() {
|
||||||
|
return popup_brut;
|
||||||
|
}
|
||||||
|
|
||||||
osMessageQueueId_t IrdaAppViewManager::get_event_queue() {
|
osMessageQueueId_t IrdaAppViewManager::get_event_queue() {
|
||||||
return event_queue;
|
return event_queue;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include <gui/modules/submenu.h>
|
#include <gui/modules/submenu.h>
|
||||||
#include <gui/modules/popup.h>
|
#include <gui/modules/popup.h>
|
||||||
#include "irda-app.hpp"
|
#include "irda-app.hpp"
|
||||||
|
#include "view/irda-app-brut-view.h"
|
||||||
|
#include "gui/modules/button_panel.h"
|
||||||
|
|
||||||
class IrdaAppViewManager {
|
class IrdaAppViewManager {
|
||||||
public:
|
public:
|
||||||
@ -15,6 +17,7 @@ public:
|
|||||||
TextInput,
|
TextInput,
|
||||||
Submenu,
|
Submenu,
|
||||||
ButtonMenu,
|
ButtonMenu,
|
||||||
|
ButtonPanel,
|
||||||
Popup,
|
Popup,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -31,6 +34,8 @@ public:
|
|||||||
Popup* get_popup();
|
Popup* get_popup();
|
||||||
TextInput* get_text_input();
|
TextInput* get_text_input();
|
||||||
ButtonMenu* get_button_menu();
|
ButtonMenu* get_button_menu();
|
||||||
|
ButtonPanel* get_button_panel();
|
||||||
|
IrdaAppPopupBrut* get_popup_brut();
|
||||||
|
|
||||||
osMessageQueueId_t get_event_queue();
|
osMessageQueueId_t get_event_queue();
|
||||||
|
|
||||||
@ -44,6 +49,8 @@ private:
|
|||||||
Submenu* submenu;
|
Submenu* submenu;
|
||||||
Popup* popup;
|
Popup* popup;
|
||||||
ButtonMenu* button_menu;
|
ButtonMenu* button_menu;
|
||||||
|
ButtonPanel* button_panel;
|
||||||
|
IrdaAppPopupBrut* popup_brut;
|
||||||
|
|
||||||
osMessageQueueId_t event_queue;
|
osMessageQueueId_t event_queue;
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
#include "irda-app.hpp"
|
#include "irda-app.hpp"
|
||||||
#include "sys/_stdint.h"
|
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <input/input.h>
|
#include <input/input.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <callback-connector.h>
|
#include <callback-connector.h>
|
||||||
|
|
||||||
@ -101,8 +99,8 @@ IrdaAppRemoteManager* IrdaApp::get_remote_manager() {
|
|||||||
return &remote_manager;
|
return &remote_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
IrdaAppSignalReceiver* IrdaApp::get_receiver() {
|
IrdaAppSignalTransceiver* IrdaApp::get_transceiver() {
|
||||||
return &receiver;
|
return &transceiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrdaApp::set_text_store(uint8_t index, const char* text...) {
|
void IrdaApp::set_text_store(uint8_t index, const char* text...) {
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "sys/_stdint.h"
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <irda.h>
|
#include <irda.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
|
#include "irda/scene/irda-app-scene.hpp"
|
||||||
#include "irda-app-event.hpp"
|
#include "irda-app-event.hpp"
|
||||||
#include "scene/irda-app-scene.hpp"
|
#include "scene/irda-app-scene.hpp"
|
||||||
#include "irda-app-view-manager.hpp"
|
#include "irda-app-view-manager.hpp"
|
||||||
#include "irda-app-remote-manager.hpp"
|
#include "irda-app-remote-manager.hpp"
|
||||||
#include "irda-app-receiver.hpp"
|
#include "irda-app-transceiver.hpp"
|
||||||
#include <forward_list>
|
#include <forward_list>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <notification/notification-messages.h>
|
#include <notification/notification-messages.h>
|
||||||
@ -51,7 +51,7 @@ public:
|
|||||||
bool switch_to_previous_scene(uint8_t count = 1);
|
bool switch_to_previous_scene(uint8_t count = 1);
|
||||||
Scene get_previous_scene();
|
Scene get_previous_scene();
|
||||||
IrdaAppViewManager* get_view_manager();
|
IrdaAppViewManager* get_view_manager();
|
||||||
IrdaAppSignalReceiver* get_receiver();
|
IrdaAppSignalTransceiver* get_transceiver();
|
||||||
void set_text_store(uint8_t index, const char* text...);
|
void set_text_store(uint8_t index, const char* text...);
|
||||||
char* get_text_store(uint8_t index);
|
char* get_text_store(uint8_t index);
|
||||||
uint8_t get_text_store_size();
|
uint8_t get_text_store_size();
|
||||||
@ -103,7 +103,7 @@ private:
|
|||||||
uint32_t current_button;
|
uint32_t current_button;
|
||||||
|
|
||||||
NotificationApp* notification;
|
NotificationApp* notification;
|
||||||
IrdaAppSignalReceiver receiver;
|
IrdaAppSignalTransceiver transceiver;
|
||||||
IrdaAppViewManager view_manager;
|
IrdaAppViewManager view_manager;
|
||||||
IrdaAppRemoteManager remote_manager;
|
IrdaAppRemoteManager remote_manager;
|
||||||
|
|
||||||
@ -113,6 +113,8 @@ private:
|
|||||||
std::map<Scene, IrdaAppScene*> scenes = {
|
std::map<Scene, IrdaAppScene*> scenes = {
|
||||||
{Scene::Start, new IrdaAppSceneStart()},
|
{Scene::Start, new IrdaAppSceneStart()},
|
||||||
{Scene::Universal, new IrdaAppSceneUniversal()},
|
{Scene::Universal, new IrdaAppSceneUniversal()},
|
||||||
|
{Scene::UniversalTV, new IrdaAppSceneUniversalTV()},
|
||||||
|
// {Scene::UniversalAudio, new IrdaAppSceneUniversalAudio()},
|
||||||
{Scene::Learn, new IrdaAppSceneLearn()},
|
{Scene::Learn, new IrdaAppSceneLearn()},
|
||||||
{Scene::LearnSuccess, new IrdaAppSceneLearnSuccess()},
|
{Scene::LearnSuccess, new IrdaAppSceneLearnSuccess()},
|
||||||
{Scene::LearnEnterName, new IrdaAppSceneLearnEnterName()},
|
{Scene::LearnEnterName, new IrdaAppSceneLearnEnterName()},
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include "irda.h"
|
#include "irda.h"
|
||||||
#include "irda/scene/irda-app-scene.hpp"
|
#include "irda/scene/irda-app-scene.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
static void dialog_result_callback(DialogExResult result, void* context) {
|
static void dialog_result_callback(DialogExResult result, void* context) {
|
||||||
auto app = static_cast<IrdaApp*>(context);
|
auto app = static_cast<IrdaApp*>(context);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include "../irda-app.hpp"
|
#include "../irda-app.hpp"
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
void IrdaAppSceneEditRename::on_enter(IrdaApp* app) {
|
void IrdaAppSceneEditRename::on_enter(IrdaApp* app) {
|
||||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
#include "../irda-app.hpp"
|
#include "../irda-app.hpp"
|
||||||
#include <string>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <gui/modules/popup.h>
|
#include <gui/modules/popup.h>
|
||||||
|
|
||||||
void IrdaAppSceneLearnDoneAfter::on_enter(IrdaApp* app) {
|
void IrdaAppSceneLearnDoneAfter::on_enter(IrdaApp* app) {
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
#include "../irda-app.hpp"
|
#include "../irda-app.hpp"
|
||||||
#include <string>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void IrdaAppSceneLearnDone::on_enter(IrdaApp* app) {
|
void IrdaAppSceneLearnDone::on_enter(IrdaApp* app) {
|
||||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
#include "../irda-app.hpp"
|
#include "../irda-app.hpp"
|
||||||
#include "gui/modules/text_input.h"
|
#include "gui/modules/text_input.h"
|
||||||
#include <callback-connector.h>
|
|
||||||
#include <string>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void IrdaAppSceneLearnEnterName::on_enter(IrdaApp* app) {
|
void IrdaAppSceneLearnEnterName::on_enter(IrdaApp* app) {
|
||||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||||
TextInput* text_input = view_manager->get_text_input();
|
TextInput* text_input = view_manager->get_text_input();
|
||||||
|
|
||||||
auto receiver = app->get_receiver();
|
auto transceiver = app->get_transceiver();
|
||||||
auto message = receiver->get_last_message();
|
auto message = transceiver->get_last_message();
|
||||||
|
|
||||||
app->set_text_store(
|
app->set_text_store(
|
||||||
0,
|
0,
|
||||||
@ -34,14 +31,14 @@ bool IrdaAppSceneLearnEnterName::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
|||||||
|
|
||||||
if(event->type == IrdaAppEvent::Type::TextEditDone) {
|
if(event->type == IrdaAppEvent::Type::TextEditDone) {
|
||||||
auto remote_manager = app->get_remote_manager();
|
auto remote_manager = app->get_remote_manager();
|
||||||
auto receiver = app->get_receiver();
|
auto transceiver = app->get_transceiver();
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if(app->get_learn_new_remote()) {
|
if(app->get_learn_new_remote()) {
|
||||||
result = remote_manager->add_remote_with_button(
|
result = remote_manager->add_remote_with_button(
|
||||||
app->get_text_store(0), receiver->get_last_message());
|
app->get_text_store(0), transceiver->get_last_message());
|
||||||
} else {
|
} else {
|
||||||
result =
|
result = remote_manager->add_button(
|
||||||
remote_manager->add_button(app->get_text_store(0), receiver->get_last_message());
|
app->get_text_store(0), transceiver->get_last_message());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!result) {
|
if(!result) {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
#include "../irda-app.hpp"
|
#include "../irda-app.hpp"
|
||||||
#include "irda.h"
|
#include "irda.h"
|
||||||
#include <string>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
static void dialog_result_callback(DialogExResult result, void* context) {
|
static void dialog_result_callback(DialogExResult result, void* context) {
|
||||||
auto app = static_cast<IrdaApp*>(context);
|
auto app = static_cast<IrdaApp*>(context);
|
||||||
@ -19,8 +17,8 @@ void IrdaAppSceneLearnSuccess::on_enter(IrdaApp* app) {
|
|||||||
|
|
||||||
app->notify_green_on();
|
app->notify_green_on();
|
||||||
|
|
||||||
auto receiver = app->get_receiver();
|
auto transceiver = app->get_transceiver();
|
||||||
auto message = receiver->get_last_message();
|
auto message = transceiver->get_last_message();
|
||||||
|
|
||||||
app->set_text_store(0, "%s", irda_get_protocol_name(message->protocol));
|
app->set_text_store(0, "%s", irda_get_protocol_name(message->protocol));
|
||||||
app->set_text_store(
|
app->set_text_store(
|
||||||
@ -52,8 +50,8 @@ bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
|||||||
break;
|
break;
|
||||||
case DialogExResultCenter: {
|
case DialogExResultCenter: {
|
||||||
app->notify_space_blink();
|
app->notify_space_blink();
|
||||||
auto receiver = app->get_receiver();
|
auto transceiver = app->get_transceiver();
|
||||||
auto message = receiver->get_last_message();
|
auto message = transceiver->get_last_message();
|
||||||
irda_send(message, 1);
|
irda_send(message, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
void IrdaAppSceneLearn::on_enter(IrdaApp* app) {
|
void IrdaAppSceneLearn::on_enter(IrdaApp* app) {
|
||||||
auto view_manager = app->get_view_manager();
|
auto view_manager = app->get_view_manager();
|
||||||
auto receiver = app->get_receiver();
|
auto transceiver = app->get_transceiver();
|
||||||
auto event_queue = view_manager->get_event_queue();
|
auto event_queue = view_manager->get_event_queue();
|
||||||
|
|
||||||
receiver->capture_once_start(event_queue);
|
transceiver->capture_once_start(event_queue);
|
||||||
|
|
||||||
auto popup = view_manager->get_popup();
|
auto popup = view_manager->get_popup();
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ bool IrdaAppSceneRemote::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
|||||||
app->notify_click_and_blink();
|
app->notify_click_and_blink();
|
||||||
auto remote_manager = app->get_remote_manager();
|
auto remote_manager = app->get_remote_manager();
|
||||||
auto message = remote_manager->get_button_data(event->payload.menu_index);
|
auto message = remote_manager->get_button_data(event->payload.menu_index);
|
||||||
app->get_receiver()->send_message(message);
|
app->get_transceiver()->send_message(message);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(event->type == IrdaAppEvent::Type::Back) {
|
} else if(event->type == IrdaAppEvent::Type::Back) {
|
||||||
|
98
applications/irda/scene/irda-app-scene-universal-common.cpp
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#include "../irda-app.hpp"
|
||||||
|
#include "assets_icons.h"
|
||||||
|
#include "gui/modules/button_menu.h"
|
||||||
|
#include "gui/modules/button_panel.h"
|
||||||
|
#include "../view/irda-app-brut-view.h"
|
||||||
|
#include "gui/view.h"
|
||||||
|
#include "irda/irda-app-view-manager.hpp"
|
||||||
|
#include "irda/scene/irda-app-scene.hpp"
|
||||||
|
|
||||||
|
void IrdaAppSceneUniversalCommon::irda_app_item_callback(void* context, uint32_t index) {
|
||||||
|
IrdaApp* app = static_cast<IrdaApp*>(context);
|
||||||
|
IrdaAppEvent event;
|
||||||
|
|
||||||
|
event.type = IrdaAppEvent::Type::ButtonPanelPressed;
|
||||||
|
event.payload.menu_index = index;
|
||||||
|
|
||||||
|
app->get_view_manager()->send_event(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool irda_popup_brut_input_callback(InputEvent* event, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
furi_assert(event);
|
||||||
|
auto app = static_cast<IrdaApp*>(context);
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if((event->type == InputTypeShort) && (event->key == InputKeyBack)) {
|
||||||
|
consumed = true;
|
||||||
|
IrdaAppEvent irda_event;
|
||||||
|
|
||||||
|
irda_event.type = IrdaAppEvent::Type::ButtonPanelPopupBackPressed;
|
||||||
|
app->get_view_manager()->send_event(&irda_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrdaAppSceneUniversalCommon::remove_popup(IrdaApp* app) {
|
||||||
|
auto button_panel = app->get_view_manager()->get_button_panel();
|
||||||
|
button_panel_set_popup_draw_callback(button_panel, NULL, NULL);
|
||||||
|
button_panel_set_popup_input_callback(button_panel, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrdaAppSceneUniversalCommon::show_popup(IrdaApp* app, int record_amount) {
|
||||||
|
auto button_panel = app->get_view_manager()->get_button_panel();
|
||||||
|
auto popup_brut = app->get_view_manager()->get_popup_brut();
|
||||||
|
popup_brut_set_progress_max(popup_brut, record_amount);
|
||||||
|
button_panel_set_popup_draw_callback(button_panel, popup_brut_draw_callback, popup_brut);
|
||||||
|
button_panel_set_popup_input_callback(button_panel, irda_popup_brut_input_callback, app);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrdaAppSceneUniversalCommon::progress_popup(IrdaApp* app) {
|
||||||
|
popup_brut_increase_progress(app->get_view_manager()->get_popup_brut());
|
||||||
|
auto button_panel = app->get_view_manager()->get_button_panel();
|
||||||
|
with_view_model_cpp(button_panel_get_view(button_panel), void*, model, { return true; });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IrdaAppSceneUniversalCommon::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event->type == IrdaAppEvent::Type::Tick) {
|
||||||
|
if(brute_force_started) {
|
||||||
|
if(brute_force.send_next_bruteforce(*app->get_transceiver())) {
|
||||||
|
progress_popup(app);
|
||||||
|
} else {
|
||||||
|
brute_force.stop_bruteforce();
|
||||||
|
brute_force_started = false;
|
||||||
|
remove_popup(app);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(event->type == IrdaAppEvent::Type::ButtonPanelPopupBackPressed) {
|
||||||
|
consumed = true;
|
||||||
|
brute_force_started = false;
|
||||||
|
brute_force.stop_bruteforce();
|
||||||
|
remove_popup(app);
|
||||||
|
} else if(event->type == IrdaAppEvent::Type::ButtonPanelPressed) {
|
||||||
|
int record_amount = 0;
|
||||||
|
if(brute_force.start_bruteforce(event->payload.menu_index, record_amount)) {
|
||||||
|
if(record_amount > 0) {
|
||||||
|
brute_force_started = true;
|
||||||
|
show_popup(app, record_amount);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
app->switch_to_previous_scene();
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrdaAppSceneUniversalCommon::on_exit(IrdaApp* app) {
|
||||||
|
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||||
|
ButtonPanel* button_panel = view_manager->get_button_panel();
|
||||||
|
button_panel_clean(button_panel);
|
||||||
|
}
|
61
applications/irda/scene/irda-app-scene-universal-tv.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include "irda/scene/irda-app-scene.hpp"
|
||||||
|
#include "irda/irda-app.hpp"
|
||||||
|
|
||||||
|
void IrdaAppSceneUniversalTV::on_enter(IrdaApp* app) {
|
||||||
|
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||||
|
ButtonPanel* button_panel = view_manager->get_button_panel();
|
||||||
|
button_panel_reserve(button_panel, 2, 3);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel, i, 0, 0, 3, 19, I_Power_25x27, I_Power_hvr_25x27, irda_app_item_callback, app);
|
||||||
|
brute_force.add_record(i, "POWER");
|
||||||
|
++i;
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel, i, 1, 0, 36, 19, I_Mute_25x27, I_Mute_hvr_25x27, irda_app_item_callback, app);
|
||||||
|
brute_force.add_record(i, "MUTE");
|
||||||
|
++i;
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel,
|
||||||
|
i,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
66,
|
||||||
|
I_Vol_up_25x27,
|
||||||
|
I_Vol_up_hvr_25x27,
|
||||||
|
irda_app_item_callback,
|
||||||
|
app);
|
||||||
|
brute_force.add_record(i, "VOL+");
|
||||||
|
++i;
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel, i, 1, 1, 36, 66, I_Up_25x27, I_Up_hvr_25x27, irda_app_item_callback, app);
|
||||||
|
brute_force.add_record(i, "CH+");
|
||||||
|
++i;
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel,
|
||||||
|
i,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
98,
|
||||||
|
I_Vol_down_25x27,
|
||||||
|
I_Vol_down_hvr_25x27,
|
||||||
|
irda_app_item_callback,
|
||||||
|
app);
|
||||||
|
brute_force.add_record(i, "VOL-");
|
||||||
|
++i;
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel, i, 1, 2, 36, 98, I_Down_25x27, I_Down_hvr_25x27, irda_app_item_callback, app);
|
||||||
|
brute_force.add_record(i, "CH-");
|
||||||
|
|
||||||
|
button_panel_add_label(button_panel, 6, 11, FontPrimary, "TV remote");
|
||||||
|
button_panel_add_label(button_panel, 9, 64, FontSecondary, "Vol");
|
||||||
|
button_panel_add_label(button_panel, 43, 64, FontSecondary, "Ch");
|
||||||
|
|
||||||
|
view_manager->switch_to(IrdaAppViewManager::ViewType::ButtonPanel);
|
||||||
|
|
||||||
|
if(!brute_force.calculate_messages()) {
|
||||||
|
app->switch_to_previous_scene();
|
||||||
|
}
|
||||||
|
}
|
@ -37,7 +37,7 @@ bool IrdaAppSceneUniversal::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
|||||||
submenu_item_selected = event->payload.menu_index;
|
submenu_item_selected = event->payload.menu_index;
|
||||||
switch(event->payload.menu_index) {
|
switch(event->payload.menu_index) {
|
||||||
case SubmenuIndexUniversalTV:
|
case SubmenuIndexUniversalTV:
|
||||||
// app->switch_to_next_scene(IrdaApp::Scene::UniversalTV);
|
app->switch_to_next_scene(IrdaApp::Scene::UniversalTV);
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexUniversalAudio:
|
case SubmenuIndexUniversalAudio:
|
||||||
// app->switch_to_next_scene(IrdaApp::Scene::UniversalAudio);
|
// app->switch_to_next_scene(IrdaApp::Scene::UniversalAudio);
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../irda-app.hpp"
|
#include "../irda-app-event.hpp"
|
||||||
#include <api-hal-irda.h>
|
#include <api-hal-irda.h>
|
||||||
#include "irda.h"
|
#include "irda.h"
|
||||||
#include <gui/elements.h>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "../irda-app-brute-force.hpp"
|
||||||
|
|
||||||
|
|
||||||
class IrdaApp;
|
class IrdaApp;
|
||||||
|
|
||||||
@ -137,3 +138,31 @@ public:
|
|||||||
void on_exit(IrdaApp* app) final;
|
void on_exit(IrdaApp* app) final;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IrdaAppSceneUniversalCommon : public IrdaAppScene {
|
||||||
|
bool brute_force_started = false;
|
||||||
|
protected:
|
||||||
|
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||||
|
void on_exit(IrdaApp* app) final;
|
||||||
|
IrdaAppBruteForce brute_force;
|
||||||
|
void remove_popup(IrdaApp* app);
|
||||||
|
void show_popup(IrdaApp* app, int record_amount);
|
||||||
|
void progress_popup(IrdaApp* app);
|
||||||
|
static void irda_app_item_callback(void* context, uint32_t index);
|
||||||
|
IrdaAppSceneUniversalCommon(const char* filename) : brute_force(filename) {}
|
||||||
|
~IrdaAppSceneUniversalCommon() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class IrdaAppSceneUniversalTV : public IrdaAppSceneUniversalCommon {
|
||||||
|
public:
|
||||||
|
void on_enter(IrdaApp* app) final;
|
||||||
|
IrdaAppSceneUniversalTV() : IrdaAppSceneUniversalCommon("/irda/universal/tv.ir") {}
|
||||||
|
~IrdaAppSceneUniversalTV() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class IrdaAppSceneUniversalAudio : public IrdaAppSceneUniversalCommon {
|
||||||
|
public:
|
||||||
|
void on_enter(IrdaApp* app) final;
|
||||||
|
IrdaAppSceneUniversalAudio() : IrdaAppSceneUniversalCommon("/irda/universal/audio.ir") {}
|
||||||
|
~IrdaAppSceneUniversalAudio() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
82
applications/irda/view/irda-app-brut-view.c
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#include "api-hal-resources.h"
|
||||||
|
#include "assets_icons.h"
|
||||||
|
#include "gui/canvas.h"
|
||||||
|
#include "gui/view.h"
|
||||||
|
#include "input/input.h"
|
||||||
|
#include <gui/elements.h>
|
||||||
|
#include <furi.h>
|
||||||
|
#include "irda-app-brut-view.h"
|
||||||
|
#include "gui/modules/button_panel.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct IrdaAppPopupBrut {
|
||||||
|
uint16_t progress;
|
||||||
|
uint16_t progress_max;
|
||||||
|
char percents_string_storage[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
void popup_brut_increase_progress(IrdaAppPopupBrut* popup_brut) {
|
||||||
|
furi_assert(popup_brut);
|
||||||
|
|
||||||
|
if(popup_brut->progress < popup_brut->progress_max)
|
||||||
|
++popup_brut->progress;
|
||||||
|
else
|
||||||
|
furi_assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void popup_brut_draw_callback(Canvas* canvas, void* context) {
|
||||||
|
furi_assert(canvas);
|
||||||
|
furi_assert(context);
|
||||||
|
IrdaAppPopupBrut* popup_brut = (IrdaAppPopupBrut*)context;
|
||||||
|
uint8_t x = 0;
|
||||||
|
uint8_t width = 64;
|
||||||
|
uint8_t x_max = x + width - 1;
|
||||||
|
uint8_t y = 36;
|
||||||
|
uint8_t height = 59;
|
||||||
|
uint8_t y_max = y + height - 1;
|
||||||
|
|
||||||
|
canvas_invert_color(canvas);
|
||||||
|
canvas_draw_rbox(canvas, x + 1, y + 1, width - 2, height - 2, 3);
|
||||||
|
canvas_invert_color(canvas);
|
||||||
|
canvas_draw_rframe(canvas, x, y, width, height, 3);
|
||||||
|
canvas_draw_rframe(canvas, x + 1, y + 1, width - 2, height - 2, 3);
|
||||||
|
canvas_draw_line(canvas, x + 2, y + 1, x + 2, y + 3);
|
||||||
|
canvas_draw_line(canvas, x + 1, y + 2, x + 3, y + 2);
|
||||||
|
canvas_draw_line(canvas, x_max - 2, y + 1, x_max - 2, y + 3);
|
||||||
|
canvas_draw_line(canvas, x_max - 1, y + 2, x_max - 3, y + 2);
|
||||||
|
canvas_draw_line(canvas, x + 2, y_max - 1, x + 2, y_max - 3);
|
||||||
|
canvas_draw_line(canvas, x + 1, y_max - 2, x + 3, y_max - 2);
|
||||||
|
canvas_draw_line(canvas, x_max - 2, y_max - 1, x_max - 2, y_max - 3);
|
||||||
|
canvas_draw_line(canvas, x_max - 1, y_max - 2, x_max - 3, y_max - 2);
|
||||||
|
|
||||||
|
elements_progress_bar(
|
||||||
|
canvas, x + 4, y + 19, x_max - 8, popup_brut->progress, popup_brut->progress_max);
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
canvas_draw_str(canvas, x + 15, y + 12, "Sending ...");
|
||||||
|
canvas_draw_icon_name(canvas, x + 11, y_max - 14, I_Back_15x10);
|
||||||
|
|
||||||
|
uint8_t percent_value = 100 * popup_brut->progress / popup_brut->progress_max;
|
||||||
|
snprintf(
|
||||||
|
popup_brut->percents_string_storage,
|
||||||
|
sizeof(popup_brut->percents_string_storage),
|
||||||
|
"%d%%",
|
||||||
|
percent_value);
|
||||||
|
elements_multiline_text_aligned(
|
||||||
|
canvas, x + 32, y + 40, AlignCenter, AlignBottom, popup_brut->percents_string_storage);
|
||||||
|
canvas_draw_str(canvas, x + 30, y_max - 5, "= stop");
|
||||||
|
}
|
||||||
|
|
||||||
|
void popup_brut_set_progress_max(IrdaAppPopupBrut* popup_brut, uint16_t progress_max) {
|
||||||
|
furi_assert(popup_brut);
|
||||||
|
popup_brut->progress = 0;
|
||||||
|
popup_brut->progress_max = progress_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
IrdaAppPopupBrut* popup_brut_alloc(void) {
|
||||||
|
return (IrdaAppPopupBrut*)furi_alloc(sizeof(IrdaAppPopupBrut));
|
||||||
|
}
|
||||||
|
|
||||||
|
void popup_brut_free(IrdaAppPopupBrut* popup_brut) {
|
||||||
|
free(popup_brut);
|
||||||
|
}
|
18
applications/irda/view/irda-app-brut-view.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <gui/view.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct IrdaAppPopupBrut IrdaAppPopupBrut;
|
||||||
|
|
||||||
|
void popup_brut_increase_progress(IrdaAppPopupBrut* popup_brut);
|
||||||
|
IrdaAppPopupBrut* popup_brut_alloc();
|
||||||
|
void popup_brut_free(IrdaAppPopupBrut* popup_brut);
|
||||||
|
void popup_brut_draw_callback(Canvas* canvas, void* model);
|
||||||
|
void popup_brut_set_progress_max(IrdaAppPopupBrut* popup_brut, uint16_t progress_max);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -3,129 +3,143 @@
|
|||||||
#include <gui/icon.h>
|
#include <gui/icon.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
I_SDQuestion_35x43,
|
I_Down_hvr_25x27,
|
||||||
I_SDError_43x35,
|
I_Vol_down_hvr_25x27,
|
||||||
I_Health_16x16,
|
I_Down_25x27,
|
||||||
I_FaceCharging_29x14,
|
I_Fill_marker_7x7,
|
||||||
I_BatteryBody_52x28,
|
I_Vol_down_25x27,
|
||||||
I_Voltage_16x16,
|
I_Vol_up_25x27,
|
||||||
I_Temperature_16x16,
|
I_Up_hvr_25x27,
|
||||||
I_FaceNopower_29x14,
|
I_Vol_up_hvr_25x27,
|
||||||
I_FaceNormal_29x14,
|
|
||||||
I_Battery_16x16,
|
|
||||||
I_FaceConfused_29x14,
|
|
||||||
I_PassportBottom_128x17,
|
|
||||||
I_DoorLeft_8x56,
|
|
||||||
I_DoorLocked_10x56,
|
|
||||||
I_DoorRight_8x56,
|
|
||||||
I_DoorLeft_70x55,
|
|
||||||
I_PassportLeft_6x47,
|
|
||||||
I_DoorRight_70x55,
|
|
||||||
I_LockPopup_100x49,
|
|
||||||
I_WalkR2_32x32,
|
|
||||||
I_WalkL2_32x32,
|
|
||||||
I_WalkRB1_32x32,
|
|
||||||
I_Home_painting_17x20,
|
|
||||||
I_WalkLB2_32x32,
|
|
||||||
I_Sofa_40x13,
|
|
||||||
I_WalkLB1_32x32,
|
|
||||||
I_PC_22x29,
|
|
||||||
I_WalkL1_32x32,
|
|
||||||
I_TV_20x20,
|
|
||||||
I_WalkR1_32x32,
|
|
||||||
I_WalkRB2_32x32,
|
|
||||||
I_TV_20x24,
|
|
||||||
I_dir_10px,
|
|
||||||
I_Nfc_10px,
|
|
||||||
I_sub1_10px,
|
|
||||||
I_ir_10px,
|
|
||||||
I_ibutt_10px,
|
|
||||||
I_unknown_10px,
|
|
||||||
I_ble_10px,
|
|
||||||
I_125_10px,
|
|
||||||
I_FX_SittingB_40x27,
|
|
||||||
I_BigGames_24x24,
|
|
||||||
I_BigProfile_24x24,
|
|
||||||
I_DolphinOkay_41x43,
|
|
||||||
I_DolphinFirstStart5_45x53,
|
|
||||||
I_DolphinFirstStart4_67x53,
|
|
||||||
I_DolphinFirstStart2_59x51,
|
|
||||||
I_DolphinFirstStart0_70x53,
|
|
||||||
I_DolphinFirstStart6_58x54,
|
|
||||||
I_DolphinFirstStart1_59x53,
|
|
||||||
I_DolphinFirstStart8_56x51,
|
|
||||||
I_DolphinFirstStart7_61x51,
|
|
||||||
I_Flipper_young_80x60,
|
|
||||||
I_BigBurger_24x24,
|
|
||||||
I_FX_Bang_32x6,
|
|
||||||
I_DolphinFirstStart3_57x48,
|
|
||||||
I_BadUsb_9x8,
|
|
||||||
I_PlaceholderR_30x13,
|
|
||||||
I_Background_128x8,
|
|
||||||
I_Lock_8x8,
|
|
||||||
I_Battery_26x8,
|
|
||||||
I_PlaceholderL_11x13,
|
|
||||||
I_Battery_19x8,
|
|
||||||
I_SDcardMounted_11x8,
|
|
||||||
I_SDcardFail_11x8,
|
|
||||||
I_USBConnected_15x8,
|
|
||||||
I_Bluetooth_5x8,
|
|
||||||
I_Background_128x11,
|
|
||||||
I_IrdaArrowUp_4x8,
|
|
||||||
I_IrdaLearnShort_128x31,
|
I_IrdaLearnShort_128x31,
|
||||||
|
I_IrdaSend_128x64,
|
||||||
|
I_Mute_hvr_25x27,
|
||||||
|
I_Back_15x10,
|
||||||
|
I_Up_25x27,
|
||||||
|
I_IrdaArrowUp_4x8,
|
||||||
|
I_Mute_25x27,
|
||||||
|
I_Power_25x27,
|
||||||
|
I_IrdaSendShort_128x34,
|
||||||
I_IrdaArrowDown_4x8,
|
I_IrdaArrowDown_4x8,
|
||||||
I_IrdaLearn_128x64,
|
I_IrdaLearn_128x64,
|
||||||
I_IrdaSend_128x64,
|
I_Power_hvr_25x27,
|
||||||
I_IrdaSendShort_128x34,
|
|
||||||
I_passport_happy1_43x45,
|
|
||||||
I_passport_bad3_43x45,
|
|
||||||
I_passport_okay2_43x45,
|
|
||||||
I_passport_bad2_43x45,
|
|
||||||
I_passport_okay3_43x45,
|
|
||||||
I_passport_bad1_43x45,
|
|
||||||
I_passport_happy3_43x45,
|
|
||||||
I_passport_happy2_43x45,
|
|
||||||
I_passport_okay1_43x45,
|
|
||||||
I_ButtonRightSmall_3x5,
|
|
||||||
I_ButtonLeft_4x7,
|
|
||||||
I_ButtonLeftSmall_3x5,
|
|
||||||
I_ButtonRight_4x7,
|
|
||||||
I_ButtonCenter_7x7,
|
|
||||||
A_Games_14,
|
A_Games_14,
|
||||||
A_Plugins_14,
|
A_Power_14,
|
||||||
|
A_GPIO_14,
|
||||||
|
A_Bluetooth_14,
|
||||||
A_Passport_14,
|
A_Passport_14,
|
||||||
A_Sub1ghz_14,
|
A_Sub1ghz_14,
|
||||||
A_NFC_14,
|
|
||||||
A_Tamagotchi_14,
|
|
||||||
A_FileManager_14,
|
|
||||||
A_125khz_14,
|
|
||||||
A_U2F_14,
|
A_U2F_14,
|
||||||
A_Infrared_14,
|
A_Infrared_14,
|
||||||
A_Power_14,
|
|
||||||
A_Settings_14,
|
A_Settings_14,
|
||||||
|
A_125khz_14,
|
||||||
A_iButton_14,
|
A_iButton_14,
|
||||||
A_Bluetooth_14,
|
A_FileManager_14,
|
||||||
A_GPIO_14,
|
A_Tamagotchi_14,
|
||||||
I_DolphinMafia_115x62,
|
A_NFC_14,
|
||||||
I_DolphinExcited_64x63,
|
A_Plugins_14,
|
||||||
I_iButtonDolphinSuccess_109x60,
|
I_SDQuestion_35x43,
|
||||||
I_iButtonDolphinVerySuccess_108x52,
|
I_SDError_43x35,
|
||||||
|
I_BatteryBody_52x28,
|
||||||
|
I_FaceCharging_29x14,
|
||||||
|
I_Health_16x16,
|
||||||
|
I_Temperature_16x16,
|
||||||
|
I_Battery_16x16,
|
||||||
|
I_FaceConfused_29x14,
|
||||||
|
I_FaceNormal_29x14,
|
||||||
|
I_Voltage_16x16,
|
||||||
|
I_FaceNopower_29x14,
|
||||||
I_iButtonKey_49x44,
|
I_iButtonKey_49x44,
|
||||||
I_DolphinNice_96x59,
|
I_DolphinExcited_64x63,
|
||||||
I_DolphinWait_61x59,
|
I_DolphinWait_61x59,
|
||||||
|
I_iButtonDolphinVerySuccess_108x52,
|
||||||
|
I_DolphinMafia_115x62,
|
||||||
|
I_DolphinNice_96x59,
|
||||||
|
I_iButtonDolphinSuccess_109x60,
|
||||||
|
I_Background_128x11,
|
||||||
|
I_Lock_8x8,
|
||||||
|
I_Battery_26x8,
|
||||||
|
I_Battery_19x8,
|
||||||
|
I_USBConnected_15x8,
|
||||||
|
I_Background_128x8,
|
||||||
|
I_BadUsb_9x8,
|
||||||
|
I_PlaceholderL_11x13,
|
||||||
|
I_SDcardFail_11x8,
|
||||||
|
I_Bluetooth_5x8,
|
||||||
|
I_PlaceholderR_30x13,
|
||||||
|
I_SDcardMounted_11x8,
|
||||||
|
I_WalkR2_32x32,
|
||||||
|
I_WalkRB2_32x32,
|
||||||
|
I_WalkR1_32x32,
|
||||||
|
I_PC_22x29,
|
||||||
|
I_WalkRB1_32x32,
|
||||||
|
I_WalkL2_32x32,
|
||||||
|
I_WalkLB1_32x32,
|
||||||
|
I_WalkLB2_32x32,
|
||||||
|
I_TV_20x20,
|
||||||
|
I_TV_20x24,
|
||||||
|
I_Home_painting_17x20,
|
||||||
|
I_Sofa_40x13,
|
||||||
|
I_WalkL1_32x32,
|
||||||
|
I_passport_bad1_43x45,
|
||||||
|
I_passport_bad3_43x45,
|
||||||
|
I_passport_happy3_43x45,
|
||||||
|
I_passport_happy2_43x45,
|
||||||
|
I_passport_okay3_43x45,
|
||||||
|
I_passport_okay2_43x45,
|
||||||
|
I_passport_happy1_43x45,
|
||||||
|
I_passport_bad2_43x45,
|
||||||
|
I_passport_okay1_43x45,
|
||||||
A_Wink_128x64,
|
A_Wink_128x64,
|
||||||
A_MDWL_32x32,
|
|
||||||
A_MDWR_32x32,
|
|
||||||
A_WatchingTV_128x64,
|
|
||||||
A_MDI_32x32,
|
A_MDI_32x32,
|
||||||
A_MDWRB_32x32,
|
|
||||||
A_MDIB_32x32,
|
|
||||||
A_FX_Sitting_40x27,
|
A_FX_Sitting_40x27,
|
||||||
|
A_MDWR_32x32,
|
||||||
|
A_MDWL_32x32,
|
||||||
|
A_MDWRB_32x32,
|
||||||
A_MDWLB_32x32,
|
A_MDWLB_32x32,
|
||||||
I_KeySave_24x11,
|
A_MDIB_32x32,
|
||||||
I_KeyBackspaceSelected_16x9,
|
A_WatchingTV_128x64,
|
||||||
|
I_PassportBottom_128x17,
|
||||||
|
I_DoorLeft_70x55,
|
||||||
|
I_DoorLeft_8x56,
|
||||||
|
I_DoorRight_70x55,
|
||||||
|
I_DoorRight_8x56,
|
||||||
|
I_DoorLocked_10x56,
|
||||||
|
I_PassportLeft_6x47,
|
||||||
|
I_LockPopup_100x49,
|
||||||
|
I_sub1_10px,
|
||||||
|
I_ir_10px,
|
||||||
|
I_unknown_10px,
|
||||||
|
I_ibutt_10px,
|
||||||
|
I_Nfc_10px,
|
||||||
|
I_ble_10px,
|
||||||
|
I_125_10px,
|
||||||
|
I_dir_10px,
|
||||||
|
I_ButtonCenter_7x7,
|
||||||
|
I_ButtonLeft_4x7,
|
||||||
|
I_ButtonLeftSmall_3x5,
|
||||||
|
I_ButtonRightSmall_3x5,
|
||||||
|
I_ButtonRight_4x7,
|
||||||
|
I_DolphinFirstStart2_59x51,
|
||||||
|
I_BigBurger_24x24,
|
||||||
|
I_DolphinFirstStart6_58x54,
|
||||||
|
I_Flipper_young_80x60,
|
||||||
|
I_FX_Bang_32x6,
|
||||||
|
I_DolphinFirstStart8_56x51,
|
||||||
|
I_DolphinFirstStart1_59x53,
|
||||||
|
I_DolphinOkay_41x43,
|
||||||
|
I_DolphinFirstStart3_57x48,
|
||||||
|
I_DolphinFirstStart5_45x53,
|
||||||
|
I_DolphinFirstStart7_61x51,
|
||||||
|
I_FX_SittingB_40x27,
|
||||||
|
I_BigProfile_24x24,
|
||||||
|
I_DolphinFirstStart0_70x53,
|
||||||
|
I_BigGames_24x24,
|
||||||
|
I_DolphinFirstStart4_67x53,
|
||||||
I_KeySaveSelected_24x11,
|
I_KeySaveSelected_24x11,
|
||||||
I_KeyBackspace_16x9,
|
I_KeyBackspace_16x9,
|
||||||
|
I_KeyBackspaceSelected_16x9,
|
||||||
|
I_KeySave_24x11,
|
||||||
} IconName;
|
} IconName;
|
||||||
|
|
||||||
Icon * assets_icons_get(IconName name);
|
Icon * assets_icons_get(IconName name);
|
||||||
|
BIN
assets/icons/Irda/Back_15x10.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/icons/Irda/Down_25x27.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/Irda/Down_hvr_25x27.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/icons/Irda/Fill-marker_7x7.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/icons/Irda/Mute_25x27.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/Irda/Mute_hvr_25x27.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/Irda/Power_25x27.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/Irda/Power_hvr_25x27.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/Irda/Up_25x27.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/Irda/Up_hvr_25x27.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/icons/Irda/Vol_down_25x27.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/icons/Irda/Vol_down_hvr_25x27.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/icons/Irda/Vol_up_25x27.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/icons/Irda/Vol_up_hvr_25x27.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
39
lib/file_reader/file_reader.cpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#include "file_reader/file_reader.hpp"
|
||||||
|
|
||||||
|
std::string FileReader::getline(File* file) {
|
||||||
|
std::string str;
|
||||||
|
size_t newline_index = 0;
|
||||||
|
bool found_eol = false;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
if(file_buf_cnt > 0) {
|
||||||
|
size_t end_index = 0;
|
||||||
|
char* endline_ptr = (char*)memchr(file_buf, '\n', file_buf_cnt);
|
||||||
|
newline_index = endline_ptr - file_buf;
|
||||||
|
|
||||||
|
if(endline_ptr == 0) {
|
||||||
|
end_index = file_buf_cnt;
|
||||||
|
} else if(newline_index < file_buf_cnt) {
|
||||||
|
end_index = newline_index + 1;
|
||||||
|
found_eol = true;
|
||||||
|
} else {
|
||||||
|
furi_assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
str.append(file_buf, end_index);
|
||||||
|
memmove(file_buf, &file_buf[end_index], file_buf_cnt - end_index);
|
||||||
|
file_buf_cnt = file_buf_cnt - end_index;
|
||||||
|
if(found_eol) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_buf_cnt +=
|
||||||
|
fs_api->file.read(file, &file_buf[file_buf_cnt], sizeof(file_buf) - file_buf_cnt);
|
||||||
|
if(file_buf_cnt == 0) {
|
||||||
|
break; // end of reading
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
39
lib/file_reader/file_reader.hpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include "sd-card-api.h"
|
||||||
|
#include "filesystem-api.h"
|
||||||
|
|
||||||
|
class FileReader {
|
||||||
|
private:
|
||||||
|
char file_buf[48];
|
||||||
|
size_t file_buf_cnt = 0;
|
||||||
|
SdCard_Api* sd_ex_api;
|
||||||
|
FS_Api* fs_api;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FileReader() {
|
||||||
|
sd_ex_api = static_cast<SdCard_Api*>(furi_record_open("sdcard-ex"));
|
||||||
|
fs_api = static_cast<FS_Api*>(furi_record_open("sdcard"));
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
~FileReader() {
|
||||||
|
furi_record_close("sdcard");
|
||||||
|
furi_record_close("sdcard-ex");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getline(File* file);
|
||||||
|
|
||||||
|
void reset(void) {
|
||||||
|
file_buf_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SdCard_Api& get_sd_api() {
|
||||||
|
return *sd_ex_api;
|
||||||
|
}
|
||||||
|
|
||||||
|
FS_Api& get_fs_api() {
|
||||||
|
return *fs_api;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -30,6 +30,7 @@ void irda_encoder_samsung32_encode(uint32_t addr, uint32_t cmd, bool repeat) {
|
|||||||
uint8_t command = cmd & 0xFF;
|
uint8_t command = cmd & 0xFF;
|
||||||
uint8_t command_inverse = (uint8_t) ~command;
|
uint8_t command_inverse = (uint8_t) ~command;
|
||||||
|
|
||||||
|
irda_encode_space(&encoder_timings, 100);
|
||||||
if (!repeat) {
|
if (!repeat) {
|
||||||
irda_encode_samsung32_preamble();
|
irda_encode_samsung32_preamble();
|
||||||
irda_encode_byte(&encoder_timings, address);
|
irda_encode_byte(&encoder_timings, address);
|
||||||
|
@ -87,6 +87,10 @@ C_SOURCES += $(wildcard $(LIB_DIR)/drivers/*.c)
|
|||||||
CFLAGS += -I$(LIB_DIR)/version
|
CFLAGS += -I$(LIB_DIR)/version
|
||||||
C_SOURCES += $(LIB_DIR)/version/version.c
|
C_SOURCES += $(LIB_DIR)/version/version.c
|
||||||
|
|
||||||
|
#file reader
|
||||||
|
CFLAGS += -I$(LIB_DIR)/file_reader
|
||||||
|
CPP_SOURCES += $(wildcard $(LIB_DIR)/file_reader/*.cpp)
|
||||||
|
|
||||||
#irda lib
|
#irda lib
|
||||||
CFLAGS += -I$(LIB_DIR)/irda
|
CFLAGS += -I$(LIB_DIR)/irda
|
||||||
C_SOURCES += $(wildcard $(LIB_DIR)/irda/*.c)
|
C_SOURCES += $(wildcard $(LIB_DIR)/irda/*.c)
|
||||||
|