You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
510 lines
18 KiB
510 lines
18 KiB
static uint16_t file_count;
|
|
static uint16_t page_count;
|
|
static uint16_t current_page;
|
|
static uint16_t sel_mode;
|
|
|
|
// Buttons in browser
|
|
enum {FILE_BUTTON_LEFT = 0, FILE_BUTTON_RIGHT, FILE_BUTTON_EXIT, FILE_BUTTON_DEL, FILE_BUTTON_FILE};
|
|
// Button position on screen
|
|
typedef struct {
|
|
uint16_t x;
|
|
uint16_t y;
|
|
uint16_t w;
|
|
uint8_t h;
|
|
uint8_t ofs;
|
|
} browser_btn_t;
|
|
static const browser_btn_t browser_btn[] = {
|
|
[FILE_BUTTON_LEFT] = { 0 + 40, LCD_HEIGHT - FILE_BOTTOM_HEIGHT, LCD_WIDTH/2 - 80, FILE_BOTTOM_HEIGHT, (LCD_WIDTH/2 - 80 - FONT_WIDTH)/2}, // < previous
|
|
[FILE_BUTTON_RIGHT]= {LCD_WIDTH/2 + 40, LCD_HEIGHT - FILE_BOTTOM_HEIGHT, LCD_WIDTH/2 - 80, FILE_BOTTOM_HEIGHT, (LCD_WIDTH/2 - 80 - FONT_WIDTH)/2}, // > next
|
|
[FILE_BUTTON_EXIT] = {LCD_WIDTH - 40, LCD_HEIGHT - FILE_BOTTOM_HEIGHT, 40, FILE_BOTTOM_HEIGHT, ( 40 - FONT_WIDTH)/2}, // X exit
|
|
[FILE_BUTTON_DEL] = { 0 + 0, LCD_HEIGHT - FILE_BOTTOM_HEIGHT, 40, FILE_BOTTOM_HEIGHT, ( 40 - 3*FONT_WIDTH)/2}, // DEL
|
|
// File button, only size and start position, must be idx = FILE_BUTTON_FILE
|
|
[FILE_BUTTON_FILE] = { 0, 0, LCD_WIDTH/FILES_COLUMNS, FILE_BUTTON_HEIGHT, 5},
|
|
};
|
|
|
|
static void browser_get_button_pos(int idx, browser_btn_t *b) {
|
|
int n = idx >= FILE_BUTTON_FILE ? FILE_BUTTON_FILE : idx;
|
|
#if 0
|
|
memcpy(b, &browser_btn[n], sizeof(browser_btn_t));
|
|
#else
|
|
b->x = browser_btn[n].x;
|
|
b->y = browser_btn[n].y;
|
|
b->w = browser_btn[n].w;
|
|
b->h = browser_btn[n].h;
|
|
b->ofs = browser_btn[n].ofs;
|
|
#endif
|
|
if (idx > FILE_BUTTON_FILE) { // for file buttons use multiplier from start offset
|
|
idx-= FILE_BUTTON_FILE;
|
|
b->x+= b->w * (idx / FILES_ROWS);
|
|
b->y+= b->h * (idx % FILES_ROWS);
|
|
}
|
|
}
|
|
|
|
static void browser_draw_button(int idx, const char *txt) {
|
|
if (idx < 0) return;
|
|
ui_button_t b;
|
|
browser_btn_t btn;
|
|
browser_get_button_pos(idx, &btn);
|
|
// Mark DEL button in file delete mode
|
|
b.bg = (idx == FILE_BUTTON_DEL && sel_mode) ? LCD_LOW_BAT_COLOR : LCD_MENU_COLOR;
|
|
b.fg = LCD_MENU_TEXT_COLOR;
|
|
b.border = (idx == selection) ? BROWSER_BUTTON_BORDER|BUTTON_BORDER_FALLING : BROWSER_BUTTON_BORDER|BUTTON_BORDER_RISE;
|
|
if (txt == NULL) b.border|= BUTTON_BORDER_NO_FILL;
|
|
draw_button(btn.x, btn.y, btn.w, btn.h, &b);
|
|
if (txt) ili9341_drawstring_7x13(txt, btn.x + btn.ofs, btn.y + (btn.h - bFONT_STR_HEIGHT) / 2);
|
|
}
|
|
|
|
static char to_lower(char c) {return (c >='A' && c <= 'Z') ? c - 'A' + 'a' : c;}
|
|
|
|
static bool strcmpi(const char *t1, const char *t2) {
|
|
int i = 0;
|
|
while (1) {
|
|
char ch1 = to_lower(t1[i]), ch2 = to_lower(t2[i]);
|
|
if (ch1 != ch2) return false;
|
|
if (ch1 == 0) return true;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
static bool compare_ext(const char *name, const char *ext) {
|
|
int i = 0, j = 0;
|
|
while (name[i]) if (name[i++] == '.') j = i; // Get last '.' position + 1
|
|
return j == 0 ? false : strcmpi(&name[j], ext); // Compare text after '.' and ext
|
|
}
|
|
|
|
static FRESULT sd_findnext(DIR* dp, FILINFO* fno) {
|
|
while (f_readdir(dp, fno) == FR_OK && fno->fname[0]) {
|
|
if (fno->fattrib & AM_DIR) continue;
|
|
if (compare_ext(fno->fname, dp->pat)) return FR_OK;
|
|
//#if FF_USE_LFN && FF_USE_FIND == 2
|
|
// if (compare_ext(fno->altname, dp->pat)) return FR_OK;
|
|
//#endif
|
|
}
|
|
return FR_NO_FILE;
|
|
}
|
|
|
|
static FRESULT sd_open_dir(DIR* dp, const TCHAR* path, const TCHAR* pattern) {
|
|
dp->pat = pattern;
|
|
return f_opendir(dp, path);
|
|
}
|
|
|
|
static void browser_open_file(int sel) {
|
|
FILINFO fno;
|
|
FRESULT res;
|
|
DIR dj;
|
|
int cnt;
|
|
if ((uint16_t)sel >= file_count) return;
|
|
if (f_mount(fs_volume, "", 1) != FR_OK) return;
|
|
repeat:
|
|
cnt = sel;
|
|
if (sd_open_dir(&dj, "", file_ext[keypad_mode]) != FR_OK) return; // open dir
|
|
while (sd_findnext(&dj, &fno) == FR_OK && cnt != 0) cnt--; // skip cnt files
|
|
f_closedir(&dj);
|
|
if (cnt != 0) return;
|
|
|
|
// Delete file if in delete mode
|
|
if (sel_mode) {f_unlink(fno.fname); return;}
|
|
|
|
const char *error = NULL;
|
|
bool leave_show = true;
|
|
UINT size;
|
|
if (f_open(fs_file, fno.fname, FA_READ) != FR_OK) return;
|
|
|
|
ili9341_set_foreground(LCD_FG_COLOR);
|
|
ili9341_set_background(LCD_BG_COLOR);
|
|
switch (keypad_mode) {
|
|
case FMT_TBL_FILE:
|
|
{
|
|
const int buffer_size = 256;
|
|
const int line_size = 128;
|
|
char *buf_8 = (char *)spi_buffer; // must be greater then buffer_size + line_size
|
|
char *line = buf_8 + buffer_size;
|
|
uint16_t j = 0, i, count = 0;
|
|
while (f_read(fs_file, buf_8, buffer_size, &size) == FR_OK && size > 0) {
|
|
for (i = 0; i < size; i++) {
|
|
uint8_t c = buf_8[i];
|
|
if (c == '\r') { // New line (Enter)
|
|
line[j] = 0; j = 0;
|
|
char *args[16];
|
|
int nargs = parse_line(line, args, 16); // Parse line to 16 args
|
|
if (nargs < 2 || args[0][0] == '#' || args[0][0] == '!') continue; // No data or comment or settings
|
|
if (count >= LIMITS_MAX) {error = "Format err"; goto finish2;}
|
|
setting.limits[current_trace][count].frequency = my_atoui(args[0]);// Get frequency
|
|
setting.limits[current_trace][count].level = my_atof(args[1]); // Get frequency
|
|
setting.limits[current_trace][count].enabled = true; // Get frequency
|
|
count++;
|
|
}
|
|
else if (c < 0x20) continue; // Others (skip)
|
|
else if (j < line_size) line[j++] = (char)c; // Store
|
|
}
|
|
}
|
|
finish2:
|
|
for (; count < LIMITS_MAX; i++) {
|
|
setting.limits[current_trace][count].frequency = 0;
|
|
setting.limits[current_trace][count].level = 0;
|
|
setting.limits[current_trace][count].enabled = false;
|
|
count++;
|
|
}
|
|
setting.stored[current_trace] = true;
|
|
TRACE_ENABLE(1<<current_trace);
|
|
set_average(current_trace,AV_TABLE);
|
|
dirty = true;
|
|
limits_update();
|
|
break;
|
|
}
|
|
#ifdef __BANDS__
|
|
case FMT_BND_FILE:
|
|
{
|
|
const int buffer_size = 256;
|
|
const int line_size = 128;
|
|
char *buf_8 = (char *)spi_buffer; // must be greater then buffer_size + line_size
|
|
char *line = buf_8 + buffer_size;
|
|
uint16_t j = 0, i, count = 0;
|
|
while (f_read(fs_file, buf_8, buffer_size, &size) == FR_OK && size > 0) {
|
|
for (i = 0; i < size; i++) {
|
|
uint8_t c = buf_8[i];
|
|
if (c == '\r') { // New line (Enter)
|
|
line[j] = 0; j = 0;
|
|
char *args[16];
|
|
int nargs = parse_line(line, args, 16); // Parse line to 16 args
|
|
if (nargs < 2 || args[0][0] == '#' || args[0][0] == '!') continue; // No data or comment or settings
|
|
if (count >= BANDS_MAX) {error = "Format err"; goto finish3;}
|
|
setting.bands[count].start = my_atoui(args[0]);// Get frequency
|
|
setting.bands[count].end = my_atoui(args[1]);// Get frequency
|
|
setting.bands[count].level = my_atof(args[2]); // Get frequency
|
|
setting.bands[count].enabled = true; // Get frequency
|
|
count++;
|
|
}
|
|
else if (c < 0x20) continue; // Others (skip)
|
|
else if (j < line_size) line[j++] = (char)c; // Store
|
|
}
|
|
}
|
|
finish3:
|
|
for (; count < BANDS_MAX; i++) {
|
|
setting.bands[count].start = 0;
|
|
setting.bands[count].end = 0;
|
|
setting.bands[count].level = 0;
|
|
setting.bands[count].enabled = false;
|
|
count++;
|
|
}
|
|
dirty = true;
|
|
update_frequencies();
|
|
break;
|
|
}
|
|
#endif
|
|
case FMT_CSV_FILE:
|
|
{
|
|
const int buffer_size = 256;
|
|
const int line_size = 128;
|
|
char *buf_8 = (char *)spi_buffer; // must be greater then buffer_size + line_size
|
|
char *line = buf_8 + buffer_size;
|
|
uint16_t j = 0, i, count = 0;
|
|
freq_t start = 0, stop = 0, f;
|
|
while (f_read(fs_file, buf_8, buffer_size, &size) == FR_OK && size > 0) {
|
|
for (i = 0; i < size; i++) {
|
|
uint8_t c = buf_8[i];
|
|
if (c == '\r') { // New line (Enter)
|
|
line[j] = 0; j = 0;
|
|
char *args[16];
|
|
int nargs = parse_line(line, args, 16); // Parse line to 16 args
|
|
if (nargs < 2 || args[0][0] == '#' || args[0][0] == '!') continue; // No data or comment or settings
|
|
f = my_atoui(args[0]); // Get frequency
|
|
if (count >= POINTS_COUNT || f > maxFreq) {error = "Format err"; goto finish;}
|
|
if (count == 0) {
|
|
start = f; // For index 0 set as start
|
|
setting.stored[current_trace] = true;
|
|
TRACE_ENABLE(1<<current_trace);
|
|
}
|
|
stop = f; // last set as stop
|
|
measured[current_trace][count] = my_atof(args[1]);
|
|
count++;
|
|
}
|
|
else if (c < 0x20) continue; // Others (skip)
|
|
else if (j < line_size) line[j++] = (char)c; // Store
|
|
}
|
|
}
|
|
finish:
|
|
if (count != 0) { // Points count not zero, so apply data to traces
|
|
// pause_sweep();
|
|
setting._sweep_points = count;
|
|
set_sweep_frequency(ST_START, start);
|
|
set_sweep_frequency(ST_STOP, stop);
|
|
// request_to_redraw(REDRAW_AREA);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case FMT_CMD_FILE:
|
|
{
|
|
static char cmd_buffer[256+128];
|
|
const int buffer_size = 256;
|
|
const int line_size = 128;
|
|
char *buf_8 = cmd_buffer; // (char *)spi_buffer; // must be greater then buffer_size + line_size
|
|
char *line = buf_8 + buffer_size;
|
|
uint16_t j = 0, i;
|
|
while (f_read(fs_file, buf_8, buffer_size, &size) == FR_OK && size > 0) {
|
|
for (i = 0; i < size; i++) {
|
|
uint8_t c = buf_8[i];
|
|
if (c == '\r') { // New line (Enter)
|
|
line[j] = 0; j = 0;
|
|
shell_executeCMDLine(line);
|
|
}
|
|
else if (c < 0x20) continue; // Others (skip)
|
|
else if (j < line_size) line[j++] = (char)c; // Store
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
/*
|
|
* BMP file load procedure, load only device screenshots
|
|
*/
|
|
case FMT_BMP_FILE:
|
|
{
|
|
int y;
|
|
leave_show = false; // allow step up/down load bitmap
|
|
uint16_t *buf_16 = spi_buffer; // prepare buffer
|
|
res = f_read(fs_file, (void *)buf_16, sizeof(bmp_header_v4), &size); // read heaser
|
|
if (res != FR_OK || buf_16[9] != LCD_WIDTH || buf_16[11] != LCD_HEIGHT || buf_16[14] != 16) {error = "Format err"; break;}
|
|
for (y = LCD_HEIGHT-1; y >=0 && res == FR_OK; y--) {
|
|
res = f_read(fs_file, (void *)buf_16, LCD_WIDTH * sizeof(uint16_t), &size);
|
|
swap_bytes(buf_16, LCD_WIDTH);
|
|
ili9341_bulk(0, y, LCD_WIDTH, 1);
|
|
}
|
|
ili9341_drawstring_7x13(fno.fname, 0, LCD_HEIGHT - 3*bFONT_STR_HEIGHT);
|
|
}
|
|
break;
|
|
/*
|
|
* Load calibration
|
|
*/
|
|
// case FMT_CAL_FILE:
|
|
// {
|
|
// uint32_t magic;
|
|
// char *src = (char*)¤t_props + sizeof(magic);
|
|
// uint32_t total = sizeof(current_props) - sizeof(magic);
|
|
// // Compare file size and try read magic header, if all OK load it
|
|
// if (fno.fsize == sizeof(current_props) && f_read(fs_file, &magic, sizeof(magic), &size) == FR_OK &&
|
|
// magic == PROPS_MAGIC && f_read(fs_file, src, total, &size) == FR_OK)
|
|
// load_properties(NO_SAVE_SLOT);
|
|
// else error = "Format err";
|
|
// }
|
|
// break;
|
|
/*
|
|
* Load preset
|
|
*/
|
|
case FMT_PRS_FILE:
|
|
{
|
|
uint32_t magic;
|
|
char *src = (char*)&setting + sizeof(magic);
|
|
uint32_t total = sizeof(setting_t) - sizeof(magic);
|
|
// Compare file size and try read magic header, if all OK load it
|
|
if (fno.fsize == sizeof(setting) && f_read(fs_file, &magic, sizeof(magic), &size) == FR_OK &&
|
|
magic == SETTING_MAGIC && f_read(fs_file, src, total, &size) == FR_OK) {
|
|
|
|
// TODO remove code duplication with flash.c
|
|
update_min_max_freq();
|
|
update_frequencies();
|
|
set_scale(setting.scale);
|
|
set_reflevel(setting.reflevel);
|
|
set_waterfall();
|
|
set_level_meter();
|
|
}
|
|
else error = "Format err";
|
|
}
|
|
break;
|
|
/*
|
|
* Load preset
|
|
*/
|
|
case FMT_CFG_FILE:
|
|
{
|
|
uint32_t magic;
|
|
char *src = (char*)&config + sizeof(magic);
|
|
uint32_t total = sizeof(config_t) - sizeof(magic);
|
|
// Compare file size and try read magic header, if all OK load it
|
|
if (fno.fsize == sizeof(config) && f_read(fs_file, &magic, sizeof(magic), &size) == FR_OK &&
|
|
magic == CONFIG_MAGIC && f_read(fs_file, src, total, &size) == FR_OK) {
|
|
config_save();
|
|
drawMessageBox("Info", "Restart tinySA to load new config", 2000);
|
|
}
|
|
else error = "Format err";
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
f_close(fs_file);
|
|
if (error) {
|
|
ili9341_clear_screen();
|
|
drawMessageBox(error, fno.fname, leave_show ? 2000 : 0);
|
|
} else
|
|
if (leave_show) drawMessageBox("Loaded", fno.fname, leave_show ? 1000 : 0);
|
|
if (leave_show) return;
|
|
// Process input
|
|
while (1) {
|
|
uint16_t status = btn_check();
|
|
int key = -1;
|
|
if (status & EVT_DOWN) key = 0;
|
|
if (status & EVT_UP ) key = 1;
|
|
if (status & EVT_BUTTON_SINGLE_CLICK) key = 2;
|
|
|
|
status = touch_check();
|
|
if (status == EVT_TOUCH_PRESSED || status == EVT_TOUCH_DOWN) {
|
|
int touch_x, touch_y;
|
|
touch_position(&touch_x, &touch_y);
|
|
if (touch_x < LCD_WIDTH *1/3) key = 0;
|
|
else if (touch_x < LCD_WIDTH *2/3) key = 2;
|
|
else key = 1;
|
|
touch_wait_release();
|
|
}
|
|
chThdSleepMilliseconds(100);
|
|
int old_sel = sel;
|
|
if (key == 0) {if (--sel < 0) sel = file_count - 1;}
|
|
else if (key == 1) {if (++sel > file_count - 1) sel = 0;}
|
|
else if (key == 2) break;
|
|
if (old_sel != sel) goto repeat;
|
|
}
|
|
}
|
|
|
|
static void browser_draw_buttons(void) {
|
|
browser_draw_button(FILE_BUTTON_DEL, "DEL");
|
|
browser_draw_button(FILE_BUTTON_LEFT, "<");
|
|
browser_draw_button(FILE_BUTTON_RIGHT, ">");
|
|
browser_draw_button(FILE_BUTTON_EXIT, "X");
|
|
}
|
|
|
|
static void browser_draw_page(int page) {
|
|
FILINFO fno;
|
|
DIR dj;
|
|
// Mount SD card and open directory
|
|
if (f_mount(fs_volume, "", 1) != FR_OK ||
|
|
sd_open_dir(&dj, "", file_ext[keypad_mode]) != FR_OK) {
|
|
drawMessageBox("ERROR", "NO CARD", 2000);
|
|
ui_mode_normal();
|
|
return;
|
|
}
|
|
// Draw Browser UI
|
|
int cnt = 0;
|
|
uint16_t start_file = (page - 1) * FILES_PER_PAGE;
|
|
ili9341_set_background(LCD_MENU_COLOR);
|
|
ili9341_clear_screen();
|
|
lcd_set_font(FONT_NORMAL);
|
|
while (sd_findnext(&dj, &fno) == FR_OK) {
|
|
if (cnt >= start_file && cnt < (start_file + FILES_PER_PAGE)) {
|
|
//uint16_t sec = ((fno.ftime<<1) & 0x3F);
|
|
//uint16_t min = ((fno.ftime>>5) & 0x3F);
|
|
//uint16_t h = ((fno.ftime>>11) & 0x1F);
|
|
//uint16_t d = ((fno.fdate>>0) & 0x1F);
|
|
//uint16_t m = ((fno.fdate>>5) & 0x0F);
|
|
//uint16_t year= ((fno.fdate>>9) & 0x3F) + 1980;
|
|
//lcd_printf(x, y, "%2d %s %u - %u/%02u/%02u %02u:%02u:%02u", cnt, fno.fname, fno.fsize, year, m, d, h, min, sec);
|
|
browser_draw_button(cnt - start_file + FILE_BUTTON_FILE, fno.fname);
|
|
}
|
|
cnt++;
|
|
if (file_count && (start_file + FILES_PER_PAGE == cnt)) break;
|
|
}
|
|
f_closedir(&dj);
|
|
// Calculate page and file count on first run
|
|
if (file_count == 0) {
|
|
file_count = cnt;
|
|
page_count = cnt == 0 ? 1 : (file_count + FILES_PER_PAGE - 1) / FILES_PER_PAGE;
|
|
}
|
|
browser_draw_buttons();
|
|
lcd_printf(LCD_WIDTH / 2 - 3 * bFONT_WIDTH, LCD_HEIGHT - (FILE_BOTTOM_HEIGHT + bFONT_STR_HEIGHT) / 2, "- %u | %u -", page, page_count);
|
|
lcd_set_font(FONT_SMALL);
|
|
return;
|
|
}
|
|
|
|
static void browser_key_press(int key) {
|
|
int page;
|
|
switch (key) {
|
|
case FILE_BUTTON_LEFT:
|
|
case FILE_BUTTON_RIGHT: // Switch page on left / right change
|
|
page = current_page;
|
|
if (key == FILE_BUTTON_LEFT && --current_page < 1) current_page = page_count;
|
|
if (key == FILE_BUTTON_RIGHT && ++current_page > page_count) current_page = 1;
|
|
if (page != current_page)
|
|
browser_draw_page(current_page);
|
|
break;
|
|
case FILE_BUTTON_EXIT: //Exit
|
|
ui_mode_normal();
|
|
break;
|
|
case FILE_BUTTON_DEL: // Toggle delete mode
|
|
sel_mode^= 1;
|
|
browser_draw_buttons();
|
|
break;
|
|
case FILE_BUTTON_FILE: // Open or delete file
|
|
default:
|
|
browser_open_file(key - FILE_BUTTON_FILE + (current_page - 1) * FILES_PER_PAGE);
|
|
if (sel_mode) {
|
|
file_count = 0; // Reeset file count (recalculate on draw page)
|
|
selection = -1; // Reset delection
|
|
sel_mode = 0; // Exit file delete mode
|
|
browser_draw_page(current_page);
|
|
return;
|
|
}
|
|
ui_mode_normal(); // Exit
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int browser_get_max(void) {
|
|
// get max buttons depend from page and file count
|
|
int max = current_page == page_count ? (file_count % FILES_PER_PAGE) : FILES_PER_PAGE;
|
|
if (file_count > 0 && max == 0) max = FILES_PER_PAGE;
|
|
return max + FILE_BUTTON_FILE - 1;
|
|
}
|
|
|
|
// Process UI input for browser
|
|
static void browser_apply_touch(int touch_x, int touch_y) {
|
|
browser_btn_t btn;
|
|
int old = selection;
|
|
int max = browser_get_max();
|
|
for (int idx = 0; idx <= max; idx++) {
|
|
browser_get_button_pos(idx, &btn);
|
|
if (touch_x < btn.x || touch_x >= btn.x + btn.w ||
|
|
touch_y < btn.y || touch_y >= btn.y + btn.h) continue;
|
|
// Found button under touch
|
|
browser_draw_button(selection = idx, NULL); // draw new selection
|
|
browser_draw_button(old, NULL); // clear old
|
|
touch_wait_release();
|
|
selection = -1;
|
|
browser_draw_button(idx, NULL); // clear selection
|
|
browser_key_press(idx);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void ui_process_browser_lever(void) {
|
|
uint16_t status = btn_check();
|
|
if (status == 0) return;
|
|
if (status == EVT_BUTTON_SINGLE_CLICK) {
|
|
if (selection >= 0) browser_key_press(selection); // Process click
|
|
return;
|
|
}
|
|
int max = browser_get_max();
|
|
do {
|
|
int old = selection;
|
|
if((status & EVT_DOWN) && --selection < 0) selection = max;
|
|
if((status & EVT_UP) && ++selection > max) selection = 0;
|
|
if (old != selection) {
|
|
browser_draw_button(old, NULL); // clear old selection
|
|
browser_draw_button(selection, NULL); // draw new selection
|
|
}
|
|
chThdSleepMilliseconds(100);
|
|
} while ((status = btn_wait_release()) != 0);
|
|
}
|
|
|
|
static UI_FUNCTION_CALLBACK(menu_sdcard_browse_cb) {
|
|
(void)item;
|
|
if (ui_mode == UI_BROWSER)
|
|
return;
|
|
area_width = 0;
|
|
area_height = 0;
|
|
ui_mode = UI_BROWSER;
|
|
keypad_mode = data;
|
|
current_page = 1;
|
|
|
|
file_count = 0;
|
|
selection = -1;
|
|
sel_mode = 0;
|
|
browser_draw_page(current_page);
|
|
}
|