mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-14 06:42:58 +08:00
931 lines
31 KiB
C
931 lines
31 KiB
C
/**
|
|
* @file lv_app_example.c
|
|
*
|
|
*/
|
|
|
|
/*********************
|
|
* INCLUDES
|
|
*********************/
|
|
#include "lv_app_files.h"
|
|
#if LV_APP_ENABLE != 0 && USE_LV_APP_FILES != 0
|
|
|
|
#include <stdio.h>
|
|
#include "misc/os/ptask.h"
|
|
#include "../lv_app/lv_app_util/lv_app_kb.h"
|
|
#include "../lv_app/lv_app_util/lv_app_notice.h"
|
|
|
|
/*********************
|
|
* DEFINES
|
|
*********************/
|
|
#define LV_APP_FILES_CHUNK_MIN_SIZE 32
|
|
#define LV_APP_FILES_CHUNK_MIN_TIME 10
|
|
#define LV_APP_FILES_CHUNK_MAX_TIME 10000
|
|
|
|
/**********************
|
|
* TYPEDEFS
|
|
**********************/
|
|
|
|
/*Application specific data for an instance of this application*/
|
|
typedef struct
|
|
{
|
|
char path[LV_APP_FILES_PATH_MAX_LEN];
|
|
char fn[LV_APP_FILES_FN_MAX_LEN];
|
|
fs_file_t file;
|
|
uint8_t file_cnt;
|
|
uint16_t chunk_delay;
|
|
uint16_t chunk_size;
|
|
uint8_t send_fn :1;
|
|
uint8_t send_size :1;
|
|
uint8_t send_crc :1;
|
|
uint8_t send_in_prog :1;
|
|
ptask_t * send_task;
|
|
}my_app_data_t;
|
|
|
|
/*Application specific data a window of this application*/
|
|
typedef struct
|
|
{
|
|
lv_obj_t * file_list;
|
|
lv_obj_t * send_set_h;
|
|
}my_win_data_t;
|
|
|
|
/*Application specific data for a shortcut of this application*/
|
|
typedef struct
|
|
{
|
|
lv_obj_t * label;
|
|
}my_sc_data_t;
|
|
|
|
typedef enum
|
|
{
|
|
SEND_SETTINGS_FN,
|
|
SEND_SETTINGS_SIZE,
|
|
SEND_SETTINGS_CRC,
|
|
SEND_SETTINGS_CHUNK_SIZE,
|
|
SEND_SETTINGS_CHUNK_DELAY,
|
|
}send_settings_id_t;
|
|
|
|
/**********************
|
|
* STATIC PROTOTYPES
|
|
**********************/
|
|
static void my_app_run(lv_app_inst_t * app, void * conf);
|
|
static void my_app_close(lv_app_inst_t * app);
|
|
static void my_com_rec(lv_app_inst_t * app_send, lv_app_inst_t * app_rec, lv_app_com_type_t type , const void * data, uint32_t size);
|
|
static void my_sc_open(lv_app_inst_t * app, lv_obj_t * sc);
|
|
static void my_sc_close(lv_app_inst_t * app);
|
|
static void my_win_open(lv_app_inst_t * app, lv_obj_t * win);
|
|
static void my_win_close(lv_app_inst_t * app);
|
|
|
|
static void win_load_file_list(lv_app_inst_t * app);
|
|
static void win_create_list(lv_app_inst_t * app);
|
|
static lv_action_res_t win_up_action(lv_obj_t * up, lv_dispi_t * dispi);
|
|
static lv_action_res_t win_next_action(lv_obj_t * next, lv_dispi_t * dispi);
|
|
static lv_action_res_t win_prev_action(lv_obj_t * prev, lv_dispi_t * dispi);
|
|
static lv_action_res_t win_drv_action(lv_obj_t * drv, lv_dispi_t * dispi);
|
|
static lv_action_res_t win_folder_action(lv_obj_t * folder, lv_dispi_t * dispi);
|
|
static lv_action_res_t win_file_action(lv_obj_t * file, lv_dispi_t * dispi);
|
|
static lv_action_res_t win_send_rel_action(lv_obj_t * send, lv_dispi_t * dispi);
|
|
static lv_action_res_t win_send_lpr_action(lv_obj_t * send, lv_dispi_t * dispi);
|
|
static lv_action_res_t win_send_settings_element_rel_action(lv_obj_t * element, lv_dispi_t * dispi);
|
|
static lv_action_res_t win_back_action(lv_obj_t * back, lv_dispi_t * dispi);
|
|
static lv_action_res_t win_del_rel_action(lv_obj_t * del, lv_dispi_t * dispi);
|
|
static lv_action_res_t win_del_lpr_action(lv_obj_t * del, lv_dispi_t * dispi);
|
|
static void send_settings_kb_close_action(lv_obj_t * ta);
|
|
static void send_settings_kb_ok_action(lv_obj_t * ta);
|
|
static void start_send(lv_app_inst_t * app, const char * path);
|
|
static void send_task(void * param);
|
|
|
|
/**********************
|
|
* STATIC VARIABLES
|
|
**********************/
|
|
static lv_app_dsc_t my_app_dsc =
|
|
{
|
|
.name = "Files",
|
|
.mode = LV_APP_MODE_NONE,
|
|
.app_run = my_app_run,
|
|
.app_close = my_app_close,
|
|
.com_rec = my_com_rec,
|
|
.win_open = my_win_open,
|
|
.win_close = my_win_close,
|
|
.sc_open = my_sc_open,
|
|
.sc_close = my_sc_close,
|
|
.app_data_size = sizeof(my_app_data_t),
|
|
.sc_data_size = sizeof(my_sc_data_t),
|
|
.win_data_size = sizeof(my_win_data_t),
|
|
};
|
|
|
|
static lv_labels_t sc_labels;
|
|
|
|
|
|
/**********************
|
|
* MACROS
|
|
**********************/
|
|
|
|
/**********************
|
|
* GLOBAL FUNCTIONS
|
|
**********************/
|
|
|
|
/**
|
|
* Initialize the application
|
|
* @return pointer to the application descriptor of this application
|
|
*/
|
|
const lv_app_dsc_t * lv_app_files_init(void)
|
|
{
|
|
lv_app_style_t * app_style = lv_app_style_get();
|
|
memcpy(&sc_labels, &app_style->sc_txt_style, sizeof(lv_labels_t));
|
|
sc_labels.font = LV_APP_FONT_LARGE;
|
|
|
|
|
|
return &my_app_dsc;
|
|
}
|
|
|
|
/**********************
|
|
* STATIC FUNCTIONS
|
|
**********************/
|
|
|
|
/**
|
|
* Run an application according to 'app_dsc'
|
|
* @param app_dsc pointer to an application descriptor
|
|
* @param conf pointer to a lv_app_example_conf_t structure with configuration data or NULL if unused
|
|
* @return pointer to the opened application or NULL if any error occurred
|
|
*/
|
|
static void my_app_run(lv_app_inst_t * app, void * conf)
|
|
{
|
|
/*Initialize the application*/
|
|
my_app_data_t * app_data = app->app_data;
|
|
app_data->file_cnt = 0;
|
|
app_data->path[0] = '\0';
|
|
app_data->fn[0] = '\0';
|
|
app_data->send_fn = 0;
|
|
app_data->send_size = 0;
|
|
app_data->send_crc = 0;
|
|
app_data->chunk_size = LV_APP_FILES_CHUNK_DEF_SIZE;
|
|
app_data->chunk_delay = LV_APP_FILES_CHUNK_DEF_TIME;
|
|
app_data->send_in_prog = 0;
|
|
|
|
app_data->send_task = ptask_create(send_task, LV_APP_FILES_CHUNK_DEF_TIME, PTASK_PRIO_OFF, app);
|
|
}
|
|
|
|
/**
|
|
* Close a running application.
|
|
* Close the Window and the Shortcut too if opened.
|
|
* Free all the allocated memory by this application.
|
|
* @param app pointer to an application
|
|
*/
|
|
static void my_app_close(lv_app_inst_t * app)
|
|
{
|
|
/*No dynamically allocated data in 'my_app_data'*/
|
|
my_app_data_t * app_data = app->app_data;
|
|
ptask_del(app_data->send_task);
|
|
if(app_data->send_in_prog != 0) fs_close(&app_data->file);
|
|
|
|
}
|
|
|
|
/**
|
|
* Read the data have been sent to this application
|
|
* @param app_send pointer to an application which sent the message
|
|
* @param app_rec pointer to an application which is receiving the message
|
|
* @param type type of data from 'lv_app_com_type_t' enum
|
|
* @param data pointer to the sent data
|
|
* @param size length of 'data' in bytes
|
|
*/
|
|
static void my_com_rec(lv_app_inst_t * app_send, lv_app_inst_t * app_rec,
|
|
lv_app_com_type_t type , const void * data, uint32_t size)
|
|
{
|
|
if(type == LV_APP_COM_TYPE_CHAR) {
|
|
/*Check for file query. E.g. "U:/file.txt?"*/
|
|
const char * path = data;
|
|
if(path[size - 1] == '?') {
|
|
if(size > LV_APP_FILES_PATH_MAX_LEN + LV_APP_FILES_FN_MAX_LEN) {
|
|
lv_app_notice_add("Can not send file:\ntoo long path");
|
|
}
|
|
|
|
char path_fn[LV_APP_FILES_PATH_MAX_LEN + LV_APP_FILES_FN_MAX_LEN];
|
|
memcpy(path_fn, data, size - 1); /*-1 to ignore the '?' at the end*/
|
|
path_fn[size - 1] = '\0';
|
|
start_send(app_rec, path_fn);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Open a shortcut for an application
|
|
* @param app pointer to an application
|
|
* @param sc pointer to an object where the application
|
|
* can create content of the shortcut
|
|
*/
|
|
static void my_sc_open(lv_app_inst_t * app, lv_obj_t * sc)
|
|
{
|
|
my_sc_data_t * sc_data = app->sc_data;
|
|
my_app_data_t * app_data = app->app_data;
|
|
|
|
|
|
sc_data->label = lv_label_create(sc, NULL);
|
|
lv_obj_set_style(sc_data->label, &sc_labels);
|
|
lv_label_set_text(sc_data->label, fs_get_last(app_data->path));
|
|
lv_obj_align(sc_data->label, NULL, LV_ALIGN_CENTER, 0, 0);
|
|
}
|
|
|
|
/**
|
|
* Close the shortcut of an application
|
|
* @param app pointer to an application
|
|
*/
|
|
static void my_sc_close(lv_app_inst_t * app)
|
|
{
|
|
/*No dynamically allocated data in 'my_sc_data'*/
|
|
}
|
|
|
|
|
|
/**
|
|
* Open the application in a window
|
|
* @param app pointer to an application
|
|
* @param win pointer to a window object where
|
|
* the application can create content
|
|
*/
|
|
static void my_win_open(lv_app_inst_t * app, lv_obj_t * win)
|
|
{
|
|
my_win_data_t * win_data = app->win_data;
|
|
my_app_data_t * app_data = app->app_data;
|
|
|
|
app_data->file_cnt = 0;
|
|
win_data->file_list = NULL;
|
|
win_data->send_set_h = NULL;
|
|
|
|
lv_win_set_title(win, app_data->path);
|
|
|
|
win_load_file_list(app);
|
|
}
|
|
|
|
/**
|
|
* Close the window of an application
|
|
* @param app pointer to an application
|
|
*/
|
|
static void my_win_close(lv_app_inst_t * app)
|
|
{
|
|
|
|
}
|
|
|
|
/*--------------------
|
|
* OTHER FUNCTIONS
|
|
---------------------*/
|
|
/**
|
|
* Create an mpty list on the window. 'win_load_file_list' will fill it.
|
|
* @param app pointer to a Files application
|
|
*/
|
|
static void win_create_list(lv_app_inst_t * app)
|
|
{
|
|
lv_app_style_t * app_style = lv_app_style_get();
|
|
my_win_data_t * win_data = app->win_data;
|
|
|
|
/*Delete the previous list*/
|
|
if(win_data->file_list != NULL) {
|
|
lv_obj_del(win_data->file_list);
|
|
}
|
|
|
|
/*Create a new list*/
|
|
win_data->file_list = lv_list_create(app->win, NULL);
|
|
lv_obj_set_width(win_data->file_list, app_style->win_useful_w);
|
|
lv_obj_set_style(win_data->file_list, lv_lists_get(LV_LISTS_TRANSP, NULL));
|
|
lv_obj_set_drag_parent(win_data->file_list, true);
|
|
lv_obj_set_drag_parent(lv_page_get_scrl(win_data->file_list), true);
|
|
lv_rect_set_fit(win_data->file_list, false, true);
|
|
lv_rect_set_layout(lv_page_get_scrl(win_data->file_list), LV_RECT_LAYOUT_COL_L);
|
|
}
|
|
|
|
/**
|
|
* Load the file list from the current path on the window
|
|
* @param app pointer to a Files application
|
|
*/
|
|
static void win_load_file_list(lv_app_inst_t * app)
|
|
{
|
|
my_app_data_t * app_data = app->app_data;
|
|
my_win_data_t * win_data = app->win_data;
|
|
|
|
/*Create a new list*/
|
|
win_create_list(app);
|
|
|
|
fs_res_t res = FS_RES_OK;
|
|
|
|
/*At empty path show the drivers */
|
|
lv_obj_t * liste;
|
|
if(app_data->path[0] == '\0') {
|
|
char drv[16];
|
|
char buf[2];
|
|
fs_get_letters(drv);
|
|
uint8_t i;
|
|
for(i = 0; drv[i] != '\0'; i++) {
|
|
buf[0] = drv[i];
|
|
buf[1] = '\0';
|
|
liste = lv_list_add(win_data->file_list, "U:/icon_driver", buf, win_drv_action);
|
|
lv_obj_set_free_p(liste, app);
|
|
}
|
|
}
|
|
/*List the files/folders with fs interface*/
|
|
else {
|
|
liste = lv_list_add(win_data->file_list, "U:/icon_up", "Up", win_up_action);
|
|
lv_obj_set_free_p(liste, app);
|
|
|
|
fs_readdir_t rd;
|
|
res = fs_readdir_init(&rd, app_data->path);
|
|
if(res != FS_RES_OK) {
|
|
lv_app_notice_add("Can not read the\npath in Files");
|
|
return;
|
|
}
|
|
|
|
/*At not first page add prev. page button */
|
|
if(app_data->file_cnt != 0) {
|
|
liste = lv_list_add(win_data->file_list, "U:/icon_left", "Previous page", win_prev_action);
|
|
lv_obj_set_free_p(liste, app);
|
|
}
|
|
|
|
char fn[LV_APP_FILES_FN_MAX_LEN];
|
|
|
|
/*Read the files from the previous pages*/
|
|
uint16_t file_cnt = 0;
|
|
while(file_cnt <= app_data->file_cnt) {
|
|
res = fs_readdir(&rd, fn);
|
|
if(res != FS_RES_OK || fn[0] == '\0'){
|
|
lv_app_notice_add("Can not read\nthe path in Files");
|
|
return;
|
|
}
|
|
file_cnt ++;
|
|
}
|
|
|
|
/*Add list elements from the files and folders*/
|
|
while(res == FS_RES_OK && fn[0] != '\0') {
|
|
if(fn[0] == '/') { /*Add a folder*/
|
|
lv_obj_t * liste;
|
|
liste = lv_list_add(win_data->file_list, "U:/icon_folder", &fn[1], win_folder_action);
|
|
lv_obj_set_free_p(liste, app);
|
|
app_data->file_cnt ++;
|
|
}
|
|
/*Add a file*/
|
|
else {
|
|
liste = lv_list_add(win_data->file_list, "U:/icon_file", fn, win_file_action);
|
|
lv_obj_set_free_p(liste, app);
|
|
app_data->file_cnt ++;
|
|
}
|
|
|
|
/*Get the next element*/
|
|
res = fs_readdir(&rd, fn);
|
|
|
|
/*Show only LV_APP_FSEL_MAX_FILE elements and add a Next page button*/
|
|
if(app_data->file_cnt != 0 && app_data->file_cnt % LV_APP_FILES_PAGE_SIZE == 0) {
|
|
liste = lv_list_add(win_data->file_list, "U:/icon_right", "Next page", win_next_action);
|
|
lv_obj_set_free_p(liste, app);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*Close the read directory*/
|
|
fs_readdir_close(&rd);
|
|
}
|
|
|
|
if(res != FS_RES_OK) {
|
|
lv_app_notice_add("Can not read\nthe path in Files");
|
|
}
|
|
|
|
/*Focus to the top of the list*/
|
|
lv_obj_set_y(lv_page_get_scrl(win_data->file_list), 0);
|
|
return;
|
|
}
|
|
|
|
|
|
/**
|
|
* Called when the Up list element is released to step one level
|
|
* @param up pointer to the Up button
|
|
* @param dispi pointer to the caller display input
|
|
* @return LV_ACTION_RES_INV because the list is deleted in the function
|
|
*/
|
|
static lv_action_res_t win_up_action(lv_obj_t * up, lv_dispi_t * dispi)
|
|
{
|
|
lv_app_inst_t * app = lv_obj_get_free_p(up);
|
|
my_app_data_t * app_data = app->app_data;
|
|
fs_up(app_data->path);
|
|
app_data->file_cnt = 0;
|
|
lv_win_set_title(app->win, app_data->path);
|
|
|
|
my_sc_data_t * sc_data = app->sc_data;
|
|
if(sc_data != NULL) {
|
|
lv_label_set_text(sc_data->label, fs_get_last(app_data->path));
|
|
lv_obj_align(sc_data->label, NULL, LV_ALIGN_CENTER, 0, 0);
|
|
}
|
|
|
|
win_load_file_list(app);
|
|
return LV_ACTION_RES_INV;
|
|
}
|
|
|
|
/**
|
|
* Called when the Next list element is released to go to the next page
|
|
* @param next pointer to the Next button
|
|
* @param dispi pointer to the caller display input
|
|
* @return LV_ACTION_RES_INV because the list is deleted in the function
|
|
*/
|
|
static lv_action_res_t win_next_action(lv_obj_t * next, lv_dispi_t * dispi)
|
|
{
|
|
lv_app_inst_t * app = lv_obj_get_free_p(next);
|
|
win_load_file_list(app);
|
|
return LV_ACTION_RES_INV;
|
|
}
|
|
|
|
/**
|
|
* Called when the Prev list element is released to previous page
|
|
* @param prev pointer to the Prev button
|
|
* @param dispi pointer to the caller display input
|
|
* @return LV_ACTION_RES_INV because the list is deleted in the function
|
|
*/
|
|
static lv_action_res_t win_prev_action(lv_obj_t * prev, lv_dispi_t * dispi)
|
|
{
|
|
lv_app_inst_t * app = lv_obj_get_free_p(prev);
|
|
my_app_data_t * app_data = app->app_data;
|
|
if(app_data->file_cnt <= 2 * LV_APP_FILES_PAGE_SIZE) app_data->file_cnt = 0;
|
|
else if(app_data->file_cnt % LV_APP_FILES_PAGE_SIZE == 0) {
|
|
app_data->file_cnt -= 2 * LV_APP_FILES_PAGE_SIZE;
|
|
} else {
|
|
app_data->file_cnt = ((app_data->file_cnt / LV_APP_FILES_PAGE_SIZE) - 1) * LV_APP_FILES_PAGE_SIZE;
|
|
}
|
|
|
|
win_load_file_list(app);
|
|
return LV_ACTION_RES_INV;
|
|
}
|
|
|
|
|
|
/**
|
|
* Called when the Driver list element is released to step into a driver
|
|
* @param drv pointer to the Driver button
|
|
* @param dispi pointer to the caller display input
|
|
* @return LV_ACTION_RES_INV because the list is deleted in the function
|
|
*/
|
|
static lv_action_res_t win_drv_action(lv_obj_t * drv, lv_dispi_t * dispi)
|
|
{
|
|
lv_app_inst_t * app = lv_obj_get_free_p(drv);
|
|
my_app_data_t * app_data = app->app_data;
|
|
sprintf(app_data->path, "%s:", lv_list_element_get_txt(drv));
|
|
app_data->file_cnt = 0;
|
|
lv_win_set_title(app->win, app_data->path);
|
|
my_sc_data_t * sc_data = app->sc_data;
|
|
if(sc_data != NULL) {
|
|
lv_label_set_text(sc_data->label, fs_get_last(app_data->path));
|
|
lv_obj_align(sc_data->label, NULL, LV_ALIGN_CENTER, 0, 0);
|
|
}
|
|
|
|
win_load_file_list(app);
|
|
return LV_ACTION_RES_INV;
|
|
}
|
|
|
|
|
|
/**
|
|
* Called when a folder list element is released to enter into it
|
|
* @param folder pointer to a folder button
|
|
* @param dispi pointer to the caller display input
|
|
* @return LV_ACTION_RES_INV because the list is deleted in the function
|
|
*/
|
|
static lv_action_res_t win_folder_action(lv_obj_t * folder, lv_dispi_t * dispi)
|
|
{
|
|
lv_app_inst_t * app = lv_obj_get_free_p(folder);
|
|
my_app_data_t * app_data = app->app_data;
|
|
sprintf(app_data->path, "%s/%s", app_data->path, lv_list_element_get_txt(folder));
|
|
app_data->file_cnt = 0;
|
|
|
|
lv_win_set_title(app->win, app_data->path);
|
|
my_sc_data_t * sc_data = app->sc_data;
|
|
if(sc_data != NULL) {
|
|
lv_label_set_text(sc_data->label, fs_get_last(app_data->path));
|
|
lv_obj_align(sc_data->label, NULL, LV_ALIGN_CENTER, 0, 0);
|
|
}
|
|
|
|
|
|
win_load_file_list(app);
|
|
return LV_ACTION_RES_INV;
|
|
}
|
|
|
|
|
|
/**
|
|
* Called when a file list element is released to show the list of operation on it
|
|
* @param file pointer to a file button
|
|
* @param dispi pointer to the caller display input
|
|
* @return LV_ACTION_RES_INV because the list is deleted in the function
|
|
*/
|
|
static lv_action_res_t win_file_action(lv_obj_t * file, lv_dispi_t * dispi)
|
|
{
|
|
lv_app_inst_t * app = lv_obj_get_free_p(file);
|
|
my_app_data_t * app_data = app->app_data;
|
|
my_win_data_t * win_data = app->win_data;
|
|
|
|
sprintf(app_data->fn, "%s", lv_list_element_get_txt(file));
|
|
|
|
win_create_list(app);
|
|
|
|
/*Create the list of operations*/
|
|
lv_obj_t * liste;
|
|
liste = lv_list_add(win_data->file_list, "U:/icon_left", "Back", win_back_action);
|
|
lv_obj_set_free_p(liste, app);
|
|
|
|
/*Send button*/
|
|
liste = lv_list_add(win_data->file_list, NULL, "Send", win_send_rel_action);
|
|
lv_obj_set_free_p(liste, app);
|
|
lv_btn_set_lpr_action(liste, win_send_lpr_action);
|
|
lv_obj_set_free_p(liste, app);
|
|
|
|
/*Delete button*/
|
|
liste = lv_list_add(win_data->file_list, NULL, "Delete", win_del_rel_action);
|
|
lv_btn_set_lpr_action(liste, win_del_lpr_action);
|
|
lv_obj_set_free_p(liste, app);
|
|
|
|
return LV_ACTION_RES_INV;
|
|
}
|
|
|
|
/**
|
|
* Called when the Back list element is released to when a file chosen to
|
|
* go back to the file list from file operation
|
|
* @param back pointer to the back button
|
|
* @param dispi pointer to the caller display input
|
|
* @return LV_ACTION_RES_INV because the list is deleted in the function
|
|
*/
|
|
static lv_action_res_t win_back_action(lv_obj_t * up, lv_dispi_t * dispi)
|
|
{
|
|
lv_app_inst_t * app = lv_obj_get_free_p(up);
|
|
my_app_data_t * app_data = app->app_data;
|
|
|
|
app_data->file_cnt = 0;
|
|
win_load_file_list(app);
|
|
return LV_ACTION_RES_INV;
|
|
}
|
|
|
|
/**
|
|
* Called when the Send list element is released to send the file
|
|
* @param sed pointer to the Up button
|
|
* @param dispi pointer to the caller display input
|
|
* @return LV_ACTION_RES_OK because the list is NOT deleted in the function
|
|
*/
|
|
static lv_action_res_t win_send_rel_action(lv_obj_t * send, lv_dispi_t * dispi)
|
|
{
|
|
lv_app_inst_t * app = lv_obj_get_free_p(send);
|
|
my_app_data_t * app_data = app->app_data;
|
|
|
|
if(app_data->send_in_prog != 0) {
|
|
lv_app_notice_add("File sending\nin progress");
|
|
return LV_ACTION_RES_OK;
|
|
}
|
|
|
|
char path_fn[LV_APP_FILES_PATH_MAX_LEN + LV_APP_FILES_FN_MAX_LEN];
|
|
sprintf(path_fn, "%s/%s", app_data->path, app_data->fn);
|
|
start_send(app, path_fn);
|
|
|
|
return LV_ACTION_RES_OK;
|
|
}
|
|
|
|
/**
|
|
* Called when the Send list element is long pressed to show/hide send settings
|
|
* @param send pointer to the Up button
|
|
* @param dispi pointer to the caller display input
|
|
* @return LV_ACTION_RES_OK because the list is NOT deleted in the function
|
|
*/
|
|
static lv_action_res_t win_send_lpr_action(lv_obj_t * send, lv_dispi_t * dispi)
|
|
{
|
|
lv_app_inst_t * app = lv_obj_get_free_p(send);
|
|
my_app_data_t * app_data = app->app_data;
|
|
my_win_data_t * win_data = app->win_data;
|
|
|
|
/*Close the settings if it is opened*/
|
|
if(win_data->send_set_h != NULL) {
|
|
lv_obj_del(win_data->send_set_h);
|
|
win_data->send_set_h = NULL;
|
|
lv_dispi_wait_release(dispi);
|
|
lv_btn_set_state(send, LV_BTN_STATE_REL);
|
|
return LV_ACTION_RES_OK;
|
|
}
|
|
|
|
/*Create the settings*/
|
|
lv_btn_set_state(send, LV_BTN_STATE_REL);
|
|
lv_rect_set_layout(send, LV_RECT_LAYOUT_COL_L);
|
|
|
|
/*Create holder for the settings*/
|
|
win_data->send_set_h = lv_rect_create(send, NULL);
|
|
lv_obj_set_style(win_data->send_set_h, lv_rects_get(LV_RECTS_TRANSP, NULL));
|
|
lv_obj_set_click(win_data->send_set_h, false);
|
|
lv_rect_set_fit(win_data->send_set_h, true, true);
|
|
lv_rect_set_layout(win_data->send_set_h, LV_RECT_LAYOUT_COL_L);
|
|
|
|
/*Create check boxes*/
|
|
lv_obj_t * cb;
|
|
|
|
/*Send file name check box*/
|
|
cb = lv_cb_create(win_data->send_set_h, NULL);
|
|
lv_cb_set_text(cb, "Send file name");
|
|
lv_obj_set_free_num(cb, SEND_SETTINGS_FN);
|
|
lv_obj_set_free_p(cb, app);
|
|
lv_btn_set_rel_action(cb, win_send_settings_element_rel_action);
|
|
if(app_data->send_fn != 0) lv_btn_set_state(cb, LV_BTN_STATE_TGL_REL);
|
|
else lv_btn_set_state(cb, LV_BTN_STATE_REL);
|
|
|
|
/*Send size check box*/
|
|
cb = lv_cb_create(win_data->send_set_h, cb);
|
|
lv_cb_set_text(cb, "Send size");
|
|
lv_obj_set_free_num(cb, SEND_SETTINGS_SIZE);
|
|
if(app_data->send_size != 0) lv_btn_set_state(cb, LV_BTN_STATE_TGL_REL);
|
|
else lv_btn_set_state(cb, LV_BTN_STATE_REL);
|
|
|
|
/*Send CRC check box*/
|
|
cb = lv_cb_create(win_data->send_set_h, cb);
|
|
lv_cb_set_text(cb, "Send CRC");
|
|
lv_obj_set_free_num(cb, SEND_SETTINGS_CRC);
|
|
if(app_data->send_crc != 0) lv_btn_set_state(cb, LV_BTN_STATE_TGL_REL);
|
|
else lv_btn_set_state(cb, LV_BTN_STATE_REL);
|
|
|
|
/*Create a text area the type chunk size*/
|
|
lv_obj_t * val_set_h;
|
|
val_set_h = lv_rect_create(win_data->send_set_h, NULL);
|
|
lv_obj_set_style(val_set_h, lv_rects_get(LV_RECTS_TRANSP, NULL));
|
|
lv_obj_set_click(val_set_h, false);
|
|
lv_rect_set_fit(val_set_h, true, true);
|
|
lv_rect_set_layout(val_set_h, LV_RECT_LAYOUT_ROW_M);
|
|
|
|
lv_obj_t * label;
|
|
label = lv_label_create(val_set_h, NULL);
|
|
lv_label_set_text(label, "Chunk size");
|
|
|
|
lv_obj_t * ta;
|
|
char buf[32];
|
|
ta = lv_ta_create(val_set_h, NULL);
|
|
lv_obj_set_style(ta, lv_tas_get(LV_TAS_SIMPLE, NULL));
|
|
lv_rect_set_fit(ta, false, true);
|
|
lv_obj_set_free_num(ta, SEND_SETTINGS_CHUNK_SIZE);
|
|
lv_obj_set_free_p(ta, app);
|
|
lv_page_set_rel_action(ta, win_send_settings_element_rel_action);
|
|
sprintf(buf, "%d", app_data->chunk_size);
|
|
lv_ta_set_text(ta, buf);
|
|
|
|
/*Create a text area to type the chunk delay*/
|
|
val_set_h = lv_rect_create(win_data->send_set_h, val_set_h);
|
|
|
|
label = lv_label_create(val_set_h, NULL);
|
|
lv_label_set_text(label, "Inter-chunk delay");
|
|
|
|
ta = lv_ta_create(val_set_h, ta);
|
|
lv_obj_set_free_num(ta, SEND_SETTINGS_CHUNK_DELAY);
|
|
sprintf(buf, "%d", app_data->chunk_delay);
|
|
lv_ta_set_text(ta, buf);
|
|
|
|
return LV_ACTION_RES_OK;
|
|
}
|
|
/**
|
|
* Called when a send settings element is released
|
|
* @param element pointer to a chekbox or text area
|
|
* @param dispi pointer to the caller display input
|
|
* @return LV_ACTION_RES_OK because the list is NOT deleted in the function
|
|
*/
|
|
static lv_action_res_t win_send_settings_element_rel_action(lv_obj_t * element, lv_dispi_t * dispi)
|
|
{
|
|
send_settings_id_t id = lv_obj_get_free_num(element);
|
|
lv_app_inst_t * app = lv_obj_get_free_p(element);
|
|
my_app_data_t * app_data = app->app_data;
|
|
|
|
if(id == SEND_SETTINGS_FN) {
|
|
app_data->send_fn = lv_btn_get_state(element) == LV_BTN_STATE_REL ? 0 : 1;
|
|
} else if(id == SEND_SETTINGS_SIZE) {
|
|
app_data->send_size = lv_btn_get_state(element) == LV_BTN_STATE_REL ? 0 : 1;
|
|
} else if(id == SEND_SETTINGS_CRC) {
|
|
app_data->send_crc = lv_btn_get_state(element) == LV_BTN_STATE_REL ? 0 : 1;
|
|
|
|
/*TODO CRC sending is not supported yet*/
|
|
if(app_data->send_crc != 0) {
|
|
lv_app_notice_add("CRC sending is\nnot supported yet");
|
|
}
|
|
} else if(id == SEND_SETTINGS_CHUNK_SIZE) {
|
|
lv_app_kb_open(element, LV_APP_KB_MODE_NUM, send_settings_kb_close_action, send_settings_kb_ok_action);
|
|
} else if(id == SEND_SETTINGS_CHUNK_DELAY) {
|
|
lv_app_kb_open(element, LV_APP_KB_MODE_NUM, send_settings_kb_close_action, send_settings_kb_ok_action);
|
|
}
|
|
|
|
return LV_ACTION_RES_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* Called when the Delete list element is released.
|
|
* It will show a notification to long press the Delete button to remove the file
|
|
* @param del pointer to the back button
|
|
* @param dispi pointer to the caller display input
|
|
* @return LV_ACTION_RES_OK because the list is NOT deleted in the function
|
|
*/
|
|
static lv_action_res_t win_del_rel_action(lv_obj_t * del, lv_dispi_t * dispi)
|
|
{
|
|
lv_app_notice_add("Press long the Delete button\n"
|
|
"to remove the file");
|
|
|
|
return LV_ACTION_RES_OK;
|
|
}
|
|
/**
|
|
* Called when the Delete list element is long pressed to remove a file
|
|
* @param del pointer to the Delete button
|
|
* @param dispi pointer to the caller display input
|
|
* @return LV_ACTION_RES_OK because the list is NOT deleted in the function
|
|
*/
|
|
static lv_action_res_t win_del_lpr_action(lv_obj_t * del, lv_dispi_t * dispi)
|
|
{
|
|
lv_app_inst_t * app = lv_obj_get_free_p(del);
|
|
my_app_data_t * app_data = app->app_data;
|
|
|
|
char path_fn[LV_APP_FILES_PATH_MAX_LEN + LV_APP_FILES_FN_MAX_LEN];
|
|
sprintf(path_fn, "%s/%s", app_data->path, app_data->fn);
|
|
|
|
fs_res_t res = fs_remove(path_fn);
|
|
if(res == FS_RES_OK) lv_app_notice_add("%s deleted", app_data->fn);
|
|
else lv_app_notice_add("Can not delete\n%s", app_data->fn);
|
|
|
|
return LV_ACTION_RES_OK;
|
|
}
|
|
|
|
/**
|
|
* Called when a send setting is typed and 'Close' pressed on the App. keyboard.
|
|
* The function reverts the original value in the text area.
|
|
* @param ta pointer to a text area
|
|
*/
|
|
static void send_settings_kb_close_action(lv_obj_t * ta)
|
|
{
|
|
send_settings_id_t id = lv_obj_get_free_num(ta);
|
|
lv_app_inst_t * app = lv_obj_get_free_p(ta);
|
|
my_app_data_t * app_data = app->app_data;
|
|
|
|
char buf[32];
|
|
buf[0] = '\0';
|
|
|
|
if(id == SEND_SETTINGS_CHUNK_DELAY) {
|
|
sprintf(buf, "%d", app_data->chunk_size);
|
|
} else if(id == SEND_SETTINGS_CHUNK_SIZE) {
|
|
sprintf(buf, "%d", app_data->chunk_size);
|
|
}
|
|
lv_ta_set_text(ta, buf);
|
|
}
|
|
|
|
/**
|
|
* Called when a send setting is typed and 'Ok' pressed on the App. keyboard.
|
|
* The function saves teh new value.
|
|
* @param ta pointer to a text area
|
|
*/
|
|
static void send_settings_kb_ok_action(lv_obj_t * ta)
|
|
{
|
|
send_settings_id_t id = lv_obj_get_free_num(ta);
|
|
lv_app_inst_t * app = lv_obj_get_free_p(ta);
|
|
my_app_data_t * app_data = app->app_data;
|
|
|
|
int num;
|
|
sscanf(lv_ta_get_txt(ta), "%d", &num);
|
|
|
|
if(id == SEND_SETTINGS_CHUNK_DELAY) {
|
|
if(num > LV_APP_FILES_CHUNK_MAX_TIME) num = LV_APP_FILES_CHUNK_MAX_TIME;
|
|
if(num < LV_APP_FILES_CHUNK_MIN_TIME) num = LV_APP_FILES_CHUNK_MIN_TIME;
|
|
app_data->chunk_delay = (uint16_t) num;
|
|
} else if(id == SEND_SETTINGS_CHUNK_SIZE) {
|
|
if(num > LV_APP_FILES_CHUNK_MAX_SIZE) num = LV_APP_FILES_CHUNK_MAX_SIZE;
|
|
if(num < LV_APP_FILES_CHUNK_MIN_SIZE) num = LV_APP_FILES_CHUNK_MIN_SIZE;
|
|
app_data->chunk_size= (uint16_t) num;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Start the sending of a file
|
|
* @param app pointer to a Files application
|
|
* @param path path of the file to send
|
|
*/
|
|
static void start_send(lv_app_inst_t * app, const char * path)
|
|
{
|
|
my_app_data_t * app_data = app->app_data;
|
|
|
|
/*Open the file*/
|
|
fs_res_t res = fs_open(&app_data->file, path, FS_MODE_RD);
|
|
if(res == FS_RES_OK) {
|
|
uint32_t rn;
|
|
char rd_buf[LV_APP_FILES_CHUNK_MAX_SIZE];
|
|
|
|
/*Read the first chunk*/
|
|
res = fs_read(&app_data->file, rd_buf, app_data->chunk_size, &rn);
|
|
if(res == FS_RES_OK) {
|
|
app_data->send_in_prog = 1;
|
|
|
|
/*Send the header*/
|
|
if(app_data->send_fn != 0) {
|
|
lv_app_com_send(app, LV_APP_COM_TYPE_CHAR, app_data->path, strlen(app_data->path));
|
|
lv_app_com_send(app, LV_APP_COM_TYPE_CHAR, "/", 1);
|
|
lv_app_com_send(app, LV_APP_COM_TYPE_CHAR, app_data->fn, strlen(app_data->fn));
|
|
lv_app_com_send(app, LV_APP_COM_TYPE_CHAR, "\n", 1);
|
|
}
|
|
|
|
if(app_data->send_size != 0) {
|
|
char buf[64];
|
|
uint32_t size;
|
|
fs_size(&app_data->file, &size);
|
|
sprintf(buf,"%d", (int) size);
|
|
lv_app_com_send(app, LV_APP_COM_TYPE_CHAR, buf, strlen(buf));
|
|
lv_app_com_send(app, LV_APP_COM_TYPE_CHAR, "\n", 1);
|
|
}
|
|
if(app_data->send_crc != 0) {
|
|
lv_app_com_send(app, LV_APP_COM_TYPE_CHAR, "0x0000", 6);
|
|
lv_app_com_send(app, LV_APP_COM_TYPE_CHAR, "\n", 1);
|
|
}
|
|
|
|
/*Add an extra \n to separate the header from the file data*/
|
|
if(app_data->send_fn != 0 || app_data->send_size != 0 || app_data->send_crc != 0) {
|
|
lv_app_com_send(app, LV_APP_COM_TYPE_CHAR, "\n", 1);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/*If an error occurred close the file*/
|
|
if(res != FS_RES_OK) {
|
|
fs_close(&app_data->file);
|
|
ptask_set_prio(app_data->send_task, PTASK_PRIO_OFF);
|
|
app_data->send_in_prog = 0;
|
|
lv_app_notice_add("Can not send\nthe file in Files");
|
|
}
|
|
/*If no error show notification, start the sender task and refresh the shortcut*/
|
|
else {
|
|
/*Start the sender task*/
|
|
ptask_set_period(app_data->send_task, app_data->chunk_delay);
|
|
ptask_reset(app_data->send_task);
|
|
ptask_set_prio(app_data->send_task, PTASK_PRIO_HIGH);
|
|
lv_app_notice_add("Sending\n%s", fs_get_last(path));
|
|
|
|
/*Refresh the shortcut with the percentage of the sending*/
|
|
if(app->sc_data != NULL) {
|
|
my_sc_data_t * sc_data = app->sc_data;
|
|
|
|
uint32_t size;
|
|
fs_size(&app_data->file, &size);
|
|
uint32_t pos;
|
|
fs_tell(&app_data->file, &pos);
|
|
|
|
int pct = (uint32_t) (pos * 100) / size;
|
|
|
|
char buf[256];
|
|
sprintf(buf, "Sending\n%d%%", pct);
|
|
lv_label_set_text(sc_data->label, buf);
|
|
lv_obj_align(sc_data->label, NULL, LV_ALIGN_CENTER, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Periodically send the next chunk of the file
|
|
* @param app pointer to a Files application
|
|
*/
|
|
static void send_task(void * param)
|
|
{
|
|
lv_app_inst_t * app = param;
|
|
my_app_data_t * app_data = app->app_data;
|
|
|
|
if(app_data->send_in_prog == 0) return;
|
|
|
|
/*Read a chunk*/
|
|
uint32_t rn;
|
|
char rd_buf[LV_APP_FILES_CHUNK_MAX_SIZE];
|
|
fs_res_t res = fs_read(&app_data->file, rd_buf, app_data->chunk_size, &rn);
|
|
if(res == FS_RES_OK) {
|
|
app_data->send_in_prog = 1;
|
|
lv_app_com_send(app, LV_APP_COM_TYPE_CHAR, rd_buf, rn);
|
|
}
|
|
|
|
/*If the read failed close the file and show an error*/
|
|
if(res != FS_RES_OK) {
|
|
fs_close(&app_data->file);
|
|
app_data->send_in_prog = 0;
|
|
lv_app_notice_add("Can not send\nthe file in Files");
|
|
}
|
|
/*If the read was successful*/
|
|
else {
|
|
my_sc_data_t * sc_data = app->sc_data;
|
|
|
|
/*If the file is read close it a show a notification*/
|
|
if(rn < app_data->chunk_size) {
|
|
lv_app_notice_add("File sent");
|
|
fs_close(&app_data->file);
|
|
app_data->send_in_prog = 0;
|
|
|
|
/*Refresh the shortut*/
|
|
if(sc_data != NULL) {
|
|
lv_label_set_text(sc_data->label, fs_get_last(app_data->path));
|
|
lv_obj_align(sc_data->label, NULL, LV_ALIGN_CENTER, 0, 0);
|
|
}
|
|
}
|
|
/*If the file is not sent yet refresh the shortcut with percentage of sending*/
|
|
else {
|
|
if(sc_data != NULL) {
|
|
uint32_t size;
|
|
fs_size(&app_data->file, &size);
|
|
uint32_t pos;
|
|
fs_tell(&app_data->file, &pos);
|
|
|
|
uint8_t pct = (uint32_t) (pos * 100) / size;
|
|
|
|
char buf[256];
|
|
sprintf(buf, "Sending\n%d%%", pct);
|
|
lv_label_set_text(sc_data->label, buf);
|
|
lv_obj_align(sc_data->label, NULL, LV_ALIGN_CENTER, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /*LV_APP_ENABLE != 0 && USE_LV_APP_FILES != 0*/
|