1
0
mirror of https://github.com/CTCaer/hekate.git synced 2024-10-06 06:29:43 +00:00

[Nyx] Introducing hekate GUI, named Nyx!

Version 0.8.0.

Expect dragons!
This commit is contained in:
ctcaer@gmail.com 2019-06-30 04:03:00 +03:00
parent c0b3a4fc54
commit c41f98039c
308 changed files with 91222 additions and 2 deletions

View File

@ -74,10 +74,11 @@ CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
MODULEDIRS := $(wildcard modules/*)
NYXDIR := $(wildcard nyx)
################################################################################
.PHONY: all clean $(MODULEDIRS)
.PHONY: all clean $(MODULEDIRS) $(NYXDIR)
all: $(TARGET).bin
@echo -n "Payload size is "
@ -92,7 +93,10 @@ clean:
$(MODULEDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)$(MAKEFLAGS)
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(MODULEDIRS)
$(NYXDIR):
$(MAKE) -C $@ $(MAKECMDGOALS)$(MAKEFLAGS)
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(MODULEDIRS) $(NYXDIR)
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@
@printf ICTC49 >> $(OUTPUTDIR)/$@

117
nyx/Makefile Normal file
View File

@ -0,0 +1,117 @@
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/base_rules
################################################################################
NYX_LOAD_ADDR := 0x40003000
NYX_RES_ADDR := 0xEE000000
NYX_STORAGE_ADDR := 0xED000000
NYX_MAGIC := 0x43544347 #"GCTC"
BLVERSION_MAJOR := 0
BLVERSION_MINOR := 8
BLVERSION_HOTFX := 0
BL_RESERVED := 0
################################################################################
TARGET := nyx
BUILDDIR := ./../build
OUTPUTDIR := ./../output
SOURCEDIR = nyx_gui
VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
VPATH += $(dir $(wildcard ./$(SOURCEDIR)/*/*/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/*/*/))
# Main and graphics.
OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
start.o \
nyx.o heap.o \
gfx.o \
gui.o gui_info.o gui_tools.o gui_emmc_tools.o gui_emummc_tools.o \
fe_emummc_tools.o fe_emmc_tools.o \
)
# Hardware.
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
bpmp.o clock.o cluster.o di.o gpio.o i2c.o mc.o sdram.o pinmux.o se.o smmu.o tsec.o uart.o \
fuse.o kfuse.o minerva.o \
sdmmc.o sdmmc_driver.o \
bq24193.o max17050.o max7762x.o max77620-rtc.o \
touch.o tmp451.o fan.o \
hw_init.o \
)
# Utilities.
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
btn.o dirlist.o ianos.o util.o \
config.o ini.o \
sprintf.o \
)
# Horizon.
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
nx_emmc.o \
hos.o pkg1.o pkg2.o sept.o \
)
# Libraries.
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
diskio.o ff.o ffunicode.o ffsystem.o \
elfload.o elfreloc_arm.o \
lv_group.o lv_indev.o lv_obj.o lv_refr.o lv_style.o lv_vdb.o \
lv_draw.o lv_draw_rbasic.o lv_draw_vbasic.o lv_draw_arc.o lv_draw_img.o \
lv_draw_label.o lv_draw_line.o lv_draw_rect.o lv_draw_triangle.o \
lv_hal_disp.o lv_hal_indev.o lv_hal_tick.o \
interui_20.o interui_30.o ubuntu_mono.o hekate_symbol_20.o hekate_symbol_30.o hekate_symbol_120.o lv_font_builtin.o \
lv_anim.o lv_area.o lv_circ.o lv_color.o lv_font.o lv_ll.o lv_math.o lv_mem.o lv_task.o lv_txt.o lv_gc.o \
lv_bar.o lv_btn.o lv_btnm.o lv_cb.o lv_cont.o lv_ddlist.o lv_img.o lv_kb.o lv_label.o lv_line.o lv_list.o lv_lmeter.o lv_mbox.o \
lv_page.o lv_roller.o lv_slider.o lv_sw.o lv_tabview.o lv_ta.o lv_win.o lv_log.o lv_imgbtn.o \
lv_theme.o lv_theme_hekate.o \
)
################################################################################
CUSTOMDEFINES := -DNYX_RES_ADDR=$(NYX_RES_ADDR) -DNYX_STORAGE_ADDR=$(NYX_STORAGE_ADDR)
CUSTOMDEFINES += -DNYX_LOAD_ADDR=$(NYX_LOAD_ADDR) -DBL_MAGIC=$(NYX_MAGIC)
CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BL_RESERVED)
# 0: UART_A, 1: UART_B.
#CUSTOMDEFINES += -DDEBUG_UART_PORT=1
#CUSTOMDEFINES += -DDEBUG
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -flto -fomit-frame-pointer -fno-inline -fno-strict-aliasing -std=gnu11 -Wall $(CUSTOMDEFINES)
CFLAGS += -g
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=NYX_LOAD_ADDR=$(NYX_LOAD_ADDR)
################################################################################
.PHONY: all clean
all: $(TARGET).bin
@echo -n "Nyx size is "
@wc -c < $(OUTPUTDIR)/$(TARGET).bin
clean:
@rm -rf $(OBJS)
@rm -rf $(BUILDDIR)
@rm -rf $(OUTPUTDIR)
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
$(BUILDDIR)/$(TARGET)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
$(BUILDDIR)/$(TARGET)/%.o: %.S
@mkdir -p "$(BUILDDIR)"
@mkdir -p "$(BUILDDIR)/$(TARGET)"
@mkdir -p "$(OUTPUTDIR)"
$(CC) $(CFLAGS) -c $< -o $@

12
nyx/README_RES.md Normal file
View File

@ -0,0 +1,12 @@
# Nyx - Background - Icons
The background for Nyx, must be a 1280 x 720 32-bit BMP. Alpha blending is taken into account. For that reason, if a solid background is required, that value must be 0xFF. There are sites that can produce the correct bmp.
The icons supported are 192 x 192 32-bit BMP. You can utilize transparency at will and make nice mixes with the button background.
## How to configure
The background must go to /bootloader/res/background.bmp
The icons can be utilized either via `[boot entries names]` -> `boot entries names.bmp` or by using `icon={sd path}`, which should point at a bmp.

165
nyx/nyx_gui/config/config.c Normal file
View File

@ -0,0 +1,165 @@
/*
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdlib.h>
#include "config.h"
#include "ini.h"
#include "../gfx/gfx.h"
#include "../libs/fatfs/ff.h"
#include "../soc/fuse.h"
#include "../soc/t210.h"
#include "../utils/btn.h"
#include "../utils/list.h"
#include "../utils/util.h"
extern hekate_config h_cfg;
extern bool sd_mount();
extern void sd_unmount(bool deinit);
void set_default_configuration()
{
h_cfg.autoboot = 0;
h_cfg.autoboot_list = 0;
h_cfg.bootwait = 3;
h_cfg.verification = 1;
h_cfg.se_keygen_done = 0;
h_cfg.sbar_time_keeping = 0;
h_cfg.backlight = 100;
h_cfg.autohosoff = 0;
h_cfg.errors = 0;
h_cfg.autonogc = 1;
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
h_cfg.rcm_patched = fuse_check_patched_rcm();
h_cfg.sd_timeoff = 0;
}
int create_config_entry()
{
if (!sd_mount())
return 1;
char lbuf[16];
FIL fp;
bool mainIniFound = false;
LIST_INIT(ini_sections);
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
mainIniFound = true;
else
{
u8 res = f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ);
if (res == FR_NO_FILE || res == FR_NO_PATH)
{
f_mkdir("bootloader");
f_mkdir("bootloader/ini");
f_mkdir("bootloader/payloads");
f_mkdir("bootloader/sys");
}
else
{
if (!res)
f_close(&fp);
return 1;
}
}
if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
return 1;
// Add config entry.
f_puts("[config]\nautoboot=", &fp);
itoa(h_cfg.autoboot, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nautoboot_list=", &fp);
itoa(h_cfg.autoboot_list, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nbootwait=", &fp);
itoa(h_cfg.bootwait, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nverification=", &fp);
itoa(h_cfg.verification, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nbacklight=", &fp);
itoa(h_cfg.backlight, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nautohosoff=", &fp);
itoa(h_cfg.autohosoff, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nautonogc=", &fp);
itoa(h_cfg.autonogc, lbuf, 10);
f_puts(lbuf, &fp);
if (h_cfg.brand)
{
f_puts("\nbrand=", &fp);
f_puts(h_cfg.brand, &fp);
}
if (h_cfg.tagline)
{
f_puts("\ntagline=", &fp);
f_puts(h_cfg.tagline, &fp);
}
f_puts("\n", &fp);
if (mainIniFound)
{
// Re-construct existing entries.
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
if (!strcmp(ini_sec->name, "config"))
continue;
switch (ini_sec->type)
{
case INI_CHOICE: // Re-construct Boot entry [ ].
f_puts("[", &fp);
f_puts(ini_sec->name, &fp);
f_puts("]\n", &fp);
// Re-construct boot entry's config.
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
f_puts(kv->key, &fp);
f_puts("=", &fp);
f_puts(kv->val, &fp);
f_puts("\n", &fp);
}
break;
case INI_CAPTION: // Re-construct caption entry { }.
f_puts("{", &fp);
f_puts(ini_sec->name, &fp);
f_puts("}\n", &fp);
break;
case INI_NEWLINE: // Re-construct cosmetic newline \n.
f_puts("\n", &fp);
break;
case INI_COMMENT: // Re-construct comment entry #.
f_puts("#", &fp);
f_puts(ini_sec->name, &fp);
f_puts("\n", &fp);
break;
}
}
}
f_close(&fp);
sd_unmount(false);
if (mainIniFound)
ini_free(&ini_sections);
return 0;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#include "../utils/types.h"
typedef struct _hekate_config
{
// Non-volatile config.
u32 autoboot;
u32 autoboot_list;
u32 bootwait;
u32 verification;
u32 backlight;
u32 autohosoff;
u32 autonogc;
char *brand;
char *tagline;
// Global temporary config.
bool se_keygen_done;
u32 sbar_time_keeping;
u32 errors;
int sept_run;
bool rcm_patched;
u32 sd_timeoff;
bool emummc_force_disable;
} hekate_config;
typedef enum
{
ERR_LIBSYS_LP0 = (1 << 0),
} hsysmodule_t;
void set_default_configuration();
int create_config_entry();
#endif /* _CONFIG_H_ */

259
nyx/nyx_gui/config/ini.c Normal file
View File

@ -0,0 +1,259 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "ini.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../utils/dirlist.h"
static char *_strdup(char *str)
{
if (!str)
return NULL;
// Remove starting space.
if (str[0] == ' ' && strlen(str))
str++;
char *res = (char *)malloc(strlen(str) + 1);
strcpy(res, str);
// Remove trailing space.
if (res[strlen(res) - 1] == ' ' && strlen(res))
res[strlen(res) - 1] = 0;
return res;
}
u32 _find_section_name(char *lbuf, u32 lblen, char schar)
{
u32 i;
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
;
lbuf[i] = 0;
return i;
}
ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type)
{
if (csec)
{
list_append(dst, &csec->link);
csec = NULL;
}
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
csec->name = _strdup(name);
csec->type = type;
return csec;
}
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
{
u32 lblen;
u32 pathlen = strlen(ini_path);
u32 k = 0;
char lbuf[512];
char *filelist = NULL;
FIL fp;
ini_sec_t *csec = NULL;
char *filename = (char *)malloc(256);
memcpy(filename, ini_path, pathlen + 1);
// Get all ini filenames.
if (is_dir)
{
filelist = dirlist(filename, "*.ini", false, false);
if (!filelist)
{
free(filename);
return 0;
}
memcpy(filename + pathlen, "/", 2);
pathlen++;
}
do
{
// Copy ini filename in path string.
if (is_dir)
{
if (filelist[k * 256])
{
memcpy(filename + pathlen, &filelist[k * 256], strlen(&filelist[k * 256]) + 1);
k++;
}
else
break;
}
// Open ini.
if (f_open(&fp, filename, FA_READ) != FR_OK)
{
free(filelist);
free(filename);
return 0;
}
do
{
// Fetch one line.
lbuf[0] = 0;
f_gets(lbuf, 512, &fp);
lblen = strlen(lbuf);
// Remove trailing newline.
if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r')
lbuf[lblen - 1] = 0;
if (lblen > 2 && lbuf[0] == '[') // Create new section.
{
_find_section_name(lbuf, lblen, ']');
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
list_init(&csec->kvs);
}
else if (lblen > 2 && lbuf[0] == '{') //Create new caption.
{
_find_section_name(lbuf, lblen, '}');
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
csec->color = 0xFF0AB9E6;
}
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments.
{
_find_section_name(lbuf, lblen, '\0');
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
}
else if (lblen < 2)
{
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
}
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
{
u32 i = _find_section_name(lbuf, lblen, '=');
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
kv->key = _strdup(&lbuf[0]);
kv->val = _strdup(&lbuf[i + 1]);
list_append(&csec->kvs, &kv->link);
}
} while (!f_eof(&fp));
f_close(&fp);
if (csec)
{
list_append(dst, &csec->link);
if (is_dir)
csec = NULL;
}
} while (is_dir);
free(filename);
free(filelist);
return 1;
}
void ini_free(link_t *dst)
{
if (!dst->prev || !dst->next)
return;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, dst, link)
{
if (ini_sec->type == INI_CHOICE)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
free(kv->key);
free(kv->val);
//free(kv);
}
}
free(ini_sec->name);
//free(ini_sec);
}
list_init(dst);
}
ini_sec_t *ini_clone_section(ini_sec_t *cfg)
{
if (cfg == NULL)
return NULL;
ini_sec_t *csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
list_init(&csec->kvs);
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
{
ini_kv_t *kvcfg = (ini_kv_t *)malloc(sizeof(ini_kv_t));
kvcfg->key = _strdup(kv->key);
kvcfg->val = _strdup(kv->val);
list_append(&csec->kvs, &kvcfg->link);
}
return csec;
}
void ini_free_section(ini_sec_t *cfg)
{
if (cfg == NULL)
return;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
{
free(kv->key);
free(kv->val);
//free(kv);
}
//free(cfg);
cfg = NULL;
}
char *ini_check_payload_section(ini_sec_t *cfg)
{
char *path = NULL;
if (cfg == NULL)
return NULL;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
{
if (!strcmp("payload", kv->key))
{
if (!path)
path = _strdup(kv->val);
}
}
if (path)
return path;
else
return NULL;
}

53
nyx/nyx_gui/config/ini.h Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INI_H_
#define _INI_H_
#include "../utils/types.h"
#include "../utils/list.h"
#define INI_CHOICE 3
#define INI_CAPTION 5
#define INI_CHGLINE 6
#define INI_NEWLINE 0xFE
#define INI_COMMENT 0xFF
typedef struct _ini_kv_t
{
char *key;
char *val;
link_t link;
} ini_kv_t;
typedef struct _ini_sec_t
{
char *name;
link_t kvs;
link_t link;
u32 type;
u32 color;
} ini_sec_t;
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
void ini_free(link_t *dst);
ini_sec_t *ini_clone_section(ini_sec_t *cfg);
void ini_free_section(ini_sec_t *cfg);
char *ini_check_payload_section(ini_sec_t *cfg);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2018 Rajko Stojadinovic
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _FE_EMMC_TOOLS_H_
#define _FE_EMMC_TOOLS_H_
#include "gui.h"
typedef enum
{
PART_BOOT = (1 << 0),
PART_SYSTEM = (1 << 1),
PART_USER = (1 << 2),
PART_RAW = (1 << 3),
PART_GP_ALL = (1 << 7)
} emmcPartType_t;
void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui);
void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui);
#endif

View File

@ -0,0 +1,703 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 Rajko Stojadinovic
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//! fix the dram stuff and the pop ups
#include <string.h>
#include <stdlib.h>
#include "gui.h"
#include "fe_emummc_tools.h"
#include "../config/config.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../sec/se.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/sprintf.h"
#include "../utils/util.h"
#define EMMC_BUF_ALIGNED 0xB5000000
#define SDXC_BUF_ALIGNED 0xB6000000
#define MIXD_BUF_ALIGNED 0xB7000000
#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache.
#define OUT_FILENAME_SZ 128
#define SHA256_SZ 0x20
#define MBR_1ST_PART_TYPE_OFF 0x1C2
extern sdmmc_t sd_sdmmc;
extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs;
extern hekate_config h_cfg;
extern bool sd_mount();
extern void sd_unmount(bool deinit);
void save_emummc_cfg(u32 part_idx, u32 sector_start, const char *path)
{
sd_mount();
char lbuf[16];
FIL fp;
if (f_open(&fp, "emuMMC/emummc.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
return;
// Add config entry.
f_puts("[emummc]\nenabled=", &fp);
if (part_idx && sector_start)
{
itoa(part_idx, lbuf, 10);
f_puts(lbuf, &fp);
}
else if(path)
f_puts("1", &fp);
else
f_puts("0", &fp);
if (!sector_start)
f_puts("\nsector=0x0", &fp);
else
{
f_puts("\nsector=0x", &fp);
itoa(sector_start, lbuf, 16);
f_puts(lbuf, &fp);
}
if (path)
{
f_puts("\npath=", &fp);
f_puts(path, &fp);
}
f_puts("\nid=0x0000", &fp);
f_puts("\nnintendo_path=", &fp);
if (path)
{
f_puts(path, &fp);
f_puts("/Nintendo\n", &fp);
}
else
f_puts("\n", &fp);
f_close(&fp);
}
static void _update_emummc_base_folder(char *outFilename, u32 sdPathLen, u32 currPartIdx)
{
if (currPartIdx < 10)
{
outFilename[sdPathLen] = '0';
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
}
else
itoa(currPartIdx, &outFilename[sdPathLen], 10);
}
static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
{
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
static const u32 SECTORS_TO_MIB_COEFF = 11;
u32 multipartSplitSize = 0xFE000000;
u32 totalSectors = part->lba_end - part->lba_start + 1;
u32 currPartIdx = 0;
u32 numSplitParts = 0;
int res = 0;
char *outFilename = sd_path;
u32 sdPathLen = strlen(sd_path);
s_printf(gui->txt_buf, "#96FF00 SD Card free space:# %d MiB\n#96FF00 Total backup size:# %d MiB\n\n",
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF,
totalSectors >> SECTORS_TO_MIB_COEFF);
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
lv_bar_set_value(gui->bar, 0);
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 0%");
manual_system_maintenance(true);
// Check if the USER partition or the RAW eMMC fits the sd card free space.
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
{
s_printf(gui->txt_buf, "\n#FFDD00 Not enough free space for Partial Backup!#\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
return 0;
}
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
if (totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE))
{
u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE;
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
// Continue from where we left, if Partial Backup in progress.
_update_emummc_base_folder(outFilename, sdPathLen, 0);
}
FIL fp;
s_printf(gui->txt_buf, "#96FF00 Filepath:#\n%s\n#96FF00 Filename:# #FF8000 %s#",
gui->base_path, outFilename + strlen(gui->base_path));
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
s_printf(gui->txt_buf, "\n#FF0000 Error (%d) while creating#\n#FFDD00 %s#\n", res, outFilename);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
return 0;
}
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
u32 lba_curr = part->lba_start;
u32 bytesWritten = 0;
u32 prevPct = 200;
int retryCount = 0;
DWORD *clmt = NULL;
u64 totalSize = (u64)((u64)totalSectors << 9);
if (totalSize <= FAT32_FILESIZE_LIMIT)
clmt = f_expand_cltbl(&fp, 0x400000, totalSize);
else
clmt = f_expand_cltbl(&fp, 0x400000, MIN(totalSize, multipartSplitSize));
u32 num = 0;
u32 pct = 0;
lv_obj_set_opa_scale(gui->bar, LV_OPA_COVER);
lv_obj_set_opa_scale(gui->label_pct, LV_OPA_COVER);
while (totalSectors > 0)
{
if (numSplitParts != 0 && bytesWritten >= multipartSplitSize)
{
f_close(&fp);
free(clmt);
memset(&fp, 0, sizeof(fp));
currPartIdx++;
_update_emummc_base_folder(outFilename, sdPathLen, currPartIdx);
// Create next part.
s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path));
lv_label_ins_text(gui->label_info, strlen(lv_label_get_text(gui->label_info)) - 3, gui->txt_buf);
lv_label_cut_text(gui->label_info, strlen(lv_label_get_text(gui->label_info)) - 3, 3);
manual_system_maintenance(true);
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
s_printf(gui->txt_buf, "#FF0000 Error (%d) while creating#\n#FFDD00 %s#\n", res, outFilename);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
return 0;
}
bytesWritten = 0;
totalSize = (u64)((u64)totalSectors << 9);
clmt = f_expand_cltbl(&fp, 0x400000, MIN(totalSize, multipartSplitSize));
}
retryCount = 0;
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
while (!sdmmc_storage_read(storage, lba_curr, num, buf))
{
s_printf(gui->txt_buf,
"#FFDD00 Error reading %d blocks @ LBA %08X,#\n"
"#FFDD00 from eMMC (try %d). #",
num, lba_curr, ++retryCount);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
msleep(150);
if (retryCount >= 3)
{
s_printf(gui->txt_buf, "#FF0000 Aborting...#\nPlease try again...\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
f_close(&fp);
free(clmt);
f_unlink(outFilename);
return 0;
}
else
{
s_printf(gui->txt_buf, "#FFDD00 Retrying...#\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
}
}
res = f_write_fast(&fp, buf, NX_EMMC_BLOCKSIZE * num);
if (res)
{
s_printf(gui->txt_buf, "#FF0000 Fatal error (%d) when writing to SD Card#\nPlease try again...\n", res);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
f_close(&fp);
free(clmt);
f_unlink(outFilename);
return 0;
}
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct)
{
lv_bar_set_value(gui->bar, pct);
s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct);
lv_label_set_text(gui->label_pct, gui->txt_buf);
manual_system_maintenance(true);
prevPct = pct;
}
lba_curr += num;
totalSectors -= num;
bytesWritten += num * NX_EMMC_BLOCKSIZE;
// Force a flush after a lot of data if not splitting.
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
{
f_sync(&fp);
bytesWritten = 0;
}
}
lv_bar_set_value(gui->bar, 100);
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%");
manual_system_maintenance(true);
// Backup operation ended successfully.
f_close(&fp);
free(clmt);
return 1;
}
void dump_emummc_file(emmc_tool_gui_t *gui)
{
FILINFO fno;
int res = 0;
int base_len = 0;
u32 timer = 0;
//! TODO switch to 800MHz
manual_system_maintenance(true);
char *txt_buf = (char *)malloc(0x1000);
gui->txt_buf = txt_buf;
s_printf(txt_buf, "");
lv_label_set_array_text(gui->label_log, txt_buf, 0x1000);
if (!sd_mount())
{
lv_label_set_static_text(gui->label_info, "#FFDD00 Failed to init SD!#");
goto out;
}
lv_label_set_static_text(gui->label_info, "Checking for available free space...");
manual_system_maintenance(true);
// Get SD Card free space for Partial Backup.
f_getfree("", &sd_fs.free_clst, NULL);
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
lv_label_set_static_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
goto out;
}
int i = 0;
char sdPath[OUT_FILENAME_SZ];
// Create Restore folders, if they do not exist.
f_mkdir("emuMMC");
strcpy(sdPath, "emuMMC/SD");
base_len = strlen(sdPath);
gui->base_path = (char *)malloc(OUT_FILENAME_SZ);
for (int j = 0; j < 100; j++)
{
_update_emummc_base_folder(sdPath, base_len, j);
if(f_stat(sdPath, &fno) == FR_NO_FILE)
break;
}
f_mkdir(sdPath);
strcat(sdPath, "/eMMC");
f_mkdir(sdPath);
strcat(sdPath, "/");
strcpy(gui->base_path, sdPath);
timer = get_tmr_s();
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
emmc_part_t bootPart;
memset(&bootPart, 0, sizeof(bootPart));
bootPart.lba_start = 0;
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
for (i = 0; i < 2; i++)
{
memcpy(bootPart.name, "BOOT", 5);
bootPart.name[4] = (u8)('0' + i);
bootPart.name[5] = 0;
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
i, bootPart.name, bootPart.lba_start, bootPart.lba_end);
lv_label_set_array_text(gui->label_info, txt_buf, 0x1000);
s_printf(txt_buf, "%02d: %s... ", i, bootPart.name);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
manual_system_maintenance(true);
sdmmc_storage_set_mmc_partition(&storage, i + 1);
strcat(sdPath, bootPart.name);
res = _dump_emummc_file_part(gui, sdPath, &storage, &bootPart);
if (!res)
{
s_printf(txt_buf, "#FFDD00 Failed!#\n");
goto out_failed;
}
else
s_printf(txt_buf, "Done!\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
manual_system_maintenance(true);
strcpy(sdPath, gui->base_path);
}
// Get GP partition size dynamically.
sdmmc_storage_set_mmc_partition(&storage, 0);
// Get GP partition size dynamically.
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
emmc_part_t rawPart;
memset(&rawPart, 0, sizeof(rawPart));
rawPart.lba_start = 0;
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
strcpy(rawPart.name, "GPP");
{
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
i, rawPart.name, rawPart.lba_start, rawPart.lba_end);
lv_label_set_array_text(gui->label_info, txt_buf, 0x1000);
s_printf(txt_buf, "%02d: %s... ", i, rawPart.name);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
manual_system_maintenance(true);
res = _dump_emummc_file_part(gui, sdPath, &storage, &rawPart);
if (!res)
s_printf(txt_buf, "#FFDD00 Failed!#\n");
else
s_printf(txt_buf, "Done!\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
manual_system_maintenance(true);
}
out_failed:
timer = get_tmr_s() - timer;
sdmmc_storage_end(&storage);
if (res)
{
s_printf(txt_buf, "Time taken: %dm %ds.\nFinished!", timer / 60, timer % 60);
gui->base_path[strlen(gui->base_path) - 5] = '\0';
strcpy(sdPath, gui->base_path);
strcat(sdPath, "file_based");
FIL fp;
f_open(&fp, sdPath, FA_CREATE_ALWAYS | FA_WRITE);
f_close(&fp);
gui->base_path[strlen(gui->base_path) - 1] = 0;
save_emummc_cfg(0, 0, gui->base_path);
}
else
s_printf(txt_buf, "Time taken: %dm %ds.", timer / 60, timer % 60);
lv_label_set_array_text(gui->label_finish, txt_buf, 0x1000);
out:
free(txt_buf);
free(gui->base_path);
sd_unmount(false);
}
static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part_idx, u32 sd_part_off, sdmmc_storage_t *storage, emmc_part_t *part)
{
u32 totalSectors = part->lba_end - part->lba_start + 1;
s_printf(gui->txt_buf, "\n\n\n");
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
lv_bar_set_value(gui->bar, 0);
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 0%");
manual_system_maintenance(true);
s_printf(gui->txt_buf, "#96FF00 Base folder:#\n%s\n#96FF00 Partition offset:# #FF8000 0x%08X#",
gui->base_path, sd_part_off);
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
u32 sd_sector_off = sd_part_off + (0x2000 * active_part);
u32 lba_curr = part->lba_start;
u32 prevPct = 200;
int retryCount = 0;
u32 num = 0;
u32 pct = 0;
lv_obj_set_opa_scale(gui->bar, LV_OPA_COVER);
lv_obj_set_opa_scale(gui->label_pct, LV_OPA_COVER);
while (totalSectors > 0)
{
retryCount = 0;
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
// Read data from eMMC.
while (!sdmmc_storage_read(storage, lba_curr, num, buf))
{
s_printf(gui->txt_buf,
"#FFDD00 Error reading %d blocks @LBA %08X,#\n"
"#FFDD00 from eMMC (try %d). #",
num, lba_curr, ++retryCount);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
msleep(150);
if (retryCount >= 3)
{
s_printf(gui->txt_buf, "#FF0000 Aborting...#\nPlease try again...\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
return 0;
}
else
{
s_printf(gui->txt_buf, "#FFDD00 Retrying...#\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
}
}
retryCount = 0;
// Write data to SD card.
while (!sdmmc_storage_write(&sd_storage, sd_sector_off + lba_curr, num, buf))
{
s_printf(gui->txt_buf,
"#FFDD00 Error writing %d blocks @LBA %08X,#\n"
"#FFDD00 to SD (try %d). #",
num, lba_curr, ++retryCount);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
msleep(150);
if (retryCount >= 3)
{
s_printf(gui->txt_buf, "#FF0000 Aborting...#\nPlease try again...\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
return 0;
}
else
{
s_printf(gui->txt_buf, "#FFDD00 Retrying...#\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
}
}
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct)
{
lv_bar_set_value(gui->bar, pct);
s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct);
lv_label_set_text(gui->label_pct, gui->txt_buf);
manual_system_maintenance(true);
prevPct = pct;
}
lba_curr += num;
totalSectors -= num;
}
lv_bar_set_value(gui->bar, 100);
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%");
manual_system_maintenance(true);
// Hide the partition.
if (active_part == 2)
{
u8 *mbr = (u8 *)malloc(0x200);
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
mbr[MBR_1ST_PART_TYPE_OFF + (0x10 * part_idx)] = 0xEE;
sdmmc_storage_write(&sd_storage, 0, 1, mbr);
free(mbr);
}
return 1;
}
void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start)
{
int res = 0;
u32 timer = 0;
//! TODO switch to 800MHz
manual_system_maintenance(true);
char *txt_buf = (char *)malloc(0x1000);
gui->txt_buf = txt_buf;
s_printf(txt_buf, "");
lv_label_set_array_text(gui->label_log, txt_buf, 0x1000);
if (!sd_mount())
{
lv_label_set_static_text(gui->label_info, "#FFDD00 Failed to init SD!#");
goto out;
}
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
lv_label_set_static_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
goto out;
}
int i = 0;
char sdPath[OUT_FILENAME_SZ];
// Create Restore folders, if they do not exist.
f_mkdir("emuMMC");
s_printf(sdPath, "emuMMC/RAW%d", part_idx);
gui->base_path = (char *)malloc(OUT_FILENAME_SZ);
f_mkdir(sdPath);
strcat(sdPath, "/");
strcpy(gui->base_path, sdPath);
timer = get_tmr_s();
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
emmc_part_t bootPart;
memset(&bootPart, 0, sizeof(bootPart));
bootPart.lba_start = 0;
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
for (i = 0; i < 2; i++)
{
memcpy(bootPart.name, "BOOT", 5);
bootPart.name[4] = (u8)('0' + i);
bootPart.name[5] = 0;
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
i, bootPart.name, bootPart.lba_start, bootPart.lba_end);
lv_label_set_array_text(gui->label_info, txt_buf, 0x1000);
s_printf(txt_buf, "%02d: %s... ", i, bootPart.name);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
manual_system_maintenance(true);
sdmmc_storage_set_mmc_partition(&storage, i + 1);
strcat(sdPath, bootPart.name);
res = _dump_emummc_raw_part(gui, i, part_idx, sector_start, &storage, &bootPart);
if (!res)
{
s_printf(txt_buf, "#FFDD00 Failed!#\n");
goto out_failed;
}
else
s_printf(txt_buf, "Done!\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
manual_system_maintenance(true);
strcpy(sdPath, gui->base_path);
}
sdmmc_storage_set_mmc_partition(&storage, 0);
// Get GP partition size dynamically.
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
emmc_part_t rawPart;
memset(&rawPart, 0, sizeof(rawPart));
rawPart.lba_start = 0;
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
strcpy(rawPart.name, "GPP");
{
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
i, rawPart.name, rawPart.lba_start, rawPart.lba_end);
lv_label_set_array_text(gui->label_info, txt_buf, 0x1000);
s_printf(txt_buf, "%02d: %s... ", i, rawPart.name);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
manual_system_maintenance(true);
res = _dump_emummc_raw_part(gui, 2, part_idx, sector_start, &storage, &rawPart);
if (!res)
s_printf(txt_buf, "#FFDD00 Failed!#\n");
else
s_printf(txt_buf, "Done!\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
manual_system_maintenance(true);
}
out_failed:
timer = get_tmr_s() - timer;
sdmmc_storage_end(&storage);
if (res)
{
s_printf(txt_buf, "Time taken: %dm %ds.\nFinished!", timer / 60, timer % 60);
strcpy(sdPath, gui->base_path);
strcat(sdPath, "raw_based");
FIL fp;
f_open(&fp, sdPath, FA_CREATE_ALWAYS | FA_WRITE);
f_write(&fp, &sector_start, 4, NULL);
f_close(&fp);
gui->base_path[strlen(gui->base_path) - 1] = 0;
save_emummc_cfg(part_idx, sector_start, gui->base_path);
}
else
s_printf(txt_buf, "Time taken: %dm %ds.", timer / 60, timer % 60);
lv_label_set_array_text(gui->label_finish, txt_buf, 0x1000);
out:
free(txt_buf);
free(gui->base_path);
sd_unmount(false);
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2018 Rajko Stojadinovic
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _FE_EMUMMC_TOOLS_H_
#define _FE_EMUMMC_TOOLS_H_
#include "gui.h"
void save_emummc_cfg(u32 part_idx, u32 sector_start, const char *path);
void dump_emummc_file(emmc_tool_gui_t *gui);
void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start);
#endif

2107
nyx/nyx_gui/frontend/gui.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GUI_H_
#define _GUI_H_
#include "../libs/lvgl/lvgl.h"
typedef struct _emmc_tool_gui_t
{
lv_obj_t *label_log;
lv_obj_t *label_info;
lv_obj_t *label_pct;
lv_obj_t *label_finish;
lv_obj_t *bar;
lv_style_t *bar_teal_bg;
lv_style_t *bar_white_ind;
char *txt_buf;
char *base_path;
bool raw_emummc;
} emmc_tool_gui_t;
lv_style_t hint_small_style;
lv_style_t hint_small_style_white;
lv_style_t monospace_text;
lv_obj_t *payload_list;
lv_img_dsc_t *icon_switch;
lv_img_dsc_t *icon_payload;
lv_img_dsc_t *icon_lakka;
lv_img_dsc_t *hekate_bg;
lv_style_t btn_transp_rel, btn_transp_pr, btn_transp_tgl_rel, btn_transp_tgl_pr;
lv_style_t ddlist_transp_bg, ddlist_transp_sel;
lv_style_t tabview_btn_pr, tabview_btn_tgl_pr;
lv_style_t mbox_darken;
lv_img_dsc_t *bmp_to_lvimg_obj(const char *path);
lv_res_t mbox_action(lv_obj_t * btns, const char * txt);
void nyx_window_toggle_buttons(lv_obj_t *win, bool disable);
lv_obj_t *nyx_create_standard_window(const char *win_title);
void nyx_create_onoff_button(lv_theme_t *th, lv_obj_t *parent, lv_obj_t *btn, const char *btn_name, lv_action_t action, bool transparent);
lv_res_t nyx_generic_onoff_toggle(lv_obj_t *btn);
void manual_system_maintenance(bool refresh);
void nyx_load_and_run();
#endif

View File

@ -0,0 +1,458 @@
/*
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include "gui.h"
#include "gui_emmc_tools.h"
#include "fe_emmc_tools.h"
#include "../config/config.h"
#include "../hos/pkg1.h"
#include "../hos/pkg2.h"
#include "../hos/hos.h"
#include "../hos/sept.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../sec/se.h"
#include "../soc/fuse.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/sprintf.h"
#include "../utils/util.h"
extern boot_cfg_t b_cfg;
extern hekate_config h_cfg;
extern bool sd_mount();
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
#pragma GCC push_options
#pragma GCC target ("thumb")
typedef struct _emmc_backup_buttons_t
{
lv_obj_t *emmc_boot;
lv_obj_t *emmc_raw_gpp;
lv_obj_t *emmc_sys;
lv_obj_t *emmc_usr;
bool raw_emummc;
bool restore;
} emmc_backup_buttons_t;
static emmc_backup_buttons_t emmc_btn_ctxt;
static void _create_window_backup_restore(emmcPartType_t type, const char* win_label)
{
emmc_tool_gui_t emmc_tool_gui_ctxt;
emmc_tool_gui_ctxt.raw_emummc = emmc_btn_ctxt.raw_emummc;
lv_obj_t *win = nyx_create_standard_window(win_label);
//Disable buttons.
nyx_window_toggle_buttons(win, true);
// Create important info container.
lv_obj_t *h1 = lv_cont_create(win, NULL);
lv_cont_set_fit(h1, false, true);
lv_obj_set_width(h1, (LV_HOR_RES / 9) * 5);
lv_obj_set_click(h1, false);
lv_cont_set_layout(h1, LV_LAYOUT_OFF);
static lv_style_t h_style;
lv_style_copy(&h_style, lv_cont_get_style(h1));
h_style.body.main_color = LV_COLOR_HEX(0x1d1d1d);
h_style.body.grad_color = h_style.body.main_color;
h_style.body.opa = LV_OPA_COVER;
// Create log container.
lv_obj_t *h2 = lv_cont_create(win, h1);
lv_cont_set_style(h2, &h_style);
lv_cont_set_fit(h2, false, false);
lv_obj_set_size(h2, (LV_HOR_RES / 11) * 4, LV_DPI * 5);
lv_cont_set_layout(h2, LV_LAYOUT_OFF);
lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, 0, LV_DPI / 5);
lv_obj_t *label_log = lv_label_create(h2, NULL);
lv_label_set_recolor(label_log, true);
lv_obj_set_style(label_log, &monospace_text);
lv_label_set_long_mode(label_log, LV_LABEL_LONG_BREAK);
lv_label_set_static_text(label_log, "");
lv_obj_set_width(label_log, lv_obj_get_width(h2));
lv_obj_align(label_log, h2, LV_ALIGN_IN_TOP_LEFT, LV_DPI / 10, LV_DPI / 10);
emmc_tool_gui_ctxt.label_log = label_log;
lv_obj_t *label_sep = lv_label_create(h1, NULL);
lv_label_set_static_text(label_sep, "");
// Create info elements.
lv_obj_t *label_info = lv_label_create(h1, NULL);
lv_label_set_recolor(label_info, true);
lv_obj_set_width(label_info, lv_obj_get_width(h1));
lv_label_set_static_text(label_info, "\n\n\n\n\n\n\n\n\n");
lv_obj_set_style(label_info, lv_theme_get_current()->label.prim);
lv_obj_align(label_info, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 10);
emmc_tool_gui_ctxt.label_info = label_info;
lv_style_t *bar_teal_bg, *bar_white_ind;
bar_teal_bg = (lv_style_t *)malloc(sizeof(lv_style_t));
bar_white_ind = (lv_style_t *)malloc(sizeof(lv_style_t));
lv_style_copy(bar_teal_bg, lv_theme_get_current()->bar.bg);
bar_teal_bg->body.main_color = LV_COLOR_HEX(0x005a47);
bar_teal_bg->body.grad_color = bar_teal_bg->body.main_color;
lv_style_copy(bar_white_ind, lv_theme_get_current()->bar.indic);
bar_white_ind->body.main_color = LV_COLOR_HEX(0xF0F0F0);
bar_white_ind->body.grad_color = bar_white_ind->body.main_color;
emmc_tool_gui_ctxt.bar_teal_bg = bar_teal_bg;
emmc_tool_gui_ctxt.bar_white_ind = bar_white_ind;
lv_obj_t * bar = lv_bar_create(h1, NULL);
lv_obj_set_size(bar, LV_DPI * 38 / 10, LV_DPI / 5);
lv_bar_set_range(bar, 0, 100);
lv_bar_set_value(bar, 0);
lv_obj_align(bar, label_info, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 8);
lv_obj_set_opa_scale(bar, LV_OPA_0);
lv_obj_set_opa_scale_enable(bar, true);
emmc_tool_gui_ctxt.bar = bar;
lv_obj_t *label_pct= lv_label_create(h1, NULL);
lv_label_set_recolor(label_pct, true);
lv_label_set_static_text(label_pct, " "SYMBOL_DOT" 0%");
lv_obj_set_style(label_pct, lv_theme_get_current()->label.prim);
lv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0);
lv_obj_set_opa_scale(label_pct, LV_OPA_0);
lv_obj_set_opa_scale_enable(label_pct, true);
emmc_tool_gui_ctxt.label_pct = label_pct;
lv_obj_t *label_finish = lv_label_create(h1, NULL);
lv_label_set_recolor(label_finish, true);
lv_label_set_static_text(label_finish, "");
lv_obj_set_style(label_finish, lv_theme_get_current()->label.prim);
lv_obj_align(label_finish, bar, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 9 / 20);
emmc_tool_gui_ctxt.label_finish = label_finish;
if (!emmc_btn_ctxt.restore)
dump_emmc_selected(type, &emmc_tool_gui_ctxt);
else
restore_emmc_selected(type, &emmc_tool_gui_ctxt);
nyx_window_toggle_buttons(win, false);
free(bar_teal_bg);
free(bar_white_ind);
}
static lv_res_t _emmc_backup_buttons_decider(lv_obj_t *btn)
{
char *win_label = lv_label_get_text(lv_obj_get_child(btn, NULL));
if (emmc_btn_ctxt.emmc_boot == btn)
_create_window_backup_restore(PART_BOOT, win_label);
else if (emmc_btn_ctxt.emmc_raw_gpp == btn)
_create_window_backup_restore(PART_RAW, win_label);
else if (emmc_btn_ctxt.emmc_sys == btn)
{
if (!emmc_btn_ctxt.restore)
_create_window_backup_restore(PART_SYSTEM, win_label);
else
_create_window_backup_restore(PART_GP_ALL, win_label);
}
else if (!emmc_btn_ctxt.restore && emmc_btn_ctxt.emmc_usr == btn)
_create_window_backup_restore(PART_USER, win_label);
return LV_RES_OK;
}
static lv_res_t _emmc_backup_buttons_raw_toggle(lv_obj_t *btn)
{
nyx_generic_onoff_toggle(btn);
lv_obj_set_click(emmc_btn_ctxt.emmc_boot, true);
lv_btn_set_state(emmc_btn_ctxt.emmc_boot, LV_BTN_STATE_REL);
lv_obj_set_click(emmc_btn_ctxt.emmc_raw_gpp, true);
lv_btn_set_state(emmc_btn_ctxt.emmc_raw_gpp, LV_BTN_STATE_REL);
lv_obj_set_click(emmc_btn_ctxt.emmc_sys, true);
lv_btn_set_state(emmc_btn_ctxt.emmc_sys, LV_BTN_STATE_REL);
// Backup/Restore from and to eMMC.
if (!(lv_btn_get_state(btn) & LV_BTN_STATE_TGL_REL))
{
if (!emmc_btn_ctxt.restore)
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_UPLOAD" eMMC BOOT0 & BOOT1");
else
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_DOWNLOAD" eMMC BOOT0 & BOOT1");
lv_obj_realign(emmc_btn_ctxt.emmc_boot);
if (!emmc_btn_ctxt.restore)
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_DOWNLOAD" eMMC RAW GPP");
else
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_DOWNLOAD" eMMC RAW GPP");
lv_obj_realign(emmc_btn_ctxt.emmc_raw_gpp);
if (!emmc_btn_ctxt.restore)
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_sys, NULL), SYMBOL_MODULES" eMMC SYS");
else
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_sys, NULL), SYMBOL_MODULES" eMMC ALL");
lv_obj_realign(emmc_btn_ctxt.emmc_sys);
if (!emmc_btn_ctxt.restore)
{
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_usr, NULL), SYMBOL_MODULES_ALT" eMMC USER");
lv_obj_realign(emmc_btn_ctxt.emmc_usr);
lv_obj_set_click(emmc_btn_ctxt.emmc_usr, true);
lv_btn_set_state(emmc_btn_ctxt.emmc_usr, LV_BTN_STATE_REL);
}
emmc_btn_ctxt.raw_emummc = false;
}
else // Backup/Restore from and to emuMMC.
{
if (!emmc_btn_ctxt.restore)
{
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_UPLOAD" SD emuMMC BOOT0 & BOOT1");
lv_obj_set_click(emmc_btn_ctxt.emmc_boot, false);
lv_btn_set_state(emmc_btn_ctxt.emmc_boot, LV_BTN_STATE_INA);
}
else
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_DOWNLOAD" SD emuMMC BOOT0 & BOOT1");
lv_obj_realign(emmc_btn_ctxt.emmc_boot);
if (!emmc_btn_ctxt.restore)
{
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_DOWNLOAD" SD emuMMC RAW GPP");
lv_obj_set_click(emmc_btn_ctxt.emmc_raw_gpp, false);
lv_btn_set_state(emmc_btn_ctxt.emmc_raw_gpp, LV_BTN_STATE_INA);
}
else
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_DOWNLOAD" SD emuMMC RAW GPP");
lv_obj_realign(emmc_btn_ctxt.emmc_raw_gpp);
lv_obj_set_click(emmc_btn_ctxt.emmc_sys, false);
lv_btn_set_state(emmc_btn_ctxt.emmc_sys, LV_BTN_STATE_INA);
if (!emmc_btn_ctxt.restore)
{
lv_obj_set_click(emmc_btn_ctxt.emmc_usr, false);
lv_btn_set_state(emmc_btn_ctxt.emmc_usr, LV_BTN_STATE_INA);
}
emmc_btn_ctxt.raw_emummc = true;
}
return LV_RES_OK;
}
lv_res_t create_window_backup_restore_tool(lv_obj_t *btn)
{
lv_obj_t *win;
emmc_btn_ctxt.restore = false;
if (strcmp(lv_label_get_text(lv_obj_get_child(btn, NULL)), SYMBOL_UPLOAD" Backup eMMC"))
emmc_btn_ctxt.restore = true;
if (!emmc_btn_ctxt.restore)
win = nyx_create_standard_window(SYMBOL_SD" Backup");
else
win = nyx_create_standard_window(SYMBOL_SD" Restore");
static lv_style_t h_style;
lv_style_copy(&h_style, &lv_style_transp);
h_style.body.padding.inner = 0;
h_style.body.padding.hor = LV_DPI - (LV_DPI / 4);
h_style.body.padding.ver = LV_DPI / 9;
// Create Full container.
lv_obj_t *h1 = lv_cont_create(win, NULL);
lv_cont_set_style(h1, &h_style);
lv_cont_set_fit(h1, false, true);
lv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);
lv_obj_set_click(h1, false);
lv_cont_set_layout(h1, LV_LAYOUT_OFF);
lv_obj_t *label_sep = lv_label_create(h1, NULL);
lv_label_set_static_text(label_sep, "");
lv_obj_t *label_txt = lv_label_create(h1, NULL);
lv_label_set_static_text(label_txt, "Full");
lv_obj_set_style(label_txt, lv_theme_get_current()->label.prim);
lv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10);
lv_obj_t *line_sep = lv_line_create(h1, NULL);
static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };
lv_line_set_points(line_sep, line_pp, 2);
lv_line_set_style(line_sep, lv_theme_get_current()->line.decor);
lv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);
// Create BOOT0 & BOOT1 button.
lv_obj_t *btn1 = lv_btn_create(h1, NULL);
lv_obj_t *label_btn = lv_label_create(btn1, NULL);
lv_btn_set_fit(btn1, true, true);
if (!emmc_btn_ctxt.restore)
lv_label_set_static_text(label_btn, SYMBOL_UPLOAD" eMMC BOOT0 & BOOT1");
else
lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" eMMC BOOT0 & BOOT1");
lv_obj_align(btn1, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);
lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _emmc_backup_buttons_decider);
emmc_btn_ctxt.emmc_boot = btn1;
lv_obj_t *label_txt2 = lv_label_create(h1, NULL);
lv_label_set_recolor(label_txt2, true);
if (!emmc_btn_ctxt.restore)
{
lv_label_set_static_text(label_txt2,
"Allows you to backup your BOOT physical partitions.\n"
"They contain your BCT, keys and various package1.\n"
"#FF8000 These are paired with the RAW GPP backup.#");
}
else
{
lv_label_set_static_text(label_txt2,
"Allows you to restore your BOOT physical partitions.\n"
"They contain your BCT, keys and various package1.\n"
"#FF8000 These are paired with the RAW GPP restore.#");
}
lv_obj_set_style(label_txt2, &hint_small_style);
lv_obj_align(label_txt2, btn1, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
// Create RAW GPP button.
lv_obj_t *btn2 = lv_btn_create(h1, btn1);
label_btn = lv_label_create(btn2, NULL);
if (!emmc_btn_ctxt.restore)
lv_label_set_static_text(label_btn, SYMBOL_UPLOAD" eMMC RAW GPP");
else
lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" eMMC RAW GPP");
lv_obj_align(btn2, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);
lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _emmc_backup_buttons_decider);
emmc_btn_ctxt.emmc_raw_gpp= btn2;
label_txt2 = lv_label_create(h1, NULL);
lv_label_set_recolor(label_txt2, true);
if (!emmc_btn_ctxt.restore)
{
lv_label_set_static_text(label_txt2,
"Allows you to backup your GPP physical partition.\n"
"It contains, CAL0, various package2, SYSTEM, USER, etc.\n"
"#FF8000 This is paired with the BOOT0/1 backups.#");
}
else
{
lv_label_set_static_text(label_txt2,
"Allows you to restore your GPP physical partition.\n"
"It contains, CAL0, various package2, SYSTEM, USER, etc.\n"
"#FF8000 This is paired with the BOOT0/1 restore.#");
}
lv_obj_set_style(label_txt2, &hint_small_style);
lv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
// Create GPP Partitions container.
lv_obj_t *h2 = lv_cont_create(win, NULL);
lv_cont_set_style(h2, &h_style);
lv_cont_set_fit(h2, false, true);
lv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);
lv_obj_set_click(h2, false);
lv_cont_set_layout(h2, LV_LAYOUT_OFF);
lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 17 / 29, 0);
label_sep = lv_label_create(h2, NULL);
lv_label_set_static_text(label_sep, "");
lv_obj_t *label_txt3 = lv_label_create(h2, NULL);
lv_label_set_static_text(label_txt3, "GPP Partitions");
lv_obj_set_style(label_txt3, lv_theme_get_current()->label.prim);
lv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 4 / 21);
line_sep = lv_line_create(h2, line_sep);
lv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);
// Create SYS/ALL button.
lv_obj_t *btn3 = lv_btn_create(h2, NULL);
label_btn = lv_label_create(btn3, NULL);
lv_btn_set_fit(btn3, true, true);
if (!emmc_btn_ctxt.restore)
lv_label_set_static_text(label_btn, SYMBOL_MODULES" eMMC SYS");
else
lv_label_set_static_text(label_btn, SYMBOL_MODULES" eMMC ALL");
lv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);
lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _emmc_backup_buttons_decider);
emmc_btn_ctxt.emmc_sys = btn3;
lv_obj_t *label_txt4 = lv_label_create(h2, NULL);
lv_label_set_recolor(label_txt4, true);
if (!emmc_btn_ctxt.restore)
{
lv_label_set_static_text(label_txt4,
"Allows you to backup the partitions from RAW GPP except\n"
"USER. It contains, CAL0, various package2, SYSTEM, etc.\n"
"#FF8000 This is an incomplete backup.#");
}
else
{
lv_label_set_static_text(label_txt4,
"Allows you to restore ALL partitions from RAW GPP\n"
"It contains, CAL0, various package2, SYSTEM, USER, etc.\n");
}
lv_obj_set_style(label_txt4, &hint_small_style);
lv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
// Create USER button.
if (!emmc_btn_ctxt.restore)
{
lv_obj_t *btn4 = lv_btn_create(h2, btn1);
label_btn = lv_label_create(btn4, NULL);
lv_label_set_static_text(label_btn, SYMBOL_MODULES_ALT" eMMC USER");
lv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);
lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _emmc_backup_buttons_decider);
emmc_btn_ctxt.emmc_usr = btn4;
label_txt4 = lv_label_create(h2, NULL);
lv_label_set_recolor(label_txt4, true);
lv_label_set_static_text(label_txt4,
"Allows you to backup the USER partition from RAW GPP.\n"
"#FF8000 This is an incomplete backup.#\n");
lv_obj_set_style(label_txt4, &hint_small_style);
lv_obj_align(label_txt4, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
}
else
{
emmc_btn_ctxt.emmc_usr = NULL;
}
// Create eMMC/emuMMC On/Off button.
lv_obj_t *h3 = lv_cont_create(win, NULL);
lv_cont_set_style(h3, &h_style);
lv_cont_set_fit(h3, false, true);
lv_obj_set_width(h3, (LV_HOR_RES / 10) * 4);
lv_obj_set_click(h3, false);
lv_cont_set_layout(h3, LV_LAYOUT_OFF);
lv_obj_align(h3, h1, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 38 / 11, LV_DPI / 7);
lv_obj_t *sd_emummc_raw = lv_btn_create(h3, NULL);
nyx_create_onoff_button(lv_theme_get_current(), h3,
sd_emummc_raw, SYMBOL_SD" SD emuMMC Raw Partition", _emmc_backup_buttons_raw_toggle, false);
emmc_btn_ctxt.raw_emummc = false;
return LV_RES_OK;
}
#pragma GCC pop_options

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GUI_EMMC_TOOLS_H_
#define _GUI_EMMC_TOOLS_H_
#include "../libs/lvgl/lvgl.h"
lv_res_t create_window_backup_restore_tool(lv_obj_t *btn);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GUI_EMUMMC_TOOLS_H_
#define _GUI_EMUMMC_TOOLS_H_
#include "../libs/lvgl/lvgl.h"
lv_res_t create_win_emummc_tools(lv_obj_t *btn);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GUI_INFO_H_
#define _GUI_INFO_H_
#include "../libs/lvgl/lvgl.h"
void create_tab_info(lv_theme_t *th, lv_obj_t *parent);
#endif

View File

@ -0,0 +1,902 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include "gui.h"
#include "gui_emmc_tools.h"
#include "../config/config.h"
#include "../hos/pkg1.h"
#include "../hos/pkg2.h"
#include "../hos/hos.h"
#include "../hos/sept.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../sec/se.h"
#include "../soc/fuse.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/sprintf.h"
#include "../utils/util.h"
extern volatile boot_cfg_t *b_cfg;
extern hekate_config h_cfg;
extern bool sd_mount();
extern void sd_unmount(bool deinit);
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
#pragma GCC push_options
#pragma GCC target ("thumb")
static bool _get_autorcm_status(bool change)
{
u8 corr_mod_byte0;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
bool enabled = false;
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
u8 *tempbuf = (u8 *)malloc(0x200);
sdmmc_storage_set_mmc_partition(&storage, 1);
sdmmc_storage_read(&storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf);
if ((fuse_read_odm(4) & 3) != 3)
corr_mod_byte0 = 0xF7;
else
corr_mod_byte0 = 0x37;
if (tempbuf[0x10] != corr_mod_byte0)
enabled = true;
// Change autorcm status if requested.
if (change)
{
int i, sect = 0;
u8 randomXor = 0;
for (i = 0; i < 4; i++)
{
sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE;
sdmmc_storage_read(&storage, sect, 1, tempbuf);
if (!enabled)
{
do
{
randomXor = get_tmr_us() & 0xFF; // Bricmii style of bricking.
} while (!randomXor); // Avoid the lottery.
tempbuf[0x10] ^= randomXor;
}
else
tempbuf[0x10] = corr_mod_byte0;
sdmmc_storage_write(&storage, sect, 1, tempbuf);
}
enabled = !(enabled);
}
free(tempbuf);
sdmmc_storage_end(&storage);
return enabled;
}
static lv_res_t _create_mbox_autorcm_status(lv_obj_t *btn)
{
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
lv_obj_set_style(dark_bg, &mbox_darken);
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
static const char * mbox_btn_map[] = { "\211", "\222OK", "\211", "" };
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
lv_mbox_set_recolor_text(mbox, true);
bool enabled = _get_autorcm_status(true);
if (enabled)
{
lv_mbox_set_text(mbox,
"AutoRCM is now #C7EA46 ENABLED!#\n\n"
"You can now automatically enter RCM by only pressing #FF8000 POWER#.\n"
"Use the AutoRCM button here again if you want to remove it later on.");
}
else
{
lv_mbox_set_text(mbox,
"AutoRCM is now #FF8000 DISABLED!#\n\n"
"The boot process is now normal and you need the #FF8000 VOL-# + #FF8000 HOME# (jig) combo to enter RCM.\n");
}
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_top(mbox, true);
if (enabled)
lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);
else
lv_btn_set_state(btn, LV_BTN_STATE_REL);
nyx_generic_onoff_toggle(btn);
return LV_RES_OK;
}
static int _fix_attributes(u32 *ufidx, lv_obj_t *lb_val, char *path, u32 *total, u32 hos_folder, u32 check_first_run)
{
FRESULT res;
DIR dir;
u32 dirLength = 0;
static FILINFO fno;
if (check_first_run)
{
// Read file attributes.
res = f_stat(path, &fno);
if (res != FR_OK)
return res;
// Check if archive bit is set.
if (fno.fattrib & AM_ARC)
{
*(u32 *)total = *(u32 *)total + 1;
f_chmod(path, 0, AM_ARC);
}
}
// Open directory.
res = f_opendir(&dir, path);
if (res != FR_OK)
return res;
dirLength = strlen(path);
for (;;)
{
// Clear file or folder path.
path[dirLength] = 0;
// Read a directory item.
res = f_readdir(&dir, &fno);
// Break on error or end of dir.
if (res != FR_OK || fno.fname[0] == 0)
break;
// Skip official Nintendo dir if started from root.
if (!hos_folder && !strcmp(fno.fname, "Nintendo"))
continue;
// Set new directory or file.
memcpy(&path[dirLength], "/", 1);
memcpy(&path[dirLength + 1], fno.fname, strlen(fno.fname) + 1);
// Check if archive bit is set.
if (fno.fattrib & AM_ARC)
{
*total = *total + 1;
f_chmod(path, 0, AM_ARC);
if (*ufidx == 0)
lv_label_set_array_text(lb_val, path, 256);
*ufidx += 1;
if (*ufidx > 9)
*ufidx = 0;
}
manual_system_maintenance(true);
// Is it a directory?
if (fno.fattrib & AM_DIR)
{
// Set archive bit to NCA folders.
if (hos_folder && !strcmp(fno.fname + strlen(fno.fname) - 4, ".nca"))
{
*total = *total + 1;
f_chmod(path, AM_ARC, AM_ARC);
}
lv_label_set_array_text(lb_val, path, 256);
manual_system_maintenance(true);
// Enter the directory.
res = _fix_attributes(ufidx, lb_val, path, total, hos_folder, 0);
if (res != FR_OK)
break;
}
}
f_closedir(&dir);
return res;
}
static lv_res_t _create_window_unset_abit_tool(lv_obj_t *btn)
{
lv_obj_t *win;
// Find which was called and set window's title.
bool nintendo_folder = false;
if (strcmp(lv_label_get_text(lv_obj_get_child(btn, NULL)), SYMBOL_COPY" Unset archive bit"))
nintendo_folder = true;
if (!nintendo_folder)
win = nyx_create_standard_window(SYMBOL_COPY" Unset archive bit (except Nintendo folder)");
else
win = nyx_create_standard_window(SYMBOL_COPY" Fix archive bit (Nintendo folder)");
// Disable buttons.
nyx_window_toggle_buttons(win, true);
lv_obj_t *desc = lv_cont_create(win, NULL);
lv_obj_set_size(desc, LV_HOR_RES * 10 / 11, LV_VER_RES - (LV_DPI * 11 / 7) * 4);
lv_obj_t * lb_desc = lv_label_create(desc, NULL);
lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);
lv_label_set_recolor(lb_desc, true);
if (!sd_mount())
{
lv_label_set_static_text(lb_desc, "#FFDD00 Failed to init SD!#");
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
}
else
{
if (!nintendo_folder)
lv_label_set_static_text(lb_desc, "#00DDFF Traversing all SD card files!#\nThis may take some time...");
else
lv_label_set_static_text(lb_desc, "#00DDFF Traversing all Nintendo files!#\nThis may take some time...");
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
lv_obj_t *val = lv_cont_create(win, NULL);
lv_obj_set_size(val, LV_HOR_RES * 10 / 11, LV_VER_RES - (LV_DPI * 11 / 7) * 4);
lv_obj_t * lb_val = lv_label_create(val, lb_desc);
char path[256];
path[0] = 0;
lv_label_set_static_text(lb_val, "");
lv_obj_set_width(lb_val, lv_obj_get_width(val));
lv_obj_align(val, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
u32 total = 0;
if (!nintendo_folder)
memcpy(path, "", 1);
else
memcpy(path, "Nintendo", 9);
u32 ufidx = 0;
_fix_attributes(&ufidx, lb_val, path, &total, nintendo_folder, nintendo_folder);
sd_unmount(false);
lv_obj_t *desc2 = lv_cont_create(win, NULL);
lv_obj_set_size(desc2, LV_HOR_RES * 10 / 11, LV_VER_RES - (LV_DPI * 11 / 7) * 4);
lv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc);
char *txt_buf = (char *)malloc(0x500);
s_printf(txt_buf, "#96FF00 Total archive bits fixed:# #FF8000 %d!#", total);
lv_label_set_array_text(lb_desc2, txt_buf, 0x500);
lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));
lv_obj_align(desc2, val, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, 0);
}
// Enable buttons.
nyx_window_toggle_buttons(win, false);
return LV_RES_OK;
}
static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
{
lv_obj_t *win = nyx_create_standard_window(SYMBOL_MODULES" Dump package1/2");
// Disable buttons.
nyx_window_toggle_buttons(win, true);
lv_obj_t *desc = lv_cont_create(win, NULL);
lv_obj_set_size(desc, LV_HOR_RES * 10 / 11, LV_VER_RES - (LV_DPI * 12 / 7));
lv_obj_t * lb_desc = lv_label_create(desc, NULL);
lv_obj_set_style(lb_desc, &monospace_text);
lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);
lv_label_set_recolor(lb_desc, true);
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
if (!sd_mount())
{
lv_label_set_static_text(lb_desc, "#FFDD00 Failed to init SD!#");
goto out_end;
}
char path[128];
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
u8 *warmboot = (u8 *)calloc(1, 0x40000);
u8 *secmon = (u8 *)calloc(1, 0x40000);
u8 *loader = (u8 *)calloc(1, 0x40000);
u8 *pkg2 = NULL;
u8 kb = 0;
char *txt_buf = (char *)malloc(0x1000);
char *txt_buf2 = (char *)malloc(0x1000);
tsec_ctxt_t tsec_ctxt;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
lv_label_set_static_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
goto out_free;
}
sdmmc_storage_set_mmc_partition(&storage, 1);
// Read package1.
char *build_date = malloc(32);
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1, build_date);
s_printf(txt_buf, "#00DDFF Found pkg1 ('%s')#\n\n", build_date);
free(build_date);
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
// Dump package1 in its encrypted state if unknown.
if (!pkg1_id)
{
s_printf(txt_buf + strlen(txt_buf), "#FFDD00 Unknown pkg1 version for reading\nTSEC firmware!#");
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
emmcsn_path_impl(path, "/pkg1", "pkg1_enc.bin", &storage);
if (sd_save_to_file(pkg1, 0x40000, path))
goto out_free;
s_printf(txt_buf + strlen(txt_buf), "\nEncrypted pkg1 dumped to pkg1_enc.bin");
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
goto out_free;
}
const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20);
kb = pkg1_id->kb;
if (!h_cfg.se_keygen_done)
{
tsec_ctxt.fw = (void *)pkg1 + pkg1_id->tsec_off;
tsec_ctxt.pkg1 = (void *)pkg1;
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
if (kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
{
b_cfg->autoboot = 0;
b_cfg->autoboot_list = 0;
if (!reboot_to_sept((u8 *)tsec_ctxt.fw, kb))
{
lv_label_set_static_text(lb_desc, "FFDD00 Failed to run sept#\n");
goto out_free;
}
}
// Read keyblob.
u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob);
// Decrypt.
keygen(keyblob, kb, &tsec_ctxt);
if (kb <= KB_FIRMWARE_VERSION_600)
h_cfg.se_keygen_done = 1;
free(keyblob);
}
if (kb <= KB_FIRMWARE_VERSION_600)
pkg1_decrypt(pkg1_id, pkg1);
if (kb <= KB_FIRMWARE_VERSION_620)
{
pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1);
// Display info.
s_printf(txt_buf + strlen(txt_buf),
"#C7EA46 NX Bootloader size: #0x%05X\n"
"#C7EA46 Secure monitor addr: #0x%05X\n"
"#C7EA46 Secure monitor size: #0x%05X\n"
"#C7EA46 Warmboot addr: #0x%05X\n"
"#C7EA46 Warmboot size: #0x%05X\n\n",
hdr->ldr_size, pkg1_id->secmon_base, hdr->sm_size, pkg1_id->warmboot_base, hdr->wb_size);
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
// Dump package1.1.
emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage);
if (sd_save_to_file(pkg1, 0x40000, path))
goto out_free;
s_printf(txt_buf + strlen(txt_buf), "pkg1 dumped to pkg1_decr.bin\n");
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
// Dump nxbootloader.
emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage);
if (sd_save_to_file(loader, hdr->ldr_size, path))
goto out_free;
s_printf(txt_buf + strlen(txt_buf), "NX Bootloader dumped to nxloader.bin\n");
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
// Dump secmon.
emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage);
if (sd_save_to_file(secmon, hdr->sm_size, path))
goto out_free;
s_printf(txt_buf + strlen(txt_buf), "Secure Monitor dumped to secmon.bin\n");
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
// Dump warmboot.
emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage);
if (sd_save_to_file(warmboot, hdr->wb_size, path))
goto out_free;
s_printf(txt_buf + strlen(txt_buf), "Warmboot dumped to warmboot.bin\n\n");
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
}
// Dump package2.1.
sdmmc_storage_set_mmc_partition(&storage, 0);
// Parse eMMC GPT.
LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage);
// Find package2 partition.
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
if (!pkg2_part)
goto out;
// Read in package2 header and get package2 real size.
u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp);
u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100);
u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3];
free(tmp);
// Read in package2.
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
pkg2 = malloc(pkg2_size_aligned);
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE,
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2);
#if 0
emmcsn_path_impl(path, "/pkg2", "pkg2_encr.bin", &storage);
if (sd_save_to_file(pkg2, pkg2_size_aligned, path))
goto out;
gfx_puts("\npkg2 dumped to pkg2_encr.bin\n");
#endif
// Decrypt package2 and parse KIP1 blobs in INI1 section.
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2);
if (!pkg2_hdr)
{
s_printf(txt_buf + strlen(txt_buf), "FFDD00 Pkg2 decryption failed!#");
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
goto out;
}
// Display info.
s_printf(txt_buf + strlen(txt_buf),
"#C7EA46 Kernel size: #0x%05X\n"
"#C7EA46 INI1 size: #0x%05X\n\n",
pkg2_hdr->sec_size[PKG2_SEC_KERNEL], pkg2_hdr->sec_size[PKG2_SEC_INI1]);
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
// Dump pkg2.1.
emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &storage);
if (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
goto out;
s_printf(txt_buf + strlen(txt_buf), "pkg2 dumped to pkg2_decr.bin\n");
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
// Dump kernel.
emmcsn_path_impl(path, "/pkg2", "kernel.bin", &storage);
if (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path))
goto out;
s_printf(txt_buf + strlen(txt_buf), "Kernel dumped to kernel.bin\n");
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
// Dump INI1.
u32 ini1_off = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
u32 ini1_size = pkg2_hdr->sec_size[PKG2_SEC_INI1];
if (!ini1_size)
{
ini1_off = *(u32 *)(pkg2_hdr->data + PKG2_NEWKERN_INI1_START);
ini1_size = *(u32 *)(pkg2_hdr->data + PKG2_NEWKERN_INI1_END) - *(u32 *)(pkg2_hdr->data + PKG2_NEWKERN_INI1_START);
}
pkg2_ini1_t *ini1 = (pkg2_ini1_t *)(pkg2_hdr->data + ini1_off);
emmcsn_path_impl(path, "/pkg2", "ini1.bin", &storage);
if (sd_save_to_file(ini1, ini1_size, path))
goto out;
s_printf(txt_buf + strlen(txt_buf), "INI1 dumped to ini1.bin\n\n");
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
char filename[32];
u8 *ptr = (u8 *)ini1;
ptr += sizeof(pkg2_ini1_t);
// Dump all kips.
u8 *kip_buffer = (u8 *)malloc(0x400000);
for (u32 i = 0; i < ini1->num_procs; i++)
{
pkg2_kip1_t *kip1 = (pkg2_kip1_t *)ptr;
u32 kip1_size = pkg2_calc_kip1_size(kip1);
s_printf(filename, "%s.kip1", kip1->name);
if ((u32)kip1 % 8)
{
memcpy(kip_buffer, kip1, kip1_size);
kip1 = (pkg2_kip1_t *)kip_buffer;
}
emmcsn_path_impl(path, "/pkg2/ini1", filename, &storage);
if (sd_save_to_file(kip1, kip1_size, path))
{
free(kip_buffer);
goto out;
}
s_printf(txt_buf + strlen(txt_buf), "%s kip dumped to %s.kip1\n", kip1->name, kip1->name);
lv_label_set_array_text(lb_desc, txt_buf, 0x1000);
manual_system_maintenance(true);
ptr += kip1_size;
}
free(kip_buffer);
out:
nx_emmc_gpt_free(&gpt);
out_free:
free(pkg1);
free(secmon);
free(warmboot);
free(loader);
free(pkg2);
free(txt_buf);
free(txt_buf2);
sdmmc_storage_end(&storage);
sd_unmount(false);
if (kb >= KB_FIRMWARE_VERSION_620)
se_aes_key_clear(8);
out_end:
// Enable buttons.
nyx_window_toggle_buttons(win, false);
return LV_RES_OK;
}
void sept_run_dump()
{
_create_window_dump_pk12_tool(NULL);
}
static void _create_tab_tools_emmc_pkg12(lv_theme_t *th, lv_obj_t *parent)
{
lv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY);
static lv_style_t h_style;
lv_style_copy(&h_style, &lv_style_transp);
h_style.body.padding.inner = 0;
h_style.body.padding.hor = LV_DPI - (LV_DPI / 4);
h_style.body.padding.ver = LV_DPI / 6;
// Create Backup & Restore container.
lv_obj_t *h1 = lv_cont_create(parent, NULL);
lv_cont_set_style(h1, &h_style);
lv_cont_set_fit(h1, false, true);
lv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);
lv_obj_set_click(h1, false);
lv_cont_set_layout(h1, LV_LAYOUT_OFF);
lv_obj_t *label_sep = lv_label_create(h1, NULL);
lv_label_set_static_text(label_sep, "");
lv_obj_t *label_txt = lv_label_create(h1, NULL);
lv_label_set_static_text(label_txt, "Backup & Restore");
lv_obj_set_style(label_txt, th->label.prim);
lv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10);
lv_obj_t *line_sep = lv_line_create(h1, NULL);
static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };
lv_line_set_points(line_sep, line_pp, 2);
lv_line_set_style(line_sep, th->line.decor);
lv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);
// Create Backup eMMC button.
lv_obj_t *btn = lv_btn_create(h1, NULL);
if (hekate_bg)
{
lv_btn_set_style(btn, LV_BTN_STYLE_REL, &btn_transp_rel);
lv_btn_set_style(btn, LV_BTN_STYLE_PR, &btn_transp_pr);
}
lv_obj_t *label_btn = lv_label_create(btn, NULL);
lv_btn_set_fit(btn, true, true);
lv_label_set_static_text(label_btn, SYMBOL_UPLOAD" Backup eMMC");
lv_obj_align(btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);
lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, create_window_backup_restore_tool);
lv_obj_t *label_txt2 = lv_label_create(h1, NULL);
lv_label_set_recolor(label_txt2, true);
lv_label_set_static_text(label_txt2,
"Allows you to backup your eMMC partitions individually or as\n"
"a whole raw image to your SD card.\n"
"#FF8000 Supports SD cards from 4GB and up. FAT32 and exFAT.#");
lv_obj_set_style(label_txt2, &hint_small_style);
lv_obj_align(label_txt2, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
// Create Restore eMMC button.
lv_obj_t *btn2 = lv_btn_create(h1, btn);
label_btn = lv_label_create(btn2, NULL);
lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Restore eMMC");
lv_obj_align(btn2, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);
lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, create_window_backup_restore_tool);
label_txt2 = lv_label_create(h1, NULL);
lv_label_set_recolor(label_txt2, true);
lv_label_set_static_text(label_txt2,
"Allows you to restore your eMMC partitions individually or as\n"
"a whole raw image to your SD card.\n"
"#FF8000 Supports SD cards from 4GB and up. FAT32 and exFAT. #");
lv_obj_set_style(label_txt2, &hint_small_style);
lv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
// Create Misc container.
lv_obj_t *h2 = lv_cont_create(parent, NULL);
lv_cont_set_style(h2, &h_style);
lv_cont_set_fit(h2, false, true);
lv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);
lv_obj_set_click(h2, false);
lv_cont_set_layout(h2, LV_LAYOUT_OFF);
lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, 0, 0);
label_sep = lv_label_create(h2, NULL);
lv_label_set_static_text(label_sep, "");
lv_obj_t *label_txt3 = lv_label_create(h2, NULL);
lv_label_set_static_text(label_txt3, "Misc");
lv_obj_set_style(label_txt3, th->label.prim);
lv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10);
line_sep = lv_line_create(h2, line_sep);
lv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);
// Create Dump Package1/2 button.
lv_obj_t *btn3 = lv_btn_create(h2, NULL);
if (hekate_bg)
{
lv_btn_set_style(btn3, LV_BTN_STYLE_REL, &btn_transp_rel);
lv_btn_set_style(btn3, LV_BTN_STYLE_PR, &btn_transp_pr);
}
label_btn = lv_label_create(btn3, NULL);
lv_btn_set_fit(btn3, true, true);
lv_label_set_static_text(label_btn, SYMBOL_MODULES" Dump Package1/2");
lv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);
lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_window_dump_pk12_tool);
lv_obj_t *label_txt4 = lv_label_create(h2, NULL);
lv_label_set_recolor(label_txt4, true);
lv_label_set_static_text(label_txt4,
"Allows you to dump and decrypt pkg1 and pkg2 and further\n"
"split it up into their individual parts. It also dumps the kip1.\n\n");
lv_obj_set_style(label_txt4, &hint_small_style);
lv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
label_sep = lv_label_create(h2, NULL);
lv_label_set_static_text(label_sep, "");
lv_obj_align(label_sep, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 11 / 7);
}
static void _create_tab_tools_arc_autorcm(lv_theme_t *th, lv_obj_t *parent)
{
lv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY);
static lv_style_t h_style;
lv_style_copy(&h_style, &lv_style_transp);
h_style.body.padding.inner = 0;
h_style.body.padding.hor = LV_DPI - (LV_DPI / 4);
h_style.body.padding.ver = LV_DPI / 6;
// Create Misc container.
lv_obj_t *h1 = lv_cont_create(parent, NULL);
lv_cont_set_style(h1, &h_style);
lv_cont_set_fit(h1, false, true);
lv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);
lv_obj_set_click(h1, false);
lv_cont_set_layout(h1, LV_LAYOUT_OFF);
lv_obj_t *label_sep = lv_label_create(h1, NULL);
lv_label_set_static_text(label_sep, "");
lv_obj_t *label_txt = lv_label_create(h1, NULL);
lv_label_set_static_text(label_txt, "Misc");
lv_obj_set_style(label_txt, th->label.prim);
lv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10);
lv_obj_t *line_sep = lv_line_create(h1, NULL);
static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };
lv_line_set_points(line_sep, line_pp, 2);
lv_line_set_style(line_sep, th->line.decor);
lv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);
// Create Unset archive bit button.
lv_obj_t *btn = lv_btn_create(h1, NULL);
if (hekate_bg)
{
lv_btn_set_style(btn, LV_BTN_STYLE_REL, &btn_transp_rel);
lv_btn_set_style(btn, LV_BTN_STYLE_PR, &btn_transp_pr);
}
lv_obj_t *label_btn = lv_label_create(btn, NULL);
lv_btn_set_fit(btn, true, true);
lv_label_set_static_text(label_btn, SYMBOL_COPY" Unset archive bit");
lv_obj_align(btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);
lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _create_window_unset_abit_tool);
lv_obj_t *label_txt2 = lv_label_create(h1, NULL);
lv_label_set_recolor(label_txt2, true);
lv_label_set_static_text(label_txt2,
"Allows you to unset the archive bit for all folders except the\n"
"Nintendo folder.\n"
"#FF8000 If you want the Nintendo folder, use the below option.#");
lv_obj_set_style(label_txt2, &hint_small_style);
lv_obj_align(label_txt2, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
// Create Fix archive bit - Nintendo button.
lv_obj_t *btn2 = lv_btn_create(h1, btn);
label_btn = lv_label_create(btn2, NULL);
lv_label_set_static_text(label_btn, SYMBOL_DIRECTORY" Fix archive bit - Nintendo");
lv_obj_align(btn2, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);
lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _create_window_unset_abit_tool);
label_txt2 = lv_label_create(h1, NULL);
lv_label_set_recolor(label_txt2, true);
lv_label_set_static_text(label_txt2,
"Allows you to fix your Nintendo folder's archive bits.\n"
"They are required for the NCA folders but not anywhere else.\n"
"#FF8000 Use that option when you have corruption messages.#");
lv_obj_set_style(label_txt2, &hint_small_style);
lv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
// Create Others container.
lv_obj_t *h2 = lv_cont_create(parent, NULL);
lv_cont_set_style(h2, &h_style);
lv_cont_set_fit(h2, false, true);
lv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);
lv_obj_set_click(h2, false);
lv_cont_set_layout(h2, LV_LAYOUT_OFF);
lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, 0, 0);
label_sep = lv_label_create(h2, NULL);
lv_label_set_static_text(label_sep, "");
lv_obj_t *label_txt3 = lv_label_create(h2, NULL);
lv_label_set_static_text(label_txt3, "Others");
lv_obj_set_style(label_txt3, th->label.prim);
lv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10);
line_sep = lv_line_create(h2, line_sep);
lv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);
// Create AutoRCM On/Off button.
lv_obj_t *btn3 = lv_btn_create(h2, NULL);
if (hekate_bg)
{
lv_btn_set_style(btn3, LV_BTN_STYLE_REL, &btn_transp_rel);
lv_btn_set_style(btn3, LV_BTN_STYLE_PR, &btn_transp_pr);
lv_btn_set_style(btn3, LV_BTN_STYLE_TGL_REL, &btn_transp_tgl_rel);
lv_btn_set_style(btn3, LV_BTN_STYLE_TGL_PR, &btn_transp_tgl_pr);
}
label_btn = lv_label_create(btn3, NULL);
lv_btn_set_fit(btn3, true, true);
lv_label_set_recolor(label_btn, true);
lv_label_set_static_text(label_btn, SYMBOL_REFRESH" AutoRCM #00ffc9 ON #");
lv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);
lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_mbox_autorcm_status);
// Set default state for AutoRCM and lock it out if patched unit.
if (_get_autorcm_status(false))
lv_btn_set_state(btn3, LV_BTN_STATE_TGL_REL);
else
lv_btn_set_state(btn3, LV_BTN_STATE_REL);
nyx_generic_onoff_toggle(btn3);
if (h_cfg.rcm_patched)
{
lv_obj_set_click(btn3, false);
lv_btn_set_state(btn3, LV_BTN_STATE_INA);
}
char *txt_buf = (char *)malloc(0x1000);
s_printf(txt_buf,
"Allows you to enter RCM without using #C7EA46 VOL-# + #C7EA46 HOME# (jig).\n"
"#FF8000 It can restore all versions of AutoRCM whenever requested.#\n"
"#FF3C28 This corrupts your BCT and you can't boot without a custom#\n"
"#FF3C28 bootloader.#");
if (h_cfg.rcm_patched)
s_printf(txt_buf + strlen(txt_buf), " #FF8000 This is disabled because this unit is patched!#");
lv_obj_t *label_txt4 = lv_label_create(h2, NULL);
lv_label_set_recolor(label_txt4, true);
lv_label_set_array_text(label_txt4, txt_buf, 0x1000);
free(txt_buf);
lv_obj_set_style(label_txt4, &hint_small_style);
lv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
label_sep = lv_label_create(h2, NULL);
lv_label_set_static_text(label_sep, "");
lv_obj_align(label_sep, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 11 / 7);
}
void create_tab_tools(lv_theme_t *th, lv_obj_t *parent)
{
lv_obj_t *tv = lv_tabview_create(parent, NULL);
lv_obj_set_size(tv, LV_HOR_RES, 572);
static lv_style_t tabview_style;
lv_style_copy(&tabview_style, th->tabview.btn.rel);
tabview_style.body.padding.ver = LV_DPI / 8;
lv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_REL, &tabview_style);
if (hekate_bg)
{
lv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_PR, &tabview_btn_pr);
lv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_TGL_PR, &tabview_btn_tgl_pr);
}
lv_tabview_set_sliding(tv, false);
lv_tabview_set_btns_pos(tv, LV_TABVIEW_BTNS_POS_BOTTOM);
lv_obj_t *tab1= lv_tabview_add_tab(tv, "eMMC "SYMBOL_DOT" Package1/2");
lv_obj_t *tab2 = lv_tabview_add_tab(tv, "Archive bit "SYMBOL_DOT" AutoRCM");
_create_tab_tools_emmc_pkg12(th, tab1);
_create_tab_tools_arc_autorcm(th, tab2);
lv_tabview_set_tab_act(tv, 0, false);
}
#pragma GCC pop_options

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GUI_TOOLS_H_
#define _GUI_TOOLS_H_
#include "../libs/lvgl/lvgl.h"
void create_tab_tools(lv_theme_t *th, lv_obj_t *parent);
void sept_run_dump();
#endif

281
nyx/nyx_gui/gfx/di.c Normal file
View File

@ -0,0 +1,281 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "di.h"
#include "../gfx/gfx.h"
#include "../power/max77620.h"
#include "../power/max7762x.h"
#include "../soc/clock.h"
#include "../soc/gpio.h"
#include "../soc/i2c.h"
#include "../soc/pinmux.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
#include "../utils/util.h"
#pragma GCC push_options
#pragma GCC target ("thumb")
#pragma GCC optimize ("Os")
#include "di.inl"
static u32 _display_ver = 0;
static void _display_dsi_wait(u32 timeout, u32 off, u32 mask)
{
u32 end = get_tmr_us() + timeout;
while (get_tmr_us() < end && DSI(off) & mask)
;
usleep(5);
}
void display_init()
{
// Power on.
max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL);
// Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL) = 0xA;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 0xA;
// DPD idle.
PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000;
PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000;
// Config pins.
PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE;
gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); // Backlight +-5V.
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); // Backlight +-5V.
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable.
usleep(10000);
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable.
usleep(10000);
gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); // Backlight PWM, Enable, Reset.
gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE);
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Backlight Enable enable.
// Config display interface and display.
MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4);
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94);
exec_cfg((u32 *)DSI_BASE, _display_config_3, 61);
usleep(10000);
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); // Backlight Reset enable.
usleep(60000);
DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204;
DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
_display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
DSI(_DSIREG(DSI_WR_DATA)) = 0x406; // MIPI_DCS_GET_DISPLAY_ID
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
_display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
DSI(_DSIREG(DSI_HOST_CONTROL)) = DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
_display_dsi_wait(150000, _DSIREG(DSI_HOST_CONTROL), DSI_HOST_CONTROL_IMM_BTA);
usleep(5000);
_display_ver = DSI(_DSIREG(DSI_RD_DATA));
if (_display_ver == 0x10)
exec_cfg((u32 *)DSI_BASE, _display_config_4, 43);
DSI(_DSIREG(DSI_WR_DATA)) = 0x1105; // MIPI_DCS_EXIT_SLEEP_MODE
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
usleep(180000);
DSI(_DSIREG(DSI_WR_DATA)) = 0x2905; // MIPI_DCS_SET_DISPLAY_ON
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
usleep(20000);
exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3);
exec_cfg((u32 *)DSI_BASE, _display_config_5, 21);
DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4;
exec_cfg((u32 *)DSI_BASE, _display_config_7, 10);
usleep(10000);
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6);
exec_cfg((u32 *)DSI_BASE, _display_config_9, 4);
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16);
usleep(10000);
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113);
}
void display_backlight_pwm_init()
{
clock_enable_pwm();
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31); // Enable PWM
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; // PWM clock source.
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
}
void display_backlight(bool enable)
{
gpio_write(GPIO_PORT_V, GPIO_PIN_0, enable ? GPIO_HIGH : GPIO_LOW); // Backlight PWM GPIO.
}
void display_backlight_brightness(u32 brightness, u32 step_delay)
{
u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF;
if (brightness == old_value)
return;
if (brightness > 255)
brightness = 255;
if (old_value < brightness)
{
for (u32 i = old_value; i < brightness + 1; i++)
{
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
usleep(step_delay);
}
}
else
{
for (u32 i = old_value; i > brightness; i--)
{
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
usleep(step_delay);
}
}
if (!brightness)
PWM(PWM_CONTROLLER_PWM_CSR_0) = 0;
}
void display_end()
{
display_backlight_brightness(0, 1000);
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 1;
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF
DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX;
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0;
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17);
exec_cfg((u32 *)DSI_BASE, _display_config_13, 16);
usleep(10000);
if (_display_ver == 0x10)
exec_cfg((u32 *)DSI_BASE, _display_config_14, 22);
DSI(_DSIREG(DSI_WR_DATA)) = 0x1005; // MIPI_DCS_ENTER_SLEEP_MODE
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
usleep(50000);
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable.
usleep(10000);
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable.
usleep(10000);
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable.
usleep(10000);
// Disable clocks.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000;
DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF);
DSI(_DSIREG(DSI_POWER_CONTROL)) = 0;
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM.
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1;
}
void display_color_screen(u32 color)
{
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_one_color, 8);
// Configure display to show single color.
DISPLAY_A(_DIREG(DC_WIN_AD_WIN_OPTIONS)) = 0;
DISPLAY_A(_DIREG(DC_WIN_BD_WIN_OPTIONS)) = 0;
DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0;
DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color;
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ;
usleep(35000);
display_backlight(true);
}
u32 *display_init_framebuffer()
{
// Sanitize framebuffer area.
//memset((u32 *)FB_ADDRESS, 0, 0x3C0000);
// This configures the framebuffer @ FB_ADDRESS with a resolution of 1280x720 (line stride 720).
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32);
usleep(35000);
return (u32 *)FB_ADDRESS;
}
u32 *display_init_framebuffer2()
{
// Sanitize framebuffer area.
memset((u32 *)FB_ADDRESS, 0, 0x3C0000);
// This configures the framebuffer @ FB_ADDRESS with a resolution of 1280x720 (line stride 720).
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer2, 32);
usleep(35000);
return (u32 *)FB_ADDRESS;
}
#pragma GCC pop_options

370
nyx/nyx_gui/gfx/di.h Normal file
View File

@ -0,0 +1,370 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DI_H_
#define _DI_H_
#include "../utils/types.h"
#define FB_ADDRESS 0xF0800000
/*! Display registers. */
#define _DIREG(reg) ((reg) * 4)
#define DC_CMD_GENERAL_INCR_SYNCPT 0x00
#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01
#define SYNCPT_CNTRL_NO_STALL (1 << 8)
#define SYNCPT_CNTRL_SOFT_RESET (1 << 0)
#define DC_CMD_CONT_SYNCPT_VSYNC 0x28
#define SYNCPT_VSYNC_ENABLE (1 << 8)
#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031
#define DC_CMD_DISPLAY_COMMAND 0x32
#define DISP_CTRL_MODE_STOP (0 << 5)
#define DISP_CTRL_MODE_C_DISPLAY (1 << 5)
#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5)
#define DISP_CTRL_MODE_MASK (3 << 5)
#define DC_CMD_DISPLAY_POWER_CONTROL 0x36
#define PW0_ENABLE (1 << 0)
#define PW1_ENABLE (1 << 2)
#define PW2_ENABLE (1 << 4)
#define PW3_ENABLE (1 << 6)
#define PW4_ENABLE (1 << 8)
#define PM0_ENABLE (1 << 16)
#define PM1_ENABLE (1 << 18)
#define DC_CMD_INT_MASK 0x38
#define DC_CMD_INT_ENABLE 0x39
#define DC_CMD_STATE_ACCESS 0x40
#define READ_MUX (1 << 0)
#define WRITE_MUX (1 << 2)
#define DC_CMD_STATE_CONTROL 0x41
#define GENERAL_ACT_REQ (1 << 0)
#define WIN_A_ACT_REQ (1 << 1)
#define WIN_B_ACT_REQ (1 << 2)
#define WIN_C_ACT_REQ (1 << 3)
#define CURSOR_ACT_REQ (1 << 7)
#define GENERAL_UPDATE (1 << 8)
#define WIN_A_UPDATE (1 << 9)
#define WIN_B_UPDATE (1 << 10)
#define WIN_C_UPDATE (1 << 11)
#define CURSOR_UPDATE (1 << 15)
#define NC_HOST_TRIG (1 << 24)
#define DC_CMD_DISPLAY_WINDOW_HEADER 0x42
#define WINDOW_A_SELECT (1 << 4)
#define WINDOW_B_SELECT (1 << 5)
#define WINDOW_C_SELECT (1 << 6)
#define DC_CMD_REG_ACT_CONTROL 0x043
#define DC_COM_CRC_CONTROL 0x300
#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x))
#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
#define DC_COM_DSC_TOP_CTL 0x33E
#define DC_DISP_DISP_WIN_OPTIONS 0x402
#define HDMI_ENABLE (1 << 30)
#define DSI_ENABLE (1 << 29)
#define SOR1_TIMING_CYA (1 << 27)
#define SOR1_ENABLE (1 << 26)
#define SOR_ENABLE (1 << 25)
#define CURSOR_ENABLE (1 << 16)
#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403
#define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404
#define DC_DISP_DISP_TIMING_OPTIONS 0x405
#define DC_DISP_REF_TO_SYNC 0x406
#define DC_DISP_SYNC_WIDTH 0x407
#define DC_DISP_BACK_PORCH 0x408
#define DC_DISP_ACTIVE 0x409
#define DC_DISP_FRONT_PORCH 0x40A
#define DC_DISP_DISP_CLOCK_CONTROL 0x42E
#define PIXEL_CLK_DIVIDER_PCD1 (0 << 8)
#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8)
#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8)
#define PIXEL_CLK_DIVIDER_PCD3 (3 << 8)
#define PIXEL_CLK_DIVIDER_PCD4 (4 << 8)
#define PIXEL_CLK_DIVIDER_PCD6 (5 << 8)
#define PIXEL_CLK_DIVIDER_PCD8 (6 << 8)
#define PIXEL_CLK_DIVIDER_PCD9 (7 << 8)
#define PIXEL_CLK_DIVIDER_PCD12 (8 << 8)
#define PIXEL_CLK_DIVIDER_PCD16 (9 << 8)
#define PIXEL_CLK_DIVIDER_PCD18 (10 << 8)
#define PIXEL_CLK_DIVIDER_PCD24 (11 << 8)
#define PIXEL_CLK_DIVIDER_PCD13 (12 << 8)
#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff)
#define DC_DISP_DISP_INTERFACE_CONTROL 0x42F
#define DISP_DATA_FORMAT_DF1P1C (0 << 0)
#define DISP_DATA_FORMAT_DF1P2C24B (1 << 0)
#define DISP_DATA_FORMAT_DF1P2C18B (2 << 0)
#define DISP_DATA_FORMAT_DF1P2C16B (3 << 0)
#define DISP_DATA_FORMAT_DF2S (4 << 0)
#define DISP_DATA_FORMAT_DF3S (5 << 0)
#define DISP_DATA_FORMAT_DFSPI (6 << 0)
#define DISP_DATA_FORMAT_DF1P3C24B (7 << 0)
#define DISP_DATA_FORMAT_DF1P3C18B (8 << 0)
#define DISP_ALIGNMENT_MSB (0 << 8)
#define DISP_ALIGNMENT_LSB (1 << 8)
#define DISP_ORDER_RED_BLUE (0 << 9)
#define DISP_ORDER_BLUE_RED (1 << 9)
#define DC_DISP_DISP_COLOR_CONTROL 0x430
#define DITHER_CONTROL_MASK (3 << 8)
#define DITHER_CONTROL_DISABLE (0 << 8)
#define DITHER_CONTROL_ORDERED (2 << 8)
#define DITHER_CONTROL_ERRDIFF (3 << 8)
#define BASE_COLOR_SIZE_MASK (0xf << 0)
#define BASE_COLOR_SIZE_666 (0 << 0)
#define BASE_COLOR_SIZE_111 (1 << 0)
#define BASE_COLOR_SIZE_222 (2 << 0)
#define BASE_COLOR_SIZE_333 (3 << 0)
#define BASE_COLOR_SIZE_444 (4 << 0)
#define BASE_COLOR_SIZE_555 (5 << 0)
#define BASE_COLOR_SIZE_565 (6 << 0)
#define BASE_COLOR_SIZE_332 (7 << 0)
#define BASE_COLOR_SIZE_888 (8 << 0)
#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431
#define SC1_H_QUALIFIER_NONE (1 << 16)
#define SC0_H_QUALIFIER_NONE (1 << 0)
#define DC_DISP_DATA_ENABLE_OPTIONS 0x432
#define DE_SELECT_ACTIVE_BLANK (0 << 0)
#define DE_SELECT_ACTIVE (1 << 0)
#define DE_SELECT_ACTIVE_IS (2 << 0)
#define DE_CONTROL_ONECLK (0 << 2)
#define DE_CONTROL_NORMAL (1 << 2)
#define DE_CONTROL_EARLY_EXT (2 << 2)
#define DE_CONTROL_EARLY (3 << 2)
#define DE_CONTROL_ACTIVE_BLANK (4 << 2)
#define DC_DISP_DC_MCCIF_FIFOCTRL 0x480
#define DC_DISP_SD_BL_PARAMETERS 0x4D7
#define DC_DISP_SD_BL_CONTROL 0x4DC
#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4
#define DC_WIN_CSC_YOF 0x611
#define DC_WIN_CSC_KYRGB 0x612
#define DC_WIN_CSC_KUR 0x613
#define DC_WIN_CSC_KVR 0x614
#define DC_WIN_CSC_KUG 0x615
#define DC_WIN_CSC_KVG 0x616
#define DC_WIN_CSC_KUB 0x617
#define DC_WIN_CSC_KVB 0x618
#define DC_WIN_AD_WIN_OPTIONS 0xB80
#define DC_WIN_BD_WIN_OPTIONS 0xD80
#define DC_WIN_CD_WIN_OPTIONS 0xF80
// The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER).
#define DC_WIN_WIN_OPTIONS 0x700
#define H_DIRECTION (1 << 0)
#define V_DIRECTION (1 << 2)
#define SCAN_COLUMN (1 << 4)
#define COLOR_EXPAND (1 << 6)
#define CSC_ENABLE (1 << 18)
#define WIN_ENABLE (1 << 30)
#define DC_WIN_COLOR_DEPTH 0x703
#define WIN_COLOR_DEPTH_P1 0x0
#define WIN_COLOR_DEPTH_P2 0x1
#define WIN_COLOR_DEPTH_P4 0x2
#define WIN_COLOR_DEPTH_P8 0x3
#define WIN_COLOR_DEPTH_B4G4R4A4 0x4
#define WIN_COLOR_DEPTH_B5G5R5A 0x5
#define WIN_COLOR_DEPTH_B5G6R5 0x6
#define WIN_COLOR_DEPTH_AB5G5R5 0x7
#define WIN_COLOR_DEPTH_B8G8R8A8 0xC
#define WIN_COLOR_DEPTH_R8G8B8A8 0xD
#define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 0xE
#define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 0xF
#define WIN_COLOR_DEPTH_YCbCr422 0x10
#define WIN_COLOR_DEPTH_YUV422 0x11
#define WIN_COLOR_DEPTH_YCbCr420P 0x12
#define WIN_COLOR_DEPTH_YUV420P 0x13
#define WIN_COLOR_DEPTH_YCbCr422P 0x14
#define WIN_COLOR_DEPTH_YUV422P 0x15
#define WIN_COLOR_DEPTH_YCbCr422R 0x16
#define WIN_COLOR_DEPTH_YUV422R 0x17
#define WIN_COLOR_DEPTH_YCbCr422RA 0x18
#define WIN_COLOR_DEPTH_YUV422RA 0x19
#define DC_WIN_BUFFER_CONTROL 0x702
#define DC_WIN_POSITION 0x704
#define DC_WIN_SIZE 0x705
#define H_SIZE(x) (((x) & 0x1fff) << 0)
#define V_SIZE(x) (((x) & 0x1fff) << 16)
#define DC_WIN_PRESCALED_SIZE 0x706
#define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0)
#define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16)
#define DC_WIN_H_INITIAL_DDA 0x707
#define DC_WIN_V_INITIAL_DDA 0x708
#define DC_WIN_DDA_INC 0x709
#define H_DDA_INC(x) (((x) & 0xffff) << 0)
#define V_DDA_INC(x) (((x) & 0xffff) << 16)
#define DC_WIN_LINE_STRIDE 0x70A
#define LINE_STRIDE(x) (x)
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
#define DC_WIN_DV_CONTROL 0x70E
// The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER).
#define DC_WINBUF_START_ADDR 0x800
#define DC_WINBUF_ADDR_H_OFFSET 0x806
#define DC_WINBUF_ADDR_V_OFFSET 0x808
#define DC_WINBUF_SURFACE_KIND 0x80B
#define PITCH (0 << 0)
#define TILED (1 << 0)
#define BLOCK (2 << 0)
#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
/*! Display serial interface registers. */
#define _DSIREG(reg) ((reg) * 4)
#define DSI_RD_DATA 0x9
#define DSI_WR_DATA 0xA
#define DSI_POWER_CONTROL 0xB
#define DSI_POWER_CONTROL_ENABLE 1
#define DSI_INT_ENABLE 0xC
#define DSI_INT_STATUS 0xD
#define DSI_INT_MASK 0xE
#define DSI_HOST_CONTROL 0xF
#define DSI_HOST_CONTROL_FIFO_RESET (1 << 21)
#define DSI_HOST_CONTROL_CRC_RESET (1 << 20)
#define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12)
#define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12)
#define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12)
#define DSI_HOST_CONTROL_RAW (1 << 6)
#define DSI_HOST_CONTROL_HS (1 << 5)
#define DSI_HOST_CONTROL_FIFO_SEL (1 << 4)
#define DSI_HOST_CONTROL_IMM_BTA (1 << 3)
#define DSI_HOST_CONTROL_PKT_BTA (1 << 2)
#define DSI_HOST_CONTROL_CS (1 << 1)
#define DSI_HOST_CONTROL_ECC (1 << 0)
#define DSI_CONTROL 0x10
#define DSI_CONTROL_HS_CLK_CTRL (1 << 20)
#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16)
#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12)
#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8)
#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4)
#define DSI_CONTROL_DCS_ENABLE (1 << 3)
#define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2)
#define DSI_CONTROL_VIDEO_ENABLE (1 << 1)
#define DSI_CONTROL_HOST_ENABLE (1 << 0)
#define DSI_SOL_DELAY 0x11
#define DSI_MAX_THRESHOLD 0x12
#define DSI_TRIGGER 0x13
#define DSI_TRIGGER_HOST (1 << 1)
#define DSI_TRIGGER_VIDEO (1 << 0)
#define DSI_TX_CRC 0x14
#define DSI_STATUS 0x15
#define DSI_INIT_SEQ_CONTROL 0x1A
#define DSI_INIT_SEQ_DATA_0 0x1B
#define DSI_INIT_SEQ_DATA_1 0x1C
#define DSI_INIT_SEQ_DATA_2 0x1D
#define DSI_INIT_SEQ_DATA_3 0x1E
#define DSI_PKT_SEQ_0_LO 0x23
#define DSI_PKT_SEQ_0_HI 0x24
#define DSI_PKT_SEQ_1_LO 0x25
#define DSI_PKT_SEQ_1_HI 0x26
#define DSI_PKT_SEQ_2_LO 0x27
#define DSI_PKT_SEQ_2_HI 0x28
#define DSI_PKT_SEQ_3_LO 0x29
#define DSI_PKT_SEQ_3_HI 0x2A
#define DSI_PKT_SEQ_4_LO 0x2B
#define DSI_PKT_SEQ_4_HI 0x2C
#define DSI_PKT_SEQ_5_LO 0x2D
#define DSI_PKT_SEQ_5_HI 0x2E
#define DSI_DCS_CMDS 0x33
#define DSI_PKT_LEN_0_1 0x34
#define DSI_PKT_LEN_2_3 0x35
#define DSI_PKT_LEN_4_5 0x36
#define DSI_PKT_LEN_6_7 0x37
#define DSI_PHY_TIMING_0 0x3C
#define DSI_PHY_TIMING_1 0x3D
#define DSI_PHY_TIMING_2 0x3E
#define DSI_BTA_TIMING 0x3F
#define DSI_TIMEOUT_0 0x44
#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16)
#define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0)
#define DSI_TIMEOUT_1 0x45
#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16)
#define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0)
#define DSI_TO_TALLY 0x46
#define DSI_PAD_CONTROL_0 0x4B
#define DSI_PAD_CONTROL_VS1_PULLDN_CLK (1 << 24)
#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16)
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
#define DSI_PAD_CONTROL_CD 0x4C
#define DSI_VIDEO_MODE_CONTROL 0x4E
#define DSI_PAD_CONTROL_1 0x4F
#define DSI_PAD_CONTROL_2 0x50
#define DSI_PAD_CONTROL_3 0x51
#define DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12)
#define DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8)
#define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4)
#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0)
#define DSI_PAD_CONTROL_4 0x52
#define DSI_INIT_SEQ_DATA_15 0x5F
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60
void display_init();
void display_backlight_pwm_init();
void display_end();
/*! Show one single color on the display. */
void display_color_screen(u32 color);
/*! Switches screen backlight ON/OFF. */
void display_backlight(bool enable);
void display_backlight_brightness(u32 brightness, u32 step_delay);
/*! Init display in full 1280x720 resolution (B8G8R8A8, line stride 768, framebuffer size = 1280*768*4 bytes). */
u32 *display_init_framebuffer();
u32 *display_init_framebuffer2();
#endif

601
nyx/nyx_gui/gfx/di.inl Normal file
View File

@ -0,0 +1,601 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Clock config.
static const cfg_op_t _display_config_1[4] = {
{0x4E, 0x40000000}, //CLK_RST_CONTROLLER_CLK_SOURCE_DISP1
{0x34, 0x4830A001}, //CLK_RST_CONTROLLER_PLLD_BASE
{0x36, 0x20}, //CLK_RST_CONTROLLER_PLLD_MISC1
{0x37, 0x2D0AAA} //CLK_RST_CONTROLLER_PLLD_MISC
};
//Display A config.
static const cfg_op_t _display_config_2[94] = {
{DC_CMD_STATE_ACCESS, 0},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_REG_ACT_CONTROL, 0x54},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{DC_DISP_DC_MCCIF_FIFOCTRL, 0},
{DC_DISP_DISP_MEM_HIGH_PRIORITY, 0},
{DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 0},
{DC_CMD_DISPLAY_POWER_CONTROL, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE},
{DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL},
{DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | 0x9}, // 9: SYNCPT
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
{DC_CMD_STATE_ACCESS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_DV_CONTROL, 0},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
/* Setup default YUV colorspace conversion coefficients */
{DC_WIN_CSC_YOF, 0xF0},
{DC_WIN_CSC_KYRGB, 0x12A},
{DC_WIN_CSC_KUR, 0},
{DC_WIN_CSC_KVR, 0x198},
{DC_WIN_CSC_KUG, 0x39B},
{DC_WIN_CSC_KVG, 0x32F},
{DC_WIN_CSC_KUB, 0x204},
{DC_WIN_CSC_KVB, 0},
/* End of color coefficients */
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{DC_WIN_DV_CONTROL, 0},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
/* Setup default YUV colorspace conversion coefficients */
{DC_WIN_CSC_YOF, 0xF0},
{DC_WIN_CSC_KYRGB, 0x12A},
{DC_WIN_CSC_KUR, 0},
{DC_WIN_CSC_KVR, 0x198},
{DC_WIN_CSC_KUG, 0x39B},
{DC_WIN_CSC_KVG, 0x32F},
{DC_WIN_CSC_KUB, 0x204},
{DC_WIN_CSC_KVB, 0},
/* End of color coefficients */
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{DC_WIN_DV_CONTROL, 0},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
/* Setup default YUV colorspace conversion coefficients */
{DC_WIN_CSC_YOF, 0xF0},
{DC_WIN_CSC_KYRGB, 0x12A},
{DC_WIN_CSC_KUR, 0},
{DC_WIN_CSC_KVR, 0x198},
{DC_WIN_CSC_KUG, 0x39B},
{DC_WIN_CSC_KVG, 0x32F},
{DC_WIN_CSC_KUB, 0x204},
{DC_WIN_CSC_KVB, 0},
/* End of color coefficients */
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
{DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
{DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000},
{DC_COM_PIN_OUTPUT_POLARITY(3), 0},
{0x4E4, 0},
{DC_COM_CRC_CONTROL, 0},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{0x716, 0x10000FF},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{0x716, 0x10000FF},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{0x716, 0x10000FF},
{DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}
};
//DSI Init config.
static const cfg_op_t _display_config_3[61] = {
{DSI_WR_DATA, 0},
{DSI_INT_ENABLE, 0},
{DSI_INT_STATUS, 0},
{DSI_INT_MASK, 0},
{DSI_INIT_SEQ_DATA_0, 0},
{DSI_INIT_SEQ_DATA_1, 0},
{DSI_INIT_SEQ_DATA_2, 0},
{DSI_INIT_SEQ_DATA_3, 0},
{DSI_INIT_SEQ_DATA_15, 0},
{DSI_DCS_CMDS, 0},
{DSI_PKT_SEQ_0_LO, 0},
{DSI_PKT_SEQ_1_LO, 0},
{DSI_PKT_SEQ_2_LO, 0},
{DSI_PKT_SEQ_3_LO, 0},
{DSI_PKT_SEQ_4_LO, 0},
{DSI_PKT_SEQ_5_LO, 0},
{DSI_PKT_SEQ_0_HI, 0},
{DSI_PKT_SEQ_1_HI, 0},
{DSI_PKT_SEQ_2_HI, 0},
{DSI_PKT_SEQ_3_HI, 0},
{DSI_PKT_SEQ_4_HI, 0},
{DSI_PKT_SEQ_5_HI, 0},
{DSI_CONTROL, 0},
{DSI_PAD_CONTROL_CD, 0},
{DSI_SOL_DELAY, 0x18},
{DSI_MAX_THRESHOLD, 0x1E0},
{DSI_TRIGGER, 0},
{DSI_INIT_SEQ_CONTROL, 0},
{DSI_PKT_LEN_0_1, 0},
{DSI_PKT_LEN_2_3, 0},
{DSI_PKT_LEN_4_5, 0},
{DSI_PKT_LEN_6_7, 0},
{DSI_PAD_CONTROL_1, 0},
{DSI_PHY_TIMING_0, 0x6070601},
{DSI_PHY_TIMING_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30109},
{DSI_BTA_TIMING, 0x190A14},
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0},
{DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Enable
{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
{DSI_POWER_CONTROL, 0},
{DSI_POWER_CONTROL, 0},
{DSI_PAD_CONTROL_1, 0},
{DSI_PHY_TIMING_0, 0x6070601},
{DSI_PHY_TIMING_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30118},
{DSI_BTA_TIMING, 0x190A14},
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0},
{DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
{DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
{DSI_MAX_THRESHOLD, 0x40},
{DSI_TRIGGER, 0},
{DSI_TX_CRC, 0},
{DSI_INIT_SEQ_CONTROL, 0}
};
//DSI config (if ver == 0x10).
static const cfg_op_t _display_config_4[43] = {
{DSI_WR_DATA, 0x439},
{DSI_WR_DATA, 0x9483FFB9},
{DSI_TRIGGER, DSI_TRIGGER_HOST},
{DSI_WR_DATA, 0xBD15},
{DSI_TRIGGER, DSI_TRIGGER_HOST},
{DSI_WR_DATA, 0x1939},
{DSI_WR_DATA, 0xAAAAAAD8},
{DSI_WR_DATA, 0xAAAAAAEB},
{DSI_WR_DATA, 0xAAEBAAAA},
{DSI_WR_DATA, 0xAAAAAAAA},
{DSI_WR_DATA, 0xAAAAAAEB},
{DSI_WR_DATA, 0xAAEBAAAA},
{DSI_WR_DATA, 0xAA},
{DSI_TRIGGER, DSI_TRIGGER_HOST},
{DSI_WR_DATA, 0x1BD15},
{DSI_TRIGGER, DSI_TRIGGER_HOST},
{DSI_WR_DATA, 0x2739},
{DSI_WR_DATA, 0xFFFFFFD8},
{DSI_WR_DATA, 0xFFFFFFFF},
{DSI_WR_DATA, 0xFFFFFFFF},
{DSI_WR_DATA, 0xFFFFFFFF},
{DSI_WR_DATA, 0xFFFFFFFF},
{DSI_WR_DATA, 0xFFFFFFFF},
{DSI_WR_DATA, 0xFFFFFFFF},
{DSI_WR_DATA, 0xFFFFFFFF},
{DSI_WR_DATA, 0xFFFFFFFF},
{DSI_WR_DATA, 0xFFFFFF},
{DSI_TRIGGER, DSI_TRIGGER_HOST},
{DSI_WR_DATA, 0x2BD15},
{DSI_TRIGGER, DSI_TRIGGER_HOST},
{DSI_WR_DATA, 0xF39},
{DSI_WR_DATA, 0xFFFFFFD8},
{DSI_WR_DATA, 0xFFFFFFFF},
{DSI_WR_DATA, 0xFFFFFFFF},
{DSI_WR_DATA, 0xFFFFFF},
{DSI_TRIGGER, DSI_TRIGGER_HOST},
{DSI_WR_DATA, 0xBD15},
{DSI_TRIGGER, DSI_TRIGGER_HOST},
{DSI_WR_DATA, 0x6D915},
{DSI_TRIGGER, DSI_TRIGGER_HOST},
{DSI_WR_DATA, 0x439},
{DSI_WR_DATA, 0xB9},
{DSI_TRIGGER, DSI_TRIGGER_HOST}
};
//DSI config.
static const cfg_op_t _display_config_5[21] = {
{DSI_PAD_CONTROL_1, 0},
{DSI_PHY_TIMING_0, 0x6070601},
{DSI_PHY_TIMING_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30172},
{DSI_BTA_TIMING, 0x190A14},
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)},
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0},
{DSI_PKT_SEQ_0_LO, 0x40000208},
{DSI_PKT_SEQ_2_LO, 0x40000308},
{DSI_PKT_SEQ_4_LO, 0x40000308},
{DSI_PKT_SEQ_1_LO, 0x40000308},
{DSI_PKT_SEQ_3_LO, 0x3F3B2B08},
{DSI_PKT_SEQ_3_HI, 0x2CC},
{DSI_PKT_SEQ_5_LO, 0x3F3B2B08},
{DSI_PKT_SEQ_5_HI, 0x2CC},
{DSI_PKT_LEN_0_1, 0xCE0000},
{DSI_PKT_LEN_2_3, 0x87001A2},
{DSI_PKT_LEN_4_5, 0x190},
{DSI_PKT_LEN_6_7, 0x190},
{DSI_HOST_CONTROL, 0},
};
//Clock config.
static const cfg_op_t _display_config_6[3] = {
{0x34, 0x4810C001}, //CLK_RST_CONTROLLER_PLLD_BASE
{0x36, 0x20}, //CLK_RST_CONTROLLER_PLLD_MISC1
{0x37, 0x2DFC00} //CLK_RST_CONTROLLER_PLLD_MISC
};
//DSI config.
static const cfg_op_t _display_config_7[10] = {
{DSI_TRIGGER, 0},
{DSI_CONTROL, 0},
{DSI_SOL_DELAY, 6},
{DSI_MAX_THRESHOLD, 0x1E0},
{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
{DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE},
{DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_FIFO_SEL| DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
{DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE},
{DSI_HOST_CONTROL, DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
{DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}
};
//MIPI CAL config.
static const cfg_op_t _display_config_8[6] = {
{0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2
{0x02, 0xF3F10000}, // MIPI_CAL_CIL_MIPI_CAL_STATUS
{0x16, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG0
{0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2
{0x18, 0x10010}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2
{0x17, 0x300} // MIPI_CAL_MIPI_BIAS_PAD_CFG1
};
//DSI config.
static const cfg_op_t _display_config_9[4] = {
{DSI_PAD_CONTROL_1, 0},
{DSI_PAD_CONTROL_2, 0},
{DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)},
{DSI_PAD_CONTROL_4, 0}
};
//MIPI CAL config.
static const cfg_op_t _display_config_10[16] = {
{0x0E, 0x200200}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG
{0x0F, 0x200200}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG
{0x19, 0x200002}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2
{0x1A, 0x200002}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2
{0x05, 0}, // MIPI_CAL_CILA_MIPI_CAL_CONFIG
{0x06, 0}, // MIPI_CAL_CILB_MIPI_CAL_CONFIG
{0x07, 0}, // MIPI_CAL_CILC_MIPI_CAL_CONFIG
{0x08, 0}, // MIPI_CAL_CILD_MIPI_CAL_CONFIG
{0x09, 0}, // MIPI_CAL_CILE_MIPI_CAL_CONFIG
{0x0A, 0}, // MIPI_CAL_CILF_MIPI_CAL_CONFIG
{0x10, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG
{0x11, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG
{0x1A, 0}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2
{0x1C, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2
{0x1D, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG_2
{0, 0x2A000001} // MIPI_CAL_DSIA_MIPI_CAL_CONFIG
};
//Display A config.
static const cfg_op_t _display_config_11[113] = {
{DC_CMD_STATE_ACCESS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_DV_CONTROL, 0},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
/* Setup default YUV colorspace conversion coefficients */
{DC_WIN_CSC_YOF, 0xF0},
{DC_WIN_CSC_KYRGB, 0x12A},
{DC_WIN_CSC_KUR, 0},
{DC_WIN_CSC_KVR, 0x198},
{DC_WIN_CSC_KUG, 0x39B},
{DC_WIN_CSC_KVG, 0x32F},
{DC_WIN_CSC_KUB, 0x204},
{DC_WIN_CSC_KVB, 0},
/* End of color coefficients */
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{DC_WIN_DV_CONTROL, 0},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
/* Setup default YUV colorspace conversion coefficients */
{DC_WIN_CSC_YOF, 0xF0},
{DC_WIN_CSC_KYRGB, 0x12A},
{DC_WIN_CSC_KUR, 0},
{DC_WIN_CSC_KVR, 0x198},
{DC_WIN_CSC_KUG, 0x39B},
{DC_WIN_CSC_KVG, 0x32F},
{DC_WIN_CSC_KUB, 0x204},
{DC_WIN_CSC_KVB, 0},
/* End of color coefficients */
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{DC_WIN_DV_CONTROL, 0},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
/* Setup default YUV colorspace conversion coefficients */
{DC_WIN_CSC_YOF, 0xF0},
{DC_WIN_CSC_KYRGB, 0x12A},
{DC_WIN_CSC_KUR, 0},
{DC_WIN_CSC_KVR, 0x198},
{DC_WIN_CSC_KUG, 0x39B},
{DC_WIN_CSC_KVG, 0x32F},
{DC_WIN_CSC_KUB, 0x204},
{DC_WIN_CSC_KVB, 0},
/* End of color coefficients */
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
{DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
{DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000},
{DC_COM_PIN_OUTPUT_POLARITY(3), 0},
{0x4E4, 0},
{DC_COM_CRC_CONTROL, 0},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{0x716, 0x10000FF},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{0x716, 0x10000FF},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{0x716, 0x10000FF},
{DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
{DC_CMD_STATE_ACCESS, 0},
/* Set Display timings */
{DC_DISP_DISP_TIMING_OPTIONS, 0},
{DC_DISP_REF_TO_SYNC, (1 << 16)}, // h_ref_to_sync = 0, v_ref_to_sync = 1.
{DC_DISP_SYNC_WIDTH, 0x10048},
{DC_DISP_BACK_PORCH, 0x90048},
{DC_DISP_ACTIVE, 0x50002D0},
{DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd.
/* End of Display timings */
{DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE},
{DC_COM_PIN_OUTPUT_ENABLE(1), 0},
{DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL},
{DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
{DC_DISP_DISP_CLOCK_CONTROL, 0},
{DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_STATE_ACCESS, READ_MUX | WRITE_MUX},
{DC_DISP_FRONT_PORCH, 0xA0088},
{DC_CMD_STATE_ACCESS, 0},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
{DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_STATE_ACCESS, 0},
{DC_DISP_DISP_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)},
{DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
{DC_CMD_DISPLAY_COMMAND_OPTION0, 0}
};
////Display A config.
static const cfg_op_t _display_config_12[17] = {
{DC_DISP_FRONT_PORCH, 0xA0088},
{DC_CMD_INT_MASK, 0},
{DC_CMD_STATE_ACCESS, 0},
{DC_CMD_INT_ENABLE, 0},
{DC_CMD_CONT_SYNCPT_VSYNC, 0},
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
{DC_CMD_GENERAL_INCR_SYNCPT, 0x301},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_DISPLAY_POWER_CONTROL, 0},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
};
//DSI config.
static const cfg_op_t _display_config_13[16] = {
{DSI_POWER_CONTROL, 0},
{DSI_PAD_CONTROL_1, 0},
{DSI_PHY_TIMING_0, 0x6070601},
{DSI_PHY_TIMING_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30118},
{DSI_BTA_TIMING, 0x190A14},
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF) },
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0},
{DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
{DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
{DSI_MAX_THRESHOLD, 0x40},
{DSI_TRIGGER, 0},
{DSI_TX_CRC, 0},
{DSI_INIT_SEQ_CONTROL, 0}
};
//DSI config (if ver == 0x10).
static const cfg_op_t _display_config_14[22] = {
{DSI_WR_DATA, 0x439},
{DSI_WR_DATA, 0x9483FFB9},
{DSI_TRIGGER, DSI_TRIGGER_HOST},
{DSI_WR_DATA, 0x2139},
{DSI_WR_DATA, 0x191919D5},
{DSI_WR_DATA, 0x19191919},
{DSI_WR_DATA, 0x19191919},
{DSI_WR_DATA, 0x19191919},
{DSI_WR_DATA, 0x19191919},
{DSI_WR_DATA, 0x19191919},
{DSI_WR_DATA, 0x19191919},
{DSI_WR_DATA, 0x19191919},
{DSI_WR_DATA, 0x19},
{DSI_TRIGGER, DSI_TRIGGER_HOST},
{DSI_WR_DATA, 0xB39},
{DSI_WR_DATA, 0x4F0F41B1},
{DSI_WR_DATA, 0xF179A433},
{DSI_WR_DATA, 0x2D81},
{DSI_TRIGGER, DSI_TRIGGER_HOST},
{DSI_WR_DATA, 0x439},
{DSI_WR_DATA, 0xB9},
{DSI_TRIGGER, DSI_TRIGGER_HOST}
};
//Display A config.
static const cfg_op_t cfg_display_one_color[8] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A.
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B.
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C.
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} //DISPLAY_CTRL_MODE: continuous display.
};
//Display A config.
static const cfg_op_t cfg_display_framebuffer[32] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C.
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B.
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A.
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8
{DC_WIN_WIN_OPTIONS, 0},
{DC_WIN_WIN_OPTIONS, 0},
{DC_WIN_POSITION, 0}, //(0,0)
{DC_WIN_H_INITIAL_DDA, 0},
{DC_WIN_V_INITIAL_DDA, 0},
{DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes.
{DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)},
{DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels.
{DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
{DC_WIN_BUFFER_CONTROL, 0},
{DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
//{DC_WINBUF_SURFACE_KIND, BLOCK_HEIGHT(4) | BLOCK}, //Regular surface.
{DC_WINBUF_START_ADDR, FB_ADDRESS}, //Framebuffer address.
{DC_WINBUF_ADDR_H_OFFSET, 0}, //Linear: 0x383FFC, Block: 0x3813FC
{DC_WINBUF_ADDR_V_OFFSET, 1279}, //Linear: 1279, Block: 0
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
{DC_WIN_WIN_OPTIONS, WIN_ENABLE | V_DIRECTION}, //Enable window AD.
//{DC_WIN_WIN_OPTIONS, WIN_ENABLE | | SCAN_COLUMN | H_DIRECTION}, //Enable window AD. | SCAN_COLUMN | H_DIRECTION
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display.
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update.
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request.
};
static const cfg_op_t cfg_display_framebuffer2[32] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C.
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B.
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A.
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8
{DC_WIN_WIN_OPTIONS, 0},
{DC_WIN_WIN_OPTIONS, 0},
{DC_WIN_POSITION, 0}, //(0,0)
{DC_WIN_H_INITIAL_DDA, 0},
{DC_WIN_V_INITIAL_DDA, 0},
{DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes.
{DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)},
{DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels.
{DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(1280 * 2) | LINE_STRIDE(1280 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
{DC_WIN_BUFFER_CONTROL, 0},
{DC_WINBUF_SURFACE_KIND, BLOCK_HEIGHT(4) | BLOCK}, //Regular surface.
{DC_WINBUF_START_ADDR, FB_ADDRESS}, //Framebuffer address.
{DC_WINBUF_ADDR_H_OFFSET, 0x3813FC}, //Linear: 0x383FFC, Block: 0x3813FC
{DC_WINBUF_ADDR_V_OFFSET, 0}, //Linear: 1279, Block: 0
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE
{DC_WIN_WIN_OPTIONS, WIN_ENABLE | SCAN_COLUMN | H_DIRECTION}, //Enable window AD. | SCAN_COLUMN | H_DIRECTION
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display.
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update.
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request.
};

628
nyx/nyx_gui/gfx/gfx.c Normal file
View File

@ -0,0 +1,628 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdarg.h>
#include <string.h>
#include "gfx.h"
#pragma GCC push_options
#pragma GCC target ("thumb")
#pragma GCC optimize ("Os")
static const u8 _gfx_font[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( )
0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!)
0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (")
0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, // Char 035 (#)
0x00, 0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, // Char 036 ($)
0x00, 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, // Char 037 (%)
0x00, 0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, // Char 038 (&)
0x00, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, // Char 039 (')
0x00, 0x30, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, // Char 040 (()
0x00, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x00, // Char 041 ())
0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // Char 042 (*)
0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // Char 043 (+)
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 044 (,)
0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, // Char 045 (-)
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // Char 046 (.)
0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, // Char 047 (/)
0x00, 0x3C, 0x66, 0x76, 0x6E, 0x66, 0x3C, 0x00, // Char 048 (0)
0x00, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00, // Char 049 (1)
0x00, 0x3C, 0x62, 0x30, 0x0C, 0x06, 0x7E, 0x00, // Char 050 (2)
0x00, 0x3C, 0x62, 0x38, 0x60, 0x66, 0x3C, 0x00, // Char 051 (3)
0x00, 0x6C, 0x6C, 0x66, 0xFE, 0x60, 0x60, 0x00, // Char 052 (4)
0x00, 0x7E, 0x06, 0x7E, 0x60, 0x66, 0x3C, 0x00, // Char 053 (5)
0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00, // Char 054 (6)
0x00, 0x7E, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, // Char 055 (7)
0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // Char 056 (8)
0x00, 0x3C, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, // Char 057 (9)
0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, // Char 058 (:)
0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 059 (;)
0x00, 0x70, 0x1C, 0x06, 0x06, 0x1C, 0x70, 0x00, // Char 060 (<)
0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, // Char 061 (=)
0x00, 0x0E, 0x38, 0x60, 0x60, 0x38, 0x0E, 0x00, // Char 062 (>)
0x00, 0x3C, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, // Char 063 (?)
0x00, 0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, // Char 064 (@)
0x00, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 065 (A)
0x00, 0x3E, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 066 (B)
0x00, 0x3C, 0x66, 0x06, 0x06, 0x66, 0x3C, 0x00, // Char 067 (C)
0x00, 0x1E, 0x36, 0x66, 0x66, 0x36, 0x1E, 0x00, // Char 068 (D)
0x00, 0x7E, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00, // Char 069 (E)
0x00, 0x3E, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00, // Char 070 (F)
0x00, 0x3C, 0x66, 0x06, 0x76, 0x66, 0x3C, 0x00, // Char 071 (G)
0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 072 (H)
0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 073 (I)
0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, // Char 074 (J)
0x00, 0x66, 0x36, 0x1E, 0x1E, 0x36, 0x66, 0x00, // Char 075 (K)
0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00, // Char 076 (L)
0x00, 0x46, 0x6E, 0x7E, 0x56, 0x46, 0x46, 0x00, // Char 077 (M)
0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, // Char 078 (N)
0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 079 (O)
0x00, 0x3E, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, // Char 080 (P)
0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00, // Char 081 (Q)
0x00, 0x3E, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00, // Char 082 (R)
0x00, 0x3C, 0x66, 0x0C, 0x30, 0x66, 0x3C, 0x00, // Char 083 (S)
0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // Char 084 (T)
0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 085 (U)
0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 086 (V)
0x00, 0x46, 0x46, 0x56, 0x7E, 0x6E, 0x46, 0x00, // Char 087 (W)
0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, // Char 088 (X)
0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, // Char 089 (Y)
0x00, 0x7E, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00, // Char 090 (Z)
0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, // Char 091 ([)
0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, // Char 092 (\)
0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, // Char 093 (])
0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, // Char 094 (^)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // Char 095 (_)
0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, // Char 096 (`)
0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00, // Char 097 (a)
0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 098 (b)
0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00, // Char 099 (c)
0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, // Char 100 (d)
0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00, // Char 101 (e)
0x00, 0x38, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00, // Char 102 (f)
0x00, 0x00, 0x7C, 0x66, 0x7C, 0x40, 0x3C, 0x00, // Char 103 (g)
0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00, // Char 104 (h)
0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00, // Char 105 (i)
0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1E, 0x00, // Char 106 (j)
0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00, // Char 107 (k)
0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 108 (l)
0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, // Char 109 (m)
0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00, // Char 110 (n)
0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 111 (o)
0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x00, // Char 112 (p)
0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, // Char 113 (q)
0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00, // Char 114 (r)
0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00, // Char 115 (s)
0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00, // Char 116 (t)
0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, // Char 117 (u)
0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 118 (v)
0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, // Char 119 (w)
0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // Char 120 (x)
0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00, // Char 121 (y)
0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, // Char 122 (z)
0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, 0x18, // Char 123 ({)
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // Char 124 (|)
0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08, 0x0C, // Char 125 (})
0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~)
};
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride)
{
gfx_ctxt.fb = fb;
gfx_ctxt.width = width;
gfx_ctxt.height = height;
gfx_ctxt.stride = stride;
}
void gfx_clear_grey(u8 color)
{
memset(gfx_ctxt.fb, color, 0x3C0000);
}
void gfx_clear_color(u32 color)
{
for (u32 i = 0; i < gfx_ctxt.height * gfx_ctxt.stride; i++)
gfx_ctxt.fb[i] = color;
}
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height)
{
memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride);
}
void gfx_con_init()
{
gfx_con.gfx_ctxt = &gfx_ctxt;
gfx_con.fntsz = 16;
gfx_con.x = 0;
gfx_con.y = 0;
gfx_con.savedx = 0;
gfx_con.savedy = 0;
gfx_con.fgcol = 0xFFCCCCCC;
gfx_con.fillbg = 1;
gfx_con.bgcol = 0xFF1B1B1B;
gfx_con.mute = 0;
}
void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol)
{
gfx_con.fgcol = fgcol;
gfx_con.fillbg = fillbg;
gfx_con.bgcol = bgcol;
}
void gfx_con_getpos(u32 *x, u32 *y)
{
*x = gfx_con.x;
*y = gfx_con.y;
}
void gfx_con_setpos(u32 x, u32 y)
{
gfx_con.x = x;
gfx_con.y = y;
}
void gfx_putc(char c)
{
// Duplicate code for performance reasons.
switch (gfx_con.fntsz)
{
case 16:
if (c >= 32 && c <= 126)
{
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
for (u32 i = 0; i < 16; i+=2)
{
u8 v = *cbuf++;
for (u32 k = 0; k < 2; k++)
{
for (u32 j = 0; j < 8; j++)
{
if (v & 1)
{
*fb = gfx_con.fgcol;
fb++;
*fb = gfx_con.fgcol;
}
else if (gfx_con.fillbg)
{
*fb = gfx_con.bgcol;
fb++;
*fb = gfx_con.bgcol;
}
else
fb++;
v >>= 1;
fb++;
}
fb += gfx_ctxt.stride - 16;
v = *cbuf;
}
}
gfx_con.x += 16;
}
else if (c == '\n')
{
gfx_con.x = 0;
gfx_con.y +=16;
if (gfx_con.y > gfx_ctxt.height - 16)
gfx_con.y = 0;
}
break;
case 8:
default:
if (c >= 32 && c <= 126)
{
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
for (u32 i = 0; i < 8; i++)
{
u8 v = *cbuf++;
for (u32 j = 0; j < 8; j++)
{
if (v & 1)
*fb = gfx_con.fgcol;
else if (gfx_con.fillbg)
*fb = gfx_con.bgcol;
v >>= 1;
fb++;
}
fb += gfx_ctxt.stride - 8;
}
gfx_con.x += 8;
}
else if (c == '\n')
{
gfx_con.x = 0;
gfx_con.y += 8;
if (gfx_con.y > gfx_ctxt.height - 8)
gfx_con.y = 0;
}
break;
}
}
void gfx_puts(const char *s)
{
if (!s || gfx_con.mute)
return;
for (; *s; s++)
gfx_putc(*s);
}
static void _gfx_putn(u32 v, int base, char fill, int fcnt)
{
char buf[65];
static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz";
char *p;
int c = fcnt;
if (base > 36)
return;
p = buf + 64;
*p = 0;
do
{
c--;
*--p = digits[v % base];
v /= base;
} while (v);
if (fill != 0)
{
while (c > 0)
{
*--p = fill;
c--;
}
}
gfx_puts(p);
}
void gfx_put_small_sep()
{
u8 prevFontSize = gfx_con.fntsz;
gfx_con.fntsz = 8;
gfx_putc('\n');
gfx_con.fntsz = prevFontSize;
}
void gfx_put_big_sep()
{
u8 prevFontSize = gfx_con.fntsz;
gfx_con.fntsz = 16;
gfx_putc('\n');
gfx_con.fntsz = prevFontSize;
}
void gfx_printf(const char *fmt, ...)
{
if (gfx_con.mute)
return;
va_list ap;
int fill, fcnt;
va_start(ap, fmt);
while(*fmt)
{
if(*fmt == '%')
{
fmt++;
fill = 0;
fcnt = 0;
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ')
{
fcnt = *fmt;
fmt++;
if (*fmt >= '0' && *fmt <= '9')
{
fill = fcnt;
fcnt = *fmt - '0';
fmt++;
}
else
{
fill = ' ';
fcnt -= '0';
}
}
switch(*fmt)
{
case 'c':
gfx_putc(va_arg(ap, u32));
break;
case 's':
gfx_puts(va_arg(ap, char *));
break;
case 'd':
_gfx_putn(va_arg(ap, u32), 10, fill, fcnt);
break;
case 'p':
case 'P':
case 'x':
case 'X':
_gfx_putn(va_arg(ap, u32), 16, fill, fcnt);
break;
case 'k':
gfx_con.fgcol = va_arg(ap, u32);
break;
case 'K':
gfx_con.bgcol = va_arg(ap, u32);
gfx_con.fillbg = 1;
break;
case '%':
gfx_putc('%');
break;
case '\0':
goto out;
default:
gfx_putc('%');
gfx_putc(*fmt);
break;
}
}
else
gfx_putc(*fmt);
fmt++;
}
out:
va_end(ap);
}
void gfx_hexdump(u32 base, const u8 *buf, u32 len)
{
if (gfx_con.mute)
return;
u8 prevFontSize = gfx_con.fntsz;
gfx_con.fntsz = 8;
for(u32 i = 0; i < len; i++)
{
if(i % 0x10 == 0)
{
if(i != 0)
{
gfx_puts("| ");
for(u32 j = 0; j < 0x10; j++)
{
u8 c = buf[i - 0x10 + j];
if(c >= 32 && c <= 126)
gfx_putc(c);
else
gfx_putc('.');
}
gfx_putc('\n');
}
gfx_printf("%08x: ", base + i);
}
gfx_printf("%02x ", buf[i]);
if (i == len - 1)
{
int ln = len % 0x10 != 0;
u32 k = 0x10 - 1;
if (ln)
{
k = (len & 0xF) - 1;
for (u32 j = 0; j < 0x10 - k; j++)
gfx_puts(" ");
}
gfx_puts("| ");
for(u32 j = 0; j < (ln ? k : k + 1); j++)
{
u8 c = buf[i - k + j];
if(c >= 32 && c <= 126)
gfx_putc(c);
else
gfx_putc('.');
}
gfx_putc('\n');
}
}
gfx_putc('\n');
gfx_con.fntsz = prevFontSize;
}
static int abs(int x)
{
if (x < 0)
return -x;
return x;
}
void gfx_set_pixel(u32 x, u32 y, u32 color)
{
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color;
}
void gfx_line(int x0, int y0, int x1, int y1, u32 color)
{
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
int err = (dx > dy ? dx : -dy) / 2, e2;
while (1)
{
gfx_set_pixel(x0, y0, color);
if (x0 == x1 && y0 == y1)
break;
e2 = err;
if (e2 >-dx)
{
err -= dy;
x0 += sx;
}
if (e2 < dy)
{
err += dx;
y0 += sy;
}
}
}
#pragma GCC pop_options
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
u32 pos = 0;
for (u32 y = pos_y; y < (pos_y + size_y); y++)
{
for (u32 x = pos_x; x < (pos_x + size_x); x++)
{
memset(&gfx_ctxt.fb[x + y*gfx_ctxt.stride], buf[pos], 4);
pos++;
}
}
}
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
u32 pos = 0;
for (u32 y = pos_y; y < (pos_y + size_y); y++)
{
for (u32 x = pos_x; x < (pos_x + size_x); x++)
{
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16);
pos+=3;
}
}
}
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
u32 *ptr = (u32 *)buf;
for (u32 y = pos_y; y < (pos_y + size_y); y++)
for (u32 x = pos_x; x < (pos_x + size_x); x++)
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = *ptr++;
}
void gfx_set_rect_argb_land(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
u32 pos = 0;
for (u32 y = pos_y; y < (pos_y + size_y); y++)
{
for (u32 x = pos_x; x < (pos_x + size_x); x++)
{
gfx_ctxt.fb[y + (gfx_ctxt.width - x) * gfx_ctxt.stride] = buf[pos];
pos+=1;
}
}
}
void gfx_fill_rect_argb(const u32 color, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
for (u32 y = pos_y; y < (pos_y + size_y); y++)
for (u32 x = pos_x; x < (pos_x + size_x); x++)
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color;
}
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
for (u32 y = pos_y; y < (pos_y + size_y); y++)
{
for (u32 x = pos_x; x < (pos_x + size_x); x++)
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x];
}
}
__attribute__((target("arm"))) void gfx_set_rect_land_pitch(u32 *fb, const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2)
{
u32 *ptr = (u32 *)buf;
u32 pixels_w = pos_x2 - pos_x + 1;
if (!(pixels_w % 8))
{
for (u32 y = pos_y; y < (pos_y2 + 1); y++)
for (u32 x = pos_x; x < (pos_x2 + 1); x+=8)
{
u32 *fbx = &fb[x * gfx_ctxt.stride + y];
fbx[0] = *ptr++;
fbx[gfx_ctxt.stride] = *ptr++;
fbx[gfx_ctxt.stride * 2] = *ptr++;
fbx[gfx_ctxt.stride * 3] = *ptr++;
fbx[gfx_ctxt.stride * 4] = *ptr++;
fbx[gfx_ctxt.stride * 5] = *ptr++;
fbx[gfx_ctxt.stride * 6] = *ptr++;
fbx[gfx_ctxt.stride * 7] = *ptr++;
}
}
else
{
for (u32 y = pos_y; y < (pos_y2 + 1); y++)
for (u32 x = pos_x; x < (pos_x2 + 1); x++)
fb[x * gfx_ctxt.stride + y] = *ptr++;
}
}
__attribute__((target("arm"))) void gfx_set_rect_land_block(const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2)
{
u32 *ptr = (u32 *)buf;
u32 GOB_address = 0;
u32 addr = 0;
u32 x2 = 0;
// Optimized
u32 image_width_in_gobs = 655360; //1280
for (u32 y = pos_y; y < (pos_y2 + 1); y++)
{
for (u32 x = pos_x; x < (pos_x2 + 1); x++)
{
GOB_address = (y >> 7) * image_width_in_gobs + ((x >> 4) << 13) + (((y % 128) >> 3) << 9);
x2 = x << 2;
addr = GOB_address
+ (((x2 % 64) >> 5) << 8)
+ (((y % 8) >> 1) << 6)
+ (((x2 % 32) >> 4) << 5)
+ ((y % 2) << 4) + (x2 % 16);
*(u32 *)(gfx_ctxt.fb + (addr >> 2)) = *ptr++;
}
}
// Proper
// u32 block_height = 16;
// u32 image_width_in_gobs = (512 * block_height * 1280 * 4) / 64;
// for (u32 y = pos_y; y <= pos_y2; y++)
// {
// for (int x = pos_x; x <= pos_x2; x++)
// {
// GOB_address = (y / (8 * block_height)) * image_width_in_gobs + ((x * 4 / 64) * 512 * block_height) + ((y % (8 * block_height) / 8) * 512);
// x2 = x << 2;
// addr = GOB_address
// + (((x2 % 64) >> 5) << 8)
// + (((y % 8) >> 1) << 6)
// + (((x2 % 32) >> 4) << 5)
// + ((y % 2) << 4) + (x2 % 16);
// *(u32 *)(gfx_ctxt.fb + (addr >> 2)) = *ptr++;
// }
// }
}

61
nyx/nyx_gui/gfx/gfx.h Normal file
View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018-2019 CTCaer
* Copyright (C) 2018 M4xw
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GFX_H_
#define _GFX_H_
#include "../../../common/common_gfx.h"
#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);
void gfx_clear_grey(u8 color);
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height);
void gfx_clear_color(u32 color);
void gfx_con_init();
void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol);
void gfx_con_getpos(u32 *x, u32 *y);
void gfx_con_setpos(u32 x, u32 y);
void gfx_putc(char c);
void gfx_puts(const char *s);
void gfx_printf(const char *fmt, ...);
void gfx_hexdump(u32 base, const u8 *buf, u32 len);
void gfx_set_pixel(u32 x, u32 y, u32 color);
void gfx_line(int x0, int y0, int x1, int y1, u32 color);
void gfx_put_small_sep();
void gfx_put_big_sep();
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_rect_argb_land(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_fill_rect_argb(const u32 color, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_rect_land_pitch(u32 *fb, const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2);
void gfx_set_rect_land_block(const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2);
// Global gfx console and context.
gfx_ctxt_t gfx_ctxt;
gfx_con_t gfx_con;
#endif

View File

@ -0,0 +1,29 @@
#pragma once
#include "../libs/lv_conf.h"
#include "../libs/lvgl/lv_draw/lv_draw_img.h"
#include "../utils/types.h"
#define HEKATE_LOGO
#ifdef HEKATE_LOGO
lv_img_dsc_t hekate_logo = {
.header.always_zero = 0,
.header.w = 193,
.header.h = 76,
.data_size = 14668 * LV_IMG_PX_SIZE_ALPHA_BYTE,
.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA,
.data = (const uint8_t *)(NYX_RES_ADDR + 0x1D900),
};
lv_img_dsc_t ctcaer_logo = {
.header.always_zero = 0,
.header.w = 147,
.header.h = 76,
.data_size = 11172 * LV_IMG_PX_SIZE_ALPHA_BYTE,
.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA,
.data = (const uint8_t *)(NYX_RES_ADDR + 0x2BF00),
};
#endif

211
nyx/nyx_gui/hos/hos.c Normal file
View File

@ -0,0 +1,211 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk
* Copyright (c) 2018 Ced2911
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "hos.h"
#include "sept.h"
#include "../config/config.h"
#include "../gfx/di.h"
#include "../gfx/gfx.h"
#include "../mem/heap.h"
#include "../mem/mc.h"
#include "../sec/se.h"
#include "../sec/se_t210.h"
#include "../sec/tsec.h"
#include "../soc/bpmp.h"
#include "../soc/cluster.h"
#include "../soc/fuse.h"
#include "../soc/pmc.h"
#include "../soc/smmu.h"
#include "../soc/t210.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/util.h"
extern hekate_config h_cfg;
extern void sd_unmount(bool deinit);
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
#define PKG2_LOAD_ADDR 0xA9800000
// Secmon mailbox.
#define SECMON_MB_ADDR 0x40002EF8
#define SECMON7_MB_ADDR 0x400000F8
typedef struct _secmon_mailbox_t
{
// < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot.
// >= 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot.
u32 in;
// Non-zero: Secmon ready.
u32 out;
} secmon_mailbox_t;
static const u8 keyblob_keyseeds[][0x10] = {
{ 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, //1.0.0
{ 0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC }, //3.0.0
{ 0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B }, //3.0.1
{ 0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE }, //4.0.0
{ 0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80 }, //5.0.0
{ 0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0 } //6.0.0
};
static const u8 cmac_keyseed[0x10] =
{ 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5 };
static const u8 master_keyseed_retail[0x10] =
{ 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C };
static const u8 console_keyseed[0x10] =
{ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 };
static const u8 package2_keyseed[] =
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
static const u8 master_keyseed_4xx_5xx_610[0x10] =
{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };
static const u8 master_keyseed_620[0x10] =
{ 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A };
static const u8 console_keyseed_4xx_5xx[0x10] =
{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
{
u8 tmp[0x20];
u32 retries = 0;
if (kb > KB_FIRMWARE_VERSION_MAX)
return 0;
if (kb <= KB_FIRMWARE_VERSION_600)
tsec_ctxt->size = 0xF00;
else if (kb == KB_FIRMWARE_VERSION_620)
tsec_ctxt->size = 0x2900;
else if (kb == KB_FIRMWARE_VERSION_700)
tsec_ctxt->size = 0x3000;
else
tsec_ctxt->size = 0x3300;
// Prepare smmu tsec page for 6.2.0.
if (kb == KB_FIRMWARE_VERSION_620)
{
u8 *tsec_paged = (u8 *)page_alloc(3);
memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size);
tsec_ctxt->fw = tsec_paged;
}
// Get TSEC key.
if (kb <= KB_FIRMWARE_VERSION_620)
{
while (tsec_query(tmp, kb, tsec_ctxt) < 0)
{
memset(tmp, 0x00, 0x20);
retries++;
// We rely on racing conditions, make sure we cover even the unluckiest cases.
if (retries > 15)
return 0;
}
}
if (kb >= KB_FIRMWARE_VERSION_700)
se_aes_unwrap_key(8, 12, package2_keyseed);
else if (kb == KB_FIRMWARE_VERSION_620)
{
// Set TSEC key.
se_aes_key_set(12, tmp, 0x10);
// Set TSEC root key.
se_aes_key_set(13, tmp + 0x10, 0x10);
// Package2 key.
se_aes_key_set(8, tmp + 0x10, 0x10);
se_aes_unwrap_key(8, 8, master_keyseed_620);
se_aes_unwrap_key(8, 8, master_keyseed_retail);
se_aes_unwrap_key(8, 8, package2_keyseed);
}
else
{
se_key_acc_ctrl(13, 0x15);
se_key_acc_ctrl(14, 0x15);
// Set TSEC key.
se_aes_key_set(13, tmp, 0x10);
// Derive keyblob keys from TSEC+SBK.
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[0]);
se_aes_unwrap_key(15, 14, tmp);
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[kb]);
se_aes_unwrap_key(13, 14, tmp);
// Clear SBK.
se_aes_key_clear(14);
//TODO: verify keyblob CMAC.
//se_aes_unwrap_key(11, 13, cmac_keyseed);
//se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0);
//if (!memcmp(keyblob, tmp, 0x10))
// return 0;
se_aes_crypt_block_ecb(13, 0, tmp, cmac_keyseed);
se_aes_unwrap_key(11, 13, cmac_keyseed);
// Decrypt keyblob and set keyslots.
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); // Package1 key.
se_aes_key_set(12, keyblob + 0x20, 0x10);
se_aes_key_set(13, keyblob + 0x20, 0x10);
se_aes_crypt_block_ecb(12, 0, tmp, master_keyseed_retail);
switch (kb)
{
case KB_FIRMWARE_VERSION_100_200:
case KB_FIRMWARE_VERSION_300:
case KB_FIRMWARE_VERSION_301:
se_aes_unwrap_key(13, 15, console_keyseed);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
case KB_FIRMWARE_VERSION_400:
se_aes_unwrap_key(13, 15, console_keyseed_4xx_5xx);
se_aes_unwrap_key(15, 15, console_keyseed);
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
case KB_FIRMWARE_VERSION_500:
case KB_FIRMWARE_VERSION_600:
se_aes_unwrap_key(10, 15, console_keyseed_4xx_5xx);
se_aes_unwrap_key(15, 15, console_keyseed);
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
}
// Package2 key.
se_key_acc_ctrl(8, 0x15);
se_aes_unwrap_key(8, 12, package2_keyseed);
}
return 1;
}

70
nyx/nyx_gui/hos/hos.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2018 naehrwert
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _HOS_H_
#define _HOS_H_
#include "pkg1.h"
#include "pkg2.h"
#include "../utils/types.h"
#include "../config/ini.h"
#include "../sec/tsec.h"
#define KB_FIRMWARE_VERSION_100_200 0
#define KB_FIRMWARE_VERSION_300 1
#define KB_FIRMWARE_VERSION_301 2
#define KB_FIRMWARE_VERSION_400 3
#define KB_FIRMWARE_VERSION_500 4
#define KB_FIRMWARE_VERSION_600 5
#define KB_FIRMWARE_VERSION_620 6
#define KB_FIRMWARE_VERSION_700 7
#define KB_FIRMWARE_VERSION_810 8
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_810
#define HOS_PKG11_MAGIC 0x31314B50
typedef struct _launch_ctxt_t
{
void *keyblob;
void *pkg1;
const pkg1_id_t *pkg1_id;
void *warmboot;
u32 warmboot_size;
void *secmon;
u32 secmon_size;
void *pkg2;
u32 pkg2_size;
bool new_pkg2;
void *kernel;
u32 kernel_size;
link_t kip1_list;
char* kip1_patches;
bool svcperm;
bool debugmode;
bool stock;
bool atmosphere;
ini_sec_t *cfg;
} launch_ctxt_t;
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt);
#endif

95
nyx/nyx_gui/hos/pkg1.c Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "pkg1.h"
#include "../gfx/gfx.h"
#include "../mem/heap.h"
#include "../sec/se.h"
#include "../utils/aarch64_util.h"
/*
* package1.1 header: <wb, ldr, sm>
* package1.1 layout:
* 1.0: {sm, ldr, wb} { 2, 1, 0 }
* 2.0: {wb, ldr, sm} { 0, 1, 2 }
* 3.0: {wb, ldr, sm} { 0, 1, 2 }
* 3.1: {wb, ldr, sm} { 0, 1, 2 }
* 4.0: {ldr, sm, wb} { 1, 2, 0 }
* 5.0: {ldr, sm, wb} { 1, 2, 0 }
* 6.0: {ldr, sm, wb} { 1, 2, 0 }
* 6.2: {ldr, sm, wb} { 1, 2, 0 }
* 7.0: {ldr, sm, wb} { 1, 2, 0 }
*/
static const pkg1_id_t _pkg1_ids[] = {
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, 0x40014020, 0x8000D000 }, //1.0.0
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000 }, //2.0.0 - 2.3.0
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000 }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000 }, //3.0.1 - 3.0.2
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000 }, //4.0.0 - 4.1.0
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000 }, //5.0.0 - 5.1.0
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800 }, //6.0.0 - 6.1.0
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800 }, //6.2.0
{ "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000 }, //7.0.0
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000 }, //7.0.1
{ "20190314172056", 7, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000 }, //8.0.0 - 8.0.1
{ "20190531152432", 8, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000 }, //8.1.0
{ NULL } //End.
};
const pkg1_id_t *pkg1_identify(u8 *pkg1, char *build_date)
{
memcpy(build_date, (char *)(pkg1 + 0x10), 14);
build_date[14] = 0;
for (u32 i = 0; _pkg1_ids[i].id; i++)
if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12))
return &_pkg1_ids[i];
return NULL;
}
void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1)
{
// Decrypt package1.
u8 *pkg11 = pkg1 + id->pkg11_off;
u32 pkg11_size = *(u32 *)pkg11;
se_aes_crypt_ctr(11, pkg11 + 0x20, pkg11_size, pkg11 + 0x20, pkg11_size, pkg11 + 0x10);
}
void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1)
{
pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20);
u32 sec_size[3] = { hdr->wb_size, hdr->ldr_size, hdr->sm_size };
//u32 sec_off[3] = { hdr->wb_off, hdr->ldr_off, hdr->sm_off };
u8 *pdata = (u8 *)hdr + sizeof(pk11_hdr_t);
for (u32 i = 0; i < 3; i++)
{
if (id->sec_map[i] == 0 && warmboot_dst)
memcpy(warmboot_dst, pdata, sec_size[id->sec_map[i]]);
else if (id->sec_map[i] == 1 && ldr_dst)
memcpy(ldr_dst, pdata, sec_size[id->sec_map[i]]);
else if (id->sec_map[i] == 2 && secmon_dst)
memcpy(secmon_dst, pdata, sec_size[id->sec_map[i]]);
pdata += sec_size[id->sec_map[i]];
}
}

49
nyx/nyx_gui/hos/pkg1.h Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2018 naehrwert
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PKG1_H_
#define _PKG1_H_
#include "../utils/types.h"
typedef struct _pkg1_id_t
{
const char *id;
u32 kb;
u32 tsec_off;
u32 pkg11_off;
u32 sec_map[3];
u32 secmon_base;
u32 warmboot_base;
} pkg1_id_t;
typedef struct _pk11_hdr_t
{
u32 magic;
u32 wb_size;
u32 wb_off;
u32 pad;
u32 ldr_size;
u32 ldr_off;
u32 sm_size;
u32 sm_off;
} pk11_hdr_t;
const pkg1_id_t *pkg1_identify(u8 *pkg1, char *build_date);
void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1);
void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1);
#endif

104
nyx/nyx_gui/hos/pkg2.c Normal file
View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "pkg2.h"
#include "hos.h"
#include "../libs/fatfs/ff.h"
#include "../utils/aarch64_util.h"
#include "../mem/heap.h"
#include "../sec/se.h"
#include "../libs/compr/blz.h"
#include "../gfx/gfx.h"
/*#include "util.h"
#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DEBUG_PRINTING*/
#define DPRINTF(...)
u32 pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
{
u32 size = sizeof(pkg2_kip1_t);
for (u32 j = 0; j < KIP1_NUM_SECTIONS; j++)
size += kip1->sections[j].size_comp;
return size;
}
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
{
u8 *ptr;
// Check for new pkg2 type.
if (!pkg2->sec_size[PKG2_SEC_INI1])
{
u32 kernel_ini1_off = *(u32 *)(pkg2->data + PKG2_NEWKERN_INI1_START);
ptr = pkg2->data + kernel_ini1_off;
*new_pkg2 = true;
}
else
ptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL];
pkg2_ini1_t *ini1 = (pkg2_ini1_t *)ptr;
ptr += sizeof(pkg2_ini1_t);
for (u32 i = 0; i < ini1->num_procs; i++)
{
pkg2_kip1_t *kip1 = (pkg2_kip1_t *)ptr;
pkg2_kip1_info_t *ki = (pkg2_kip1_info_t *)malloc(sizeof(pkg2_kip1_info_t));
ki->kip1 = kip1;
ki->size = pkg2_calc_kip1_size(kip1);
list_append(info, &ki->link);
ptr += ki->size;
DPRINTF(" kip1 %d:%s @ %08X (%08X)\n", i, kip1->name, (u32)kip1, ki->size);
}
}
pkg2_hdr_t *pkg2_decrypt(void *data)
{
u8 *pdata = (u8 *)data;
// Skip signature.
pdata += 0x100;
pkg2_hdr_t *hdr = (pkg2_hdr_t *)pdata;
// Skip header.
pdata += sizeof(pkg2_hdr_t);
// Decrypt header.
se_aes_crypt_ctr(8, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr);
//gfx_hexdump((u32)hdr, hdr, 0x100);
if (hdr->magic != PKG2_MAGIC)
return NULL;
for (u32 i = 0; i < 4; i++)
{
DPRINTF("sec %d has size %08X\n", i, hdr->sec_size[i]);
if (!hdr->sec_size[i])
continue;
se_aes_crypt_ctr(8, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]);
//gfx_hexdump((u32)pdata, pdata, 0x100);
pdata += hdr->sec_size[i];
}
return hdr;
}

94
nyx/nyx_gui/hos/pkg2.h Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PKG2_H_
#define _PKG2_H_
#include "../utils/types.h"
#include "../utils/list.h"
#define PKG2_MAGIC 0x31324B50
#define PKG2_SEC_BASE 0x80000000
#define PKG2_SEC_KERNEL 0
#define PKG2_SEC_INI1 1
#define INI1_MAGIC 0x31494E49
#define PKG2_NEWKERN_INI1_START 0x168
#define PKG2_NEWKERN_INI1_END 0x170
#define PKG2_NEWKERN_START 0x800
typedef struct _pkg2_hdr_t
{
u8 ctr[0x10];
u8 sec_ctr[0x40];
u32 magic;
u32 base;
u32 pad0;
u16 version;
u16 pad1;
u32 sec_size[4];
u32 sec_off[4];
u8 sec_sha256[0x80];
u8 data[];
} pkg2_hdr_t;
typedef struct _pkg2_ini1_t
{
u32 magic;
u32 size;
u32 num_procs;
u32 pad;
} pkg2_ini1_t;
typedef struct _pkg2_kip1_sec_t
{
u32 offset;
u32 size_decomp;
u32 size_comp;
u32 attrib;
} pkg2_kip1_sec_t;
#define KIP1_NUM_SECTIONS 6
typedef struct _pkg2_kip1_t
{
u32 magic;
u8 name[12];
u64 tid;
u32 proc_cat;
u8 main_thrd_prio;
u8 def_cpu_core;
u8 res;
u8 flags;
pkg2_kip1_sec_t sections[KIP1_NUM_SECTIONS];
u32 caps[0x20];
u8 data[];
} pkg2_kip1_t;
typedef struct _pkg2_kip1_info_t
{
pkg2_kip1_t *kip1;
u32 size;
link_t link;
} pkg2_kip1_info_t;
u32 pkg2_calc_kip1_size(pkg2_kip1_t *kip1);
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
pkg2_hdr_t *pkg2_decrypt(void *data);
#endif

220
nyx/nyx_gui/hos/sept.c Normal file
View File

@ -0,0 +1,220 @@
/*
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "hos.h"
#include "sept.h"
#include "../config/config.h"
#include "../gfx/di.h"
#include "../ianos/ianos.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../soc/hw_init.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/btn.h"
#include "../utils/types.h"
#include "../utils/util.h"
#include "../gfx/gfx.h"
#define RELOC_META_OFF 0x7C
#define PATCHED_RELOC_SZ 0x94
#define WB_RST_ADDR 0x40010ED0
#define WB_RST_SIZE 0x30
u8 warmboot_reboot[] = {
0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450
0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1
0x00, 0x10, 0x80, 0xE5, // STR R1, [R0]
0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400
0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10
0x00, 0x10, 0x80, 0xE5, // STR R1, [R0]
0xFE, 0xFF, 0xFF, 0xEA, // LOOP
0x50, 0xE4, 0x00, 0x70, // #0x7000E450
0x00, 0xE4, 0x00, 0x70 // #0x7000E400
};
#define SEPT_PRI_ADDR 0x4003F000
#define SEPT_PK1T_ADDR 0xC0400000
#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4)
#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100)
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
extern volatile boot_cfg_t *b_cfg;
extern hekate_config h_cfg;
extern volatile nyx_storage_t *nyx_str;
extern void *sd_file_read(char *path);
extern void sd_mount();
extern void sd_unmount(bool deinit);
extern bool is_ipl_updated(void *buf);
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
void check_sept()
{
// Check if non-hekate payload is used for sept and restore it.
if (h_cfg.sept_run && !f_stat("sept/payload.bak", NULL))
{
f_unlink("sept/payload.bin");
f_rename("sept/payload.bak", "sept/payload.bin");
return;
}
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out_free;
}
sdmmc_storage_set_mmc_partition(&storage, 1);
// Read package1.
char *build_date = malloc(32);
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1, build_date);
free(build_date);
if (!pkg1_id)
{
gfx_con.fntsz = 16;
EPRINTF("Unknown pkg1 version.");
goto out_free;
}
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
{
sdmmc_storage_end(&storage);
reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb);
}
out_free:
free(pkg1);
sdmmc_storage_end(&storage);
}
int reboot_to_sept(const u8 *tsec_fw, u32 kb)
{
FIL fp;
// Copy warmboot reboot code and TSEC fw.
u32 tsec_fw_size = 0x3000;
if (kb > KB_FIRMWARE_VERSION_700)
tsec_fw_size = 0x3300;
memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot));
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_fw_size);
*(vu32 *)SEPT_TCSZ_ADDR = tsec_fw_size;
// Copy sept-primary.
if (f_open(&fp, "sept/sept-primary.bin", FA_READ))
goto error;
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
{
f_close(&fp);
goto error;
}
f_close(&fp);
// Copy sept-secondary.
if (kb < KB_FIRMWARE_VERSION_810)
{
if (f_open(&fp, "sept/sept-secondary_00.enc", FA_READ))
if (f_open(&fp, "sept/sept-secondary.enc", FA_READ)) // Try the deprecated version.
goto error;
}
else
{
if (f_open(&fp, "sept/sept-secondary_01.enc", FA_READ))
goto error;
}
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
{
f_close(&fp);
goto error;
}
f_close(&fp);
b_cfg->boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN);
b_cfg->extra_cfg = EXTRA_CFG_NYX_DUMP;
bool update_sept_payload = true;
if (!f_open(&fp, "sept/payload.bin", FA_READ | FA_WRITE))
{
ipl_ver_meta_t tmp_ver;
ipl_ver_meta_t heka_ver;
f_lseek(&fp, PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
f_read(&fp, &tmp_ver, sizeof(ipl_ver_meta_t), NULL);
memcpy(&heka_ver, (u8 *)nyx_str->hekate + 0x118, sizeof(ipl_ver_meta_t));
if (tmp_ver.magic == heka_ver.magic)
{
if (tmp_ver.version == heka_ver.version)
{
// Save auto boot config to sept payload, if any.
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
memcpy(tmp_cfg, (boot_cfg_t *)b_cfg, sizeof(boot_cfg_t));
f_lseek(&fp, PATCHED_RELOC_SZ);
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
f_close(&fp);
update_sept_payload = false;
}
}
else
f_rename("sept/payload.bin", "sept/payload.bak"); // Backup foreign payload.
f_close(&fp);
}
if (update_sept_payload)
{
volatile reloc_meta_t *reloc = (reloc_meta_t *)(nyx_str->hekate + RELOC_META_OFF);
f_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS);
f_write(&fp, (u8 *)nyx_str->hekate, reloc->end - reloc->start, NULL);
f_close(&fp);
}
sd_unmount(true);
u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE);
void (*sept)() = (void *)pk1t_sept;
reloc_patcher(WB_RST_ADDR, pk1t_sept, SEPT_PKG_SZ);
// Patch SDRAM init to perform an SVC immediately after second write.
PMC(APBDEV_PMC_SCRATCH45) = 0x2E38DFFF;
PMC(APBDEV_PMC_SCRATCH46) = 0x6001DC28;
// Set SVC handler to jump to sept-primary in IRAM.
PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR;
PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208;
reconfig_hw_workaround(false, 0);
(*sept)();
error:
return 0;
}

25
nyx/nyx_gui/hos/sept.h Normal file
View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SEPT_H_
#define _SEPT_H_
#include "../utils/types.h"
void check_sept();
int reboot_to_sept(const u8 *tsec_fw, u32 kb);
#endif

131
nyx/nyx_gui/ianos/ianos.c Normal file
View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 2018 M4xw
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "ianos.h"
#include "../utils/types.h"
#include "../libs/elfload/elfload.h"
#include "../../../common/common_module.h"
#include "../mem/heap.h"
#include "../gfx/gfx.h"
#define IRAM_LIB_ADDR 0x4002B000
#define DRAM_LIB_ADDR 0xE0000000
extern heap_t _heap;
extern void *sd_file_read(const char *path, u32 *fsize);
extern bool sd_mount();
extern void sd_unmount(bool deinit);
void *elfBuf = NULL;
void *fileBuf = NULL;
static void _ianos_call_ep(moduleEntrypoint_t entrypoint, void *moduleConfig)
{
bdkParams_t bdkParameters = (bdkParams_t)malloc(sizeof(struct _bdkParams_t));
bdkParameters->gfxCon = &gfx_con;
bdkParameters->gfxCtx = &gfx_ctxt;
bdkParameters->memcpy = (memcpy_t)&memcpy;
bdkParameters->memset = (memset_t)&memset;
bdkParameters->sharedHeap = &_heap;
entrypoint(moduleConfig, bdkParameters);
}
static void *_ianos_alloc_cb(el_ctx *ctx, Elf_Addr phys, Elf_Addr virt, Elf_Addr size)
{
(void)ctx;
(void)phys;
(void)size;
return (void *)virt;
}
static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t offset)
{
(void)ctx;
memcpy(dest, fileBuf + offset, numberBytes);
return true;
}
//TODO: Support shared libraries.
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
{
uintptr_t epaddr = 0;
if (sdmount)
{
if (!sd_mount())
goto elfLoadFinalOut;
}
fileBuf = sd_file_read(path, NULL);
if (sdmount)
sd_unmount(true);
if (!fileBuf)
goto elfLoadFinalOut;
el_ctx ctx;
ctx.pread = _ianos_read_cb;
if (el_init(&ctx))
goto elfLoadFinalOut;
// Set our relocated library's buffer.
switch (type & 0xFFFF)
{
case EXEC_ELF:
case AR64_ELF:
elfBuf = (void *)DRAM_LIB_ADDR;
sd_unmount(true);
break;
default:
elfBuf = memalign(ctx.align, ctx.memsz);
}
if (!elfBuf)
goto elfLoadFinalOut;
// Load and relocate library.
ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf;
if (el_load(&ctx, _ianos_alloc_cb))
goto elfFreeOut;
if (el_relocate(&ctx))
goto elfFreeOut;
// Launch.
epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf;
moduleEntrypoint_t ep = (moduleEntrypoint_t)epaddr;
_ianos_call_ep(ep, moduleConfig);
elfFreeOut:
free(fileBuf);
elfBuf = NULL;
fileBuf = NULL;
elfLoadFinalOut:
return epaddr;
}

34
nyx/nyx_gui/ianos/ianos.h Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2018 M4xw
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IANOS_H
#define IANOS_H
#include "../utils/types.h"
typedef enum
{
DRAM_LIB = 0, // DRAM library.
EXEC_ELF = 1, // Executable elf that does not return.
DR64_LIB = 2, // AARCH64 DRAM library.
AR64_ELF = 3, // Executable elf that does not return.
KEEP_IN_RAM = (1 << 31) // Shared library mask.
} elfType_t;
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void* config);
#endif

118
nyx/nyx_gui/input/als.c Normal file
View File

@ -0,0 +1,118 @@
/*
* Ambient light sensor driver for Nintendo Switch's Rohm BH1730
*
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "als.h"
#include "../power/max77620.h"
#include "../soc/clock.h"
#include "../soc/i2c.h"
#include "../soc/pinmux.h"
#include "../utils/util.h"
#define HOS_GAIN BH1730_GAIN_64X
#define HOS_ITIME 38
void set_als_cfg(als_table_t *als_val, u8 gain, u8 itime)
{
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain);
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - itime));
als_val->gain = gain;
als_val->itime = itime;
}
void get_als_lux(als_table_t *als_val)
{
u32 data[2];
float pre_gain_lux;
float visible_light;
float ir_light;
float light_ratio;
u8 adc_ready = 0;
u8 retries = 100;
const float als_gain_idx_tbl[4] = { 1.0, 2.0, 64.0, 128.0 };
const float als_norm_res = 100.0;
const float als_multiplier = 3.6;
const float als_tint = 2.7;
// Wait for ADC to prepare new data.
while (!(adc_ready & BH1730_CTL_ADC_VALID) && retries)
{
retries--;
adc_ready = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG));
}
// Get visible and ir light raw data.
data[0] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0LOW_REG)) +
(i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0HIGH_REG)) << 8);
data[1] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1LOW_REG)) +
(i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1HIGH_REG)) << 8);
als_val->over_limit = data[0] > 65534 || data[1] > 65534;
als_val->vi_light = data[0];
als_val->ir_light = data[1];
if (!data[0] || !retries)
{
als_val->lux = 0.0;
return;
}
visible_light = (float)data[0];
ir_light = (float)data[1];
light_ratio = (float)data[1] / (float)data[0];
// The following are specific to the light filter Switch uses.
if (light_ratio < 0.5)
pre_gain_lux = visible_light * 5.002 - ir_light * 7.502;
else if (light_ratio < 0.754)
pre_gain_lux = visible_light * 2.250 - ir_light * 2.000;
else if (light_ratio < 1.029)
pre_gain_lux = visible_light * 1.999 - ir_light * 1.667;
else if (light_ratio < 1.373)
pre_gain_lux = visible_light * 0.884 - ir_light * 0.583;
else if (light_ratio < 1.879)
pre_gain_lux = visible_light * 0.309 - ir_light * 0.165;
else pre_gain_lux = 0.0;
als_val->lux = (pre_gain_lux / als_gain_idx_tbl[als_val->gain]) * (als_norm_res / ((float)als_val->itime * als_tint)) * als_multiplier;
}
u8 als_init(als_table_t *als_val)
{
pinmux_config_i2c(I2C_2);
clock_enable_i2c(I2C_2);
i2c_init(I2C_2);
max77620_regulator_set_volt_and_flags(REGULATOR_LDO6, 2900000, MAX77620_POWER_MODE_NORMAL);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, 0xD8 | MAX77620_LDO_CFG2_ADE_MASK);
u8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12));
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0);
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), HOS_GAIN);
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - HOS_ITIME));
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG), BH1730_CTL_POWER_ON | BH1730_CTL_ADC_EN);
als_val->gain = HOS_GAIN;
als_val->itime = HOS_ITIME;
return id;
}

65
nyx/nyx_gui/input/als.h Normal file
View File

@ -0,0 +1,65 @@
/*
* Ambient light sensor driver for Nintendo Switch's Rohm BH1730
*
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ALS_H_
#define __ALS_H_
#include "../utils/types.h"
#define BH1730_I2C_ADDR 0x29
#define BH1730_CMD_MAGIC 0x80
#define BH1730_CMD_SETADDR 0x00
#define BH1730_CMD_SPECCMD 0x60
#define BH1730_SPECCMD_RESET 0x4
#define BH1730_CONTROL_REG 0x00
#define BH1730_CTL_ADC_VALID 0x10
#define BH1730_CTL_ONE_TIME 0x08
#define BH1730_CTL_DAT0_ONLY 0x04
#define BH1730_CTL_ADC_EN 0x02
#define BH1730_CTL_POWER_ON 0x01
#define BH1730_TIMING_REG 0x01
#define BH1730_GAIN_REG 0x07
#define BH1730_GAIN_1X 0x00
#define BH1730_GAIN_2X 0x01
#define BH1730_GAIN_64X 0x02
#define BH1730_GAIN_128X 0x03
#define BH1730_DATA0LOW_REG 0x14
#define BH1730_DATA0HIGH_REG 0x15
#define BH1730_DATA1LOW_REG 0x16
#define BH1730_DATA1HIGH_REG 0x17
#define BH1730_ADDR(reg) (BH1730_CMD_MAGIC | BH1730_CMD_SETADDR | reg)
#define BH1730_SPEC(cmd) (BH1730_CMD_MAGIC | BH1730_CMD_SPECCMD | cmd)
typedef struct _als_table_t
{
float lux;
bool over_limit;
u32 vi_light;
u32 ir_light;
u8 gain;
u8 itime;
} als_table_t;
void set_als_cfg(als_table_t *als_val, u8 gain, u8 itime);
void get_als_lux(als_table_t *als_val);
u8 als_init(als_table_t *als_val);
#endif /* __ALS_H_ */

206
nyx/nyx_gui/input/touch.c Normal file
View File

@ -0,0 +1,206 @@
/*
* Touch driver for Nintendo Switch's STMicroelectronics FingerTip touch controller
*
* Copyright (c) 2018 langerhans
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "../soc/clock.h"
#include "../soc/i2c.h"
#include "../soc/pinmux.h"
#include "../power/max7762x.h"
#include "../power/max77620.h"
#include "../soc/gpio.h"
#include "../soc/t210.h"
#include "../utils/util.h"
#include "touch.h"
#include "../gfx/gfx.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
static int touch_command(u8 cmd)
{
int err = i2c_send_byte(I2C_3, STMFTS_I2C_ADDR, cmd, 0);
if (!err)
return 1;
// TODO: Check for completion in event loop
msleep(1);
return 0;
}
static void _touch_process_contact_event(touch_event *event, bool touching)
{
event->x = (event->raw[2] << 4) | ((event->raw[4] & STMFTS_MASK_Y_LSB) >> 4);
// Normally, GUI elements have bigger horizontal estate.
// Avoid parsing y axis when finger is removed to minimize touch noise.
if (touching)
{
event->y = (event->raw[3] << 4) | (event->raw[4] & STMFTS_MASK_X_MSB);
event->z = event->raw[5];
event->fingers = ((event->raw[1] & STMFTS_MASK_TOUCH_ID) >> 4) + 1;
}
else
event->fingers = 0;
}
static void _touch_parse_event(touch_event *event)
{
event->type = event->raw[1] & STMFTS_MASK_EVENT_ID;
switch (event->type)
{
case STMFTS_EV_MULTI_TOUCH_ENTER:
case STMFTS_EV_MULTI_TOUCH_MOTION:
_touch_process_contact_event(event, true);
if (event->z > 52) // Discard noisy hover touch.
event->touch = true;
else
{
event->touch = false;
event->type = STMFTS_EV_MULTI_TOUCH_LEAVE;
}
break;
case STMFTS_EV_MULTI_TOUCH_LEAVE:
event->touch = false;
_touch_process_contact_event(event, false);
break;
case STMFTS_EV_NO_EVENT:
if (event->touch)
event->type = STMFTS_EV_MULTI_TOUCH_MOTION;
break;
default:
if (event->touch && event->raw[0] == STMFTS_EV_MULTI_TOUCH_MOTION)
event->type = STMFTS_EV_MULTI_TOUCH_MOTION;
else
event->type = STMFTS_EV_MULTI_TOUCH_LEAVE;
}
// gfx_con_setpos(&gfx_con, 0, 300);
// DPRINTF("x = %d \ny = %d \nz: %d \n", event->x, event->y, event->z);
// DPRINTF("0 = %02X\n1 = %02x\n2 = %02x\n3 = %02x\n", event->raw[0], event->raw[1], event->raw[2], event->raw[3]);
// DPRINTF("4 = %02X\n5 = %02x\n6 = %02x\n7 = %02x\n", event->raw[4], event->raw[5], event->raw[6], event->raw[7]);
}
void touch_poll(touch_event *event)
{
i2c_recv_buf_small(event->raw, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_LATEST_EVENT);
_touch_parse_event(event);
}
touch_event touch_poll_wait()
{
touch_event event;
do
{
touch_poll(&event);
} while (event.type != STMFTS_EV_MULTI_TOUCH_LEAVE);
return event;
}
touch_info touch_get_info()
{
touch_info info;
u8 buf[8];
memset(&buf, 0, 8);
i2c_recv_buf_small(buf, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_INFO);
info.chip_id = buf[0] << 8 | buf[1];
info.fw_ver = buf[2] << 8 | buf[3];
info.config_id = buf[4];
info.config_ver = buf[5];
//DPRINTF("ID: %04X, FW Ver: %d.%02d\nCfg ID: %02x, Cfg Ver: %d\n",
// info.chip_id, info.fw_ver >> 8, info.fw_ver & 0xFF, info.config_id, info.config_ver);
return info;
}
int touch_power_on()
{
// Configure touchscreen GPIO.
PINMUX_AUX(PINMUX_AUX_DAP4_SCLK) = PINMUX_PULL_DOWN | 3;
gpio_config(GPIO_PORT_J, GPIO_PIN_7, GPIO_MODE_GPIO);
gpio_output_enable(GPIO_PORT_J, GPIO_PIN_7, GPIO_OUTPUT_ENABLE);
gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_HIGH);
// IRQ and more.
// PINMUX_AUX(PINMUX_AUX_TOUCH_INT) = PINMUX_TRISTATE | PINMUX_PULL_UP | 3;
// gpio_config(GPIO_PORT_X, GPIO_PIN_1, GPIO_MODE_GPIO);
// gpio_write(GPIO_PORT_X, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, GPIO_LOW);
// Configure Touscreen and GCAsic shared GPIO.
PINMUX_AUX(PINMUX_AUX_CAM_I2C_SDA) = PINMUX_TRISTATE | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 3;
gpio_config(GPIO_PORT_S, GPIO_PIN_3, GPIO_MODE_GPIO);
// Initialize I2C3.
pinmux_config_i2c(I2C_3);
clock_enable_i2c(I2C_3);
i2c_init(I2C_3);
// Enables LDO6 for touchscreen VDD/AVDD supply
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG, 0xEA);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, 0xDA);
msleep(20);
// Initialize touchscreen module.
if (touch_command(STMFTS_SYSTEM_RESET))
return 0;
if (touch_command(STMFTS_SLEEP_OUT))
return 0;
if (touch_command(STMFTS_MS_CX_TUNING))
return 0;
if (touch_command(STMFTS_SS_CX_TUNING))
return 0;
if (touch_command(STMFTS_FULL_FORCE_CALIBRATION))
return 0;
if (touch_command(STMFTS_MS_MT_SENSE_ON))
return 0;
if (touch_command(STMFTS_SS_HOVER_SENSE_OFF))
return 0;
return 1;
}
void touch_power_off()
{
touch_command(STMFTS_SLEEP_IN);
// Disables LDO6 for touchscreen VDD, AVDD supply
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG, 0x28);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO6_CFG2, 0xD2);
clock_disable_i2c(I2C_3);
// Disable touchscreen power.
gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_LOW);
pinmux_config_i2c(I2C_3);
}

115
nyx/nyx_gui/input/touch.h Normal file
View File

@ -0,0 +1,115 @@
/*
* Touch driver for Nintendo Switch's STMicroelectronics FingerTip S touch controller
*
* Copyright (c) 2018 langerhans
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TOUCH_H_
#define __TOUCH_H_
#include "../utils/types.h"
#define STMFTS_I2C_ADDR 0x49
/* I2C commands */
#define STMFTS_READ_INFO 0x80
#define STMFTS_READ_STATUS 0x84
#define STMFTS_READ_ONE_EVENT 0x85
#define STMFTS_READ_ALL_EVENT 0x86
#define STMFTS_LATEST_EVENT 0x87
#define STMFTS_SLEEP_IN 0x90
#define STMFTS_SLEEP_OUT 0x91
#define STMFTS_MS_MT_SENSE_OFF 0x92
#define STMFTS_MS_MT_SENSE_ON 0x93
#define STMFTS_SS_HOVER_SENSE_OFF 0x94
#define STMFTS_SS_HOVER_SENSE_ON 0x95
#define STMFTS_MS_KEY_SENSE_OFF 0x9A
#define STMFTS_MS_KEY_SENSE_ON 0x9B
#define STMFTS_SYSTEM_RESET 0xA0
#define STMFTS_CLEAR_EVENT_STACK 0xA1
#define STMFTS_FULL_FORCE_CALIBRATION 0xA2
#define STMFTS_MS_CX_TUNING 0xA3
#define STMFTS_SS_CX_TUNING 0xA4
#define STMFTS_RELEASEINFO 0xAA
#define STMFTS_WRITE_REG 0xB6
#define STMFTS_RW_FB_REG 0xD0 // read data
#define STMFTS_UNK0 0xB8 //Request compensation
#define STMFTS_UNK1 0xCF
#define STMFTS_UNK2 0xF7
#define STMFTS_UNK3 0xFA
#define STMFTS_UNK4 0xF9
#define STMFTS_UNK5 0x62
/* events */
#define STMFTS_EV_NO_EVENT 0x00
#define STMFTS_EV_MULTI_TOUCH_DETECTED 0x02
#define STMFTS_EV_MULTI_TOUCH_ENTER 0x03
#define STMFTS_EV_MULTI_TOUCH_LEAVE 0x04
#define STMFTS_EV_MULTI_TOUCH_MOTION 0x05
#define STMFTS_EV_HOVER_ENTER 0x07
#define STMFTS_EV_HOVER_LEAVE 0x08
#define STMFTS_EV_HOVER_MOTION 0x09
#define STMFTS_EV_KEY_STATUS 0x0e
#define STMFTS_EV_ERROR 0x0f
#define STMFTS_EV_CONTROLLER_READY 0x10
#define STMFTS_EV_SLEEP_OUT_CONTROLLER_READY 0x11
#define STMFTS_EV_STATUS 0x16
#define STMFTS_EV_DEBUG 0xDB
/* multi touch related event masks */
#define STMFTS_MASK_EVENT_ID 0x0F
#define STMFTS_MASK_TOUCH_ID 0xF0
#define STMFTS_MASK_LEFT_EVENT 0x0F
#define STMFTS_MASK_X_MSB 0x0F
#define STMFTS_MASK_Y_LSB 0xF0
/* key related event masks */
#define STMFTS_MASK_KEY_NO_TOUCH 0x00
#define STMFTS_MASK_KEY_MENU 0x01
#define STMFTS_MASK_KEY_BACK 0x02
#define STMFTS_EVENT_SIZE 8
#define STMFTS_STACK_DEPTH 32
#define STMFTS_DATA_MAX_SIZE (STMFTS_EVENT_SIZE * STMFTS_STACK_DEPTH)
#define STMFTS_MAX_FINGERS 10
typedef struct _touch_event {
u8 raw[8];
u16 type; // Event type.
u16 x; // Horizontal coordinates.
u16 y; // Vertical coordinates.
u8 z;
u8 fingers;
bool touch;
} touch_event;
typedef struct _touch_info {
u16 chip_id;
u16 fw_ver;
u16 config_id;
u16 config_ver;
} touch_info;
int touch_power_on();
void touch_power_off();
void touch_poll(touch_event *event);
touch_event touch_poll_wait();
touch_info touch_get_info();
#endif /* __TOUCH_H_ */

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2018 rajkosto
* Copyright (c) 2018 SciresM
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include "blz.h"
const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int compDataLen, blz_footer *outFooter)
{
if (compDataLen < sizeof(blz_footer))
return NULL;
const blz_footer *srcFooter = (const blz_footer*)&compData[compDataLen - sizeof(blz_footer)];
if (outFooter != NULL)
memcpy(outFooter, srcFooter, sizeof(blz_footer)); // Must be a memcpy because no umaligned accesses on ARMv4.
return srcFooter;
}
// From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM!
int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer)
{
u32 addl_size = footer->addl_size;
u32 header_size = footer->header_size;
u32 cmp_and_hdr_size = footer->cmp_and_hdr_size;
unsigned char* cmp_start = &dataBuf[compSize] - cmp_and_hdr_size;
u32 cmp_ofs = cmp_and_hdr_size - header_size;
u32 out_ofs = cmp_and_hdr_size + addl_size;
while (out_ofs)
{
unsigned char control = cmp_start[--cmp_ofs];
for (unsigned int i=0; i<8; i++)
{
if (control & 0x80)
{
if (cmp_ofs < 2)
return 0; // Out of bounds.
cmp_ofs -= 2;
u16 seg_val = ((unsigned int)(cmp_start[cmp_ofs + 1]) << 8) | cmp_start[cmp_ofs];
u32 seg_size = ((seg_val >> 12) & 0xF) + 3;
u32 seg_ofs = (seg_val & 0x0FFF) + 3;
if (out_ofs < seg_size) // Kernel restricts segment copy to stay in bounds.
seg_size = out_ofs;
out_ofs -= seg_size;
for (unsigned int j = 0; j < seg_size; j++)
cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];
}
else
{
// Copy directly.
if (cmp_ofs < 1)
return 0; //out of bounds
cmp_start[--out_ofs] = cmp_start[--cmp_ofs];
}
control <<= 1;
if (out_ofs == 0) // Blz works backwards, so if it reaches byte 0, it's done.
return 1;
}
}
return 1;
}
int blz_uncompress_srcdest(const unsigned char *compData, unsigned int compDataLen, unsigned char *dstData, unsigned int dstSize)
{
blz_footer footer;
const blz_footer *compFooterPtr = blz_get_footer(compData, compDataLen, &footer);
if (compFooterPtr == NULL)
return 0;
// Decompression must be done in-place, so need to copy the relevant compressed data first.
unsigned int numCompBytes = (const unsigned char*)(compFooterPtr)-compData;
memcpy(dstData, compData, numCompBytes);
memset(&dstData[numCompBytes], 0, dstSize - numCompBytes);
return blz_uncompress_inplace(dstData, compDataLen, &footer);
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2018 rajkosto
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _BLZ_H_
#define _BLZ_H_
#include "../../utils/types.h"
typedef struct _blz_footer
{
u32 cmp_and_hdr_size;
u32 header_size;
u32 addl_size;
} blz_footer;
// Returns pointer to footer in compData if present, additionally copies it to outFooter if not NULL.
const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int compDataLen, blz_footer *outFooter);
// Returns 0 on failure.
int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer);
// Returns 0 on failure.
int blz_uncompress_srcdest(const unsigned char *compData, unsigned int compDataLen, unsigned char *dstData, unsigned int dstSize);
#endif

179
nyx/nyx_gui/libs/compr/lz.c Normal file
View File

@ -0,0 +1,179 @@
/*************************************************************************
* Name: lz.c
* Author: Marcus Geelnard
* Description: LZ77 coder/decoder implementation.
* Reentrant: Yes
*
* The LZ77 compression scheme is a substitutional compression scheme
* proposed by Abraham Lempel and Jakob Ziv in 1977. It is very simple in
* its design, and uses no fancy bit level compression.
*
* This is my first attempt at an implementation of a LZ77 code/decoder.
*
* The principle of the LZ77 compression algorithm is to store repeated
* occurrences of strings as references to previous occurrences of the same
* string. The point is that the reference consumes less space than the
* string itself, provided that the string is long enough (in this
* implementation, the string has to be at least 4 bytes long, since the
* minimum coded reference is 3 bytes long). Also note that the term
* "string" refers to any kind of byte sequence (it does not have to be
* an ASCII string, for instance).
*
* The coder uses a brute force approach to finding string matches in the
* history buffer (or "sliding window", if you wish), which is very, very
* slow. I recon the complexity is somewhere between O(n^2) and O(n^3),
* depending on the input data.
*
* There is also a faster implementation that uses a large working buffer
* in which a "jump table" is stored, which is used to quickly find
* possible string matches (see the source code for LZ_CompressFast() for
* more information). The faster method is an order of magnitude faster,
* but still quite slow compared to other compression methods.
*
* The upside is that decompression is very fast, and the compression ratio
* is often very good.
*
* The reference to a string is coded as a (length,offset) pair, where the
* length indicates the length of the string, and the offset gives the
* offset from the current data position. To distinguish between string
* references and literal strings (uncompressed bytes), a string reference
* is preceded by a marker byte, which is chosen as the least common byte
* symbol in the input data stream (this marker byte is stored in the
* output stream as the first byte).
*
* Occurrences of the marker byte in the stream are encoded as the marker
* byte followed by a zero byte, which means that occurrences of the marker
* byte have to be coded with two bytes.
*
* The lengths and offsets are coded in a variable length fashion, allowing
* values of any magnitude (up to 4294967295 in this implementation).
*
* With this compression scheme, the worst case compression result is
* (257/256)*insize + 1.
*
*-------------------------------------------------------------------------
* Copyright (c) 2003-2006 Marcus Geelnard
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would
* be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* Marcus Geelnard
* marcus.geelnard at home.se
*************************************************************************/
/*************************************************************************
* INTERNAL FUNCTIONS *
*************************************************************************/
/*************************************************************************
* _LZ_ReadVarSize() - Read unsigned integer with variable number of
* bytes depending on value.
*************************************************************************/
static int _LZ_ReadVarSize( unsigned int * x, const unsigned char * buf )
{
unsigned int y, b, num_bytes;
/* Read complete value (stop when byte contains zero in 8:th bit) */
y = 0;
num_bytes = 0;
do
{
b = (unsigned int) (*buf ++);
y = (y << 7) | (b & 0x0000007f);
++ num_bytes;
}
while( b & 0x00000080 );
/* Store value in x */
*x = y;
/* Return number of bytes read */
return num_bytes;
}
/*************************************************************************
* PUBLIC FUNCTIONS *
*************************************************************************/
/*************************************************************************
* LZ_Uncompress() - Uncompress a block of data using an LZ77 decoder.
* in - Input (compressed) buffer.
* out - Output (uncompressed) buffer. This buffer must be large
* enough to hold the uncompressed data.
* insize - Number of input bytes.
*************************************************************************/
void LZ_Uncompress( const unsigned char *in, unsigned char *out,
unsigned int insize )
{
unsigned char marker, symbol;
unsigned int i, inpos, outpos, length, offset;
/* Do we have anything to uncompress? */
if( insize < 1 )
{
return;
}
/* Get marker symbol from input stream */
marker = in[ 0 ];
inpos = 1;
/* Main decompression loop */
outpos = 0;
do
{
symbol = in[ inpos ++ ];
if( symbol == marker )
{
/* We had a marker byte */
if( in[ inpos ] == 0 )
{
/* It was a single occurrence of the marker byte */
out[ outpos ++ ] = marker;
++ inpos;
}
else
{
/* Extract true length and offset */
inpos += _LZ_ReadVarSize( &length, &in[ inpos ] );
inpos += _LZ_ReadVarSize( &offset, &in[ inpos ] );
/* Copy corresponding data from history window */
for( i = 0; i < length; ++ i )
{
out[ outpos ] = out[ outpos - offset ];
++ outpos;
}
}
}
else
{
/* No marker, plain copy */
out[ outpos ++ ] = symbol;
}
}
while( inpos < insize );
}

View File

@ -0,0 +1,52 @@
/*************************************************************************
* Name: lz.h
* Author: Marcus Geelnard
* Description: LZ77 coder/decoder interface.
* Reentrant: Yes
*-------------------------------------------------------------------------
* Copyright (c) 2003-2006 Marcus Geelnard
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would
* be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* Marcus Geelnard
* marcus.geelnard at home.se
*************************************************************************/
#ifndef _lz_h_
#define _lz_h_
#ifdef __cplusplus
extern "C" {
#endif
/*************************************************************************
* Function prototypes
*************************************************************************/
void LZ_Uncompress( const unsigned char *in, unsigned char *out,
unsigned int insize );
#ifdef __cplusplus
}
#endif
#endif /* _lz_h_ */

View File

@ -0,0 +1,589 @@
/* $OpenBSD: exec_elf.h,v 1.53 2014/01/03 03:00:39 guenther Exp $ */
/*
* Copyright (c) 1995, 1996 Erik Theisen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* imported sys/exec_elf.h from OpenBSD */
#ifndef ELF_H
#define ELF_H
#include <stdint.h>
typedef uint8_t Elf_Byte;
typedef uint32_t Elf32_Addr; /* Unsigned program address */
typedef uint32_t Elf32_Off; /* Unsigned file offset */
typedef int32_t Elf32_Sword; /* Signed large integer */
typedef uint32_t Elf32_Word; /* Unsigned large integer */
typedef uint16_t Elf32_Half; /* Unsigned medium integer */
typedef uint64_t Elf64_Addr;
typedef uint64_t Elf64_Off;
typedef int32_t Elf64_Shalf;
#ifdef __alpha__
typedef int64_t Elf64_Sword;
typedef uint64_t Elf64_Word;
#else
typedef int32_t Elf64_Sword;
typedef uint32_t Elf64_Word;
#endif
typedef int64_t Elf64_Sxword;
typedef uint64_t Elf64_Xword;
typedef uint32_t Elf64_Half;
typedef uint16_t Elf64_Quarter;
/*
* e_ident[] identification indexes
* See http://www.sco.com/developers/gabi/latest/ch4.eheader.html
*/
#define EI_MAG0 0 /* file ID */
#define EI_MAG1 1 /* file ID */
#define EI_MAG2 2 /* file ID */
#define EI_MAG3 3 /* file ID */
#define EI_CLASS 4 /* file class */
#define EI_DATA 5 /* data encoding */
#define EI_VERSION 6 /* ELF header version */
#define EI_OSABI 7 /* OS/ABI ID */
#define EI_ABIVERSION 8 /* ABI version */
#define EI_PAD 9 /* start of pad bytes */
#define EI_NIDENT 16 /* Size of e_ident[] */
/* e_ident[] magic number */
#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */
#define ELFMAG1 'E' /* e_ident[EI_MAG1] */
#define ELFMAG2 'L' /* e_ident[EI_MAG2] */
#define ELFMAG3 'F' /* e_ident[EI_MAG3] */
#define ELFMAG "\177ELF" /* magic */
#define SELFMAG 4 /* size of magic */
/* e_ident[] file class */
#define ELFCLASSNONE 0 /* invalid */
#define ELFCLASS32 1 /* 32-bit objs */
#define ELFCLASS64 2 /* 64-bit objs */
#define ELFCLASSNUM 3 /* number of classes */
/* e_ident[] data encoding */
#define ELFDATANONE 0 /* invalid */
#define ELFDATA2LSB 1 /* Little-Endian */
#define ELFDATA2MSB 2 /* Big-Endian */
#define ELFDATANUM 3 /* number of data encode defines */
/* e_ident[] Operating System/ABI */
#define ELFOSABI_SYSV 0 /* UNIX System V ABI */
#define ELFOSABI_HPUX 1 /* HP-UX operating system */
#define ELFOSABI_NETBSD 2 /* NetBSD */
#define ELFOSABI_LINUX 3 /* GNU/Linux */
#define ELFOSABI_HURD 4 /* GNU/Hurd */
#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */
#define ELFOSABI_SOLARIS 6 /* Solaris */
#define ELFOSABI_MONTEREY 7 /* Monterey */
#define ELFOSABI_IRIX 8 /* IRIX */
#define ELFOSABI_FREEBSD 9 /* FreeBSD */
#define ELFOSABI_TRU64 10 /* TRU64 UNIX */
#define ELFOSABI_MODESTO 11 /* Novell Modesto */
#define ELFOSABI_OPENBSD 12 /* OpenBSD */
#define ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
/* e_ident */
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
(ehdr).e_ident[EI_MAG3] == ELFMAG3)
/* ELF Header */
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* ELF Identification */
Elf32_Half e_type; /* object file type */
Elf32_Half e_machine; /* machine */
Elf32_Word e_version; /* object file version */
Elf32_Addr e_entry; /* virtual entry point */
Elf32_Off e_phoff; /* program header table offset */
Elf32_Off e_shoff; /* section header table offset */
Elf32_Word e_flags; /* processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size */
Elf32_Half e_phentsize; /* program header entry size */
Elf32_Half e_phnum; /* number of program header entries */
Elf32_Half e_shentsize; /* section header entry size */
Elf32_Half e_shnum; /* number of section header entries */
Elf32_Half e_shstrndx; /* section header table's "section
header string table" entry offset */
} Elf32_Ehdr;
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Id bytes */
Elf64_Quarter e_type; /* file type */
Elf64_Quarter e_machine; /* machine type */
Elf64_Half e_version; /* version number */
Elf64_Addr e_entry; /* entry point */
Elf64_Off e_phoff; /* Program hdr offset */
Elf64_Off e_shoff; /* Section hdr offset */
Elf64_Half e_flags; /* Processor flags */
Elf64_Quarter e_ehsize; /* sizeof ehdr */
Elf64_Quarter e_phentsize; /* Program header entry size */
Elf64_Quarter e_phnum; /* Number of program headers */
Elf64_Quarter e_shentsize; /* Section header entry size */
Elf64_Quarter e_shnum; /* Number of section headers */
Elf64_Quarter e_shstrndx; /* String table index */
} Elf64_Ehdr;
/* e_type */
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* relocatable file */
#define ET_EXEC 2 /* executable file */
#define ET_DYN 3 /* shared object file */
#define ET_CORE 4 /* core file */
#define ET_NUM 5 /* number of types */
#define ET_LOPROC 0xff00 /* reserved range for processor */
#define ET_HIPROC 0xffff /* specific e_type */
/* e_machine */
#define EM_NONE 0 /* No Machine */
#define EM_M32 1 /* AT&T WE 32100 */
#define EM_SPARC 2 /* SPARC */
#define EM_386 3 /* Intel 80386 */
#define EM_68K 4 /* Motorola 68000 */
#define EM_88K 5 /* Motorola 88000 */
#define EM_486 6 /* Intel 80486 - unused? */
#define EM_860 7 /* Intel 80860 */
#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */
/*
* Don't know if EM_MIPS_RS4_BE,
* EM_SPARC64, EM_PARISC,
* or EM_PPC are ABI compliant
*/
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */
#define EM_SPARC64 11 /* SPARC v9 64-bit unofficial */
#define EM_PARISC 15 /* HPPA */
#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */
#define EM_PPC 20 /* PowerPC */
#define EM_ARM 40 /* ARM AArch32 */
#define EM_ALPHA 41 /* DEC ALPHA */
#define EM_SH 42 /* Hitachi/Renesas Super-H */
#define EM_SPARCV9 43 /* SPARC version 9 */
#define EM_IA_64 50 /* Intel IA-64 Processor */
#define EM_AMD64 62 /* AMD64 architecture */
#define EM_VAX 75 /* DEC VAX */
#define EM_AARCH64 183 /* ARM AArch64 */
/* Non-standard */
#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */
/* Version */
#define EV_NONE 0 /* Invalid */
#define EV_CURRENT 1 /* Current */
#define EV_NUM 2 /* number of versions */
/* Section Header */
typedef struct
{
Elf32_Word sh_name; /* name - index into section header
* string table section */
Elf32_Word sh_type; /* type */
Elf32_Word sh_flags; /* flags */
Elf32_Addr sh_addr; /* address */
Elf32_Off sh_offset; /* file offset */
Elf32_Word sh_size; /* section size */
Elf32_Word sh_link; /* section header table index link */
Elf32_Word sh_info; /* extra information */
Elf32_Word sh_addralign; /* address alignment */
Elf32_Word sh_entsize; /* section entry size */
} Elf32_Shdr;
typedef struct
{
Elf64_Half sh_name; /* section name */
Elf64_Half sh_type; /* section type */
Elf64_Xword sh_flags; /* section flags */
Elf64_Addr sh_addr; /* virtual address */
Elf64_Off sh_offset; /* file offset */
Elf64_Xword sh_size; /* section size */
Elf64_Half sh_link; /* link to another */
Elf64_Half sh_info; /* misc info */
Elf64_Xword sh_addralign; /* memory alignment */
Elf64_Xword sh_entsize; /* table entry size */
} Elf64_Shdr;
/* Special Section Indexes */
#define SHN_UNDEF 0 /* undefined */
#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */
#define SHN_LOPROC 0xff00 /* reserved range for processor */
#define SHN_HIPROC 0xff1f /* specific section indexes */
#define SHN_ABS 0xfff1 /* absolute value */
#define SHN_COMMON 0xfff2 /* common symbol */
#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */
/* sh_type */
#define SHT_NULL 0 /* inactive */
#define SHT_PROGBITS 1 /* program defined information */
#define SHT_SYMTAB 2 /* symbol table section */
#define SHT_STRTAB 3 /* string table section */
#define SHT_RELA 4 /* relocation section with addends*/
#define SHT_HASH 5 /* symbol hash table section */
#define SHT_DYNAMIC 6 /* dynamic section */
#define SHT_NOTE 7 /* note section */
#define SHT_NOBITS 8 /* no space section */
#define SHT_REL 9 /* relation section without addends */
#define SHT_SHLIB 10 /* reserved - purpose unknown */
#define SHT_DYNSYM 11 /* dynamic symbol table section */
#define SHT_NUM 12 /* number of section types */
#define SHT_LOPROC 0x70000000 /* reserved range for processor */
#define SHT_HIPROC 0x7fffffff /* specific section header types */
#define SHT_LOUSER 0x80000000 /* reserved range for application */
#define SHT_HIUSER 0xffffffff /* specific indexes */
/* Section names */
#define ELF_BSS ".bss" /* uninitialized data */
#define ELF_DATA ".data" /* initialized data */
#define ELF_DEBUG ".debug" /* debug */
#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */
#define ELF_DYNSTR ".dynstr" /* dynamic string table */
#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */
#define ELF_FINI ".fini" /* termination code */
#define ELF_GOT ".got" /* global offset table */
#define ELF_HASH ".hash" /* symbol hash table */
#define ELF_INIT ".init" /* initialization code */
#define ELF_REL_DATA ".rel.data" /* relocation data */
#define ELF_REL_FINI ".rel.fini" /* relocation termination code */
#define ELF_REL_INIT ".rel.init" /* relocation initialization code */
#define ELF_REL_DYN ".rel.dyn" /* relocation dynamic link info */
#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */
#define ELF_REL_TEXT ".rel.text" /* relocation code */
#define ELF_RODATA ".rodata" /* read-only data */
#define ELF_SHSTRTAB ".shstrtab" /* section header string table */
#define ELF_STRTAB ".strtab" /* string table */
#define ELF_SYMTAB ".symtab" /* symbol table */
#define ELF_TEXT ".text" /* code */
/* Section Attribute Flags - sh_flags */
#define SHF_WRITE 0x1 /* Writable */
#define SHF_ALLOC 0x2 /* occupies memory */
#define SHF_EXECINSTR 0x4 /* executable */
#define SHF_TLS 0x400 /* thread local storage */
#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor \
* specific section attributes */
/* Symbol Table Entry */
typedef struct elf32_sym
{
Elf32_Word st_name; /* name - index into string table */
Elf32_Addr st_value; /* symbol value */
Elf32_Word st_size; /* symbol size */
unsigned char st_info; /* type and binding */
unsigned char st_other; /* 0 - no defined meaning */
Elf32_Half st_shndx; /* section header index */
} Elf32_Sym;
typedef struct
{
Elf64_Half st_name; /* Symbol name index in str table */
Elf_Byte st_info; /* type / binding attrs */
Elf_Byte st_other; /* unused */
Elf64_Quarter st_shndx; /* section index of symbol */
Elf64_Xword st_value; /* value of symbol */
Elf64_Xword st_size; /* size of symbol */
} Elf64_Sym;
/* Symbol table index */
#define STN_UNDEF 0 /* undefined */
/* Extract symbol info - st_info */
#define ELF32_ST_BIND(x) ((x) >> 4)
#define ELF32_ST_TYPE(x) (((unsigned int)x) & 0xf)
#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))
#define ELF64_ST_BIND(x) ((x) >> 4)
#define ELF64_ST_TYPE(x) (((unsigned int)x) & 0xf)
#define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))
/* Symbol Binding - ELF32_ST_BIND - st_info */
#define STB_LOCAL 0 /* Local symbol */
#define STB_GLOBAL 1 /* Global symbol */
#define STB_WEAK 2 /* like global - lower precedence */
#define STB_NUM 3 /* number of symbol bindings */
#define STB_LOPROC 13 /* reserved range for processor */
#define STB_HIPROC 15 /* specific symbol bindings */
/* Symbol type - ELF32_ST_TYPE - st_info */
#define STT_NOTYPE 0 /* not specified */
#define STT_OBJECT 1 /* data object */
#define STT_FUNC 2 /* function */
#define STT_SECTION 3 /* section */
#define STT_FILE 4 /* file */
#define STT_TLS 6 /* thread local storage */
#define STT_LOPROC 13 /* reserved range for processor */
#define STT_HIPROC 15 /* specific symbol types */
/* Relocation entry with implicit addend */
typedef struct
{
Elf32_Addr r_offset; /* offset of relocation */
Elf32_Word r_info; /* symbol table index and type */
} Elf32_Rel;
/* Relocation entry with explicit addend */
typedef struct
{
Elf32_Addr r_offset; /* offset of relocation */
Elf32_Word r_info; /* symbol table index and type */
Elf32_Sword r_addend;
} Elf32_Rela;
/* Extract relocation info - r_info */
#define ELF32_R_SYM(i) ((i) >> 8)
#define ELF32_R_TYPE(i) ((unsigned char)(i))
#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t))
typedef struct
{
Elf64_Xword r_offset; /* where to do it */
Elf64_Xword r_info; /* index & type of relocation */
} Elf64_Rel;
typedef struct
{
Elf64_Xword r_offset; /* where to do it */
Elf64_Xword r_info; /* index & type of relocation */
Elf64_Sxword r_addend; /* adjustment value */
} Elf64_Rela;
#define ELF64_R_SYM(info) ((info) >> 32)
#define ELF64_R_TYPE(info) ((info)&0xFFFFFFFF)
#define ELF64_R_INFO(s, t) (((s) << 32) + (__uint32_t)(t))
#if defined(__mips64__) && defined(__MIPSEL__)
/*
* The 64-bit MIPS ELF ABI uses a slightly different relocation format
* than the regular ELF ABI: the r_info field is split into several
* pieces (see gnu/usr.bin/binutils/include/elf/mips.h for details).
*/
#undef ELF64_R_SYM
#undef ELF64_R_TYPE
#undef ELF64_R_INFO
#define ELF64_R_TYPE(info) (swap32((info) >> 32))
#define ELF64_R_SYM(info) ((info)&0xFFFFFFFF)
#define ELF64_R_INFO(s, t) (((__uint64_t)swap32(t) << 32) + (__uint32_t)(s))
#endif /* __mips64__ && __MIPSEL__ */
/* Program Header */
typedef struct
{
Elf32_Word p_type; /* segment type */
Elf32_Off p_offset; /* segment offset */
Elf32_Addr p_vaddr; /* virtual address of segment */
Elf32_Addr p_paddr; /* physical address - ignored? */
Elf32_Word p_filesz; /* number of bytes in file for seg. */
Elf32_Word p_memsz; /* number of bytes in mem. for seg. */
Elf32_Word p_flags; /* flags */
Elf32_Word p_align; /* memory alignment */
} Elf32_Phdr;
typedef struct
{
Elf64_Half p_type; /* entry type */
Elf64_Half p_flags; /* flags */
Elf64_Off p_offset; /* offset */
Elf64_Addr p_vaddr; /* virtual address */
Elf64_Addr p_paddr; /* physical address */
Elf64_Xword p_filesz; /* file size */
Elf64_Xword p_memsz; /* memory size */
Elf64_Xword p_align; /* memory & file alignment */
} Elf64_Phdr;
/* Segment types - p_type */
#define PT_NULL 0 /* unused */
#define PT_LOAD 1 /* loadable segment */
#define PT_DYNAMIC 2 /* dynamic linking section */
#define PT_INTERP 3 /* the RTLD */
#define PT_NOTE 4 /* auxiliary information */
#define PT_SHLIB 5 /* reserved - purpose undefined */
#define PT_PHDR 6 /* program header */
#define PT_TLS 7 /* thread local storage */
#define PT_LOOS 0x60000000 /* reserved range for OS */
#define PT_HIOS 0x6fffffff /* specific segment types */
#define PT_LOPROC 0x70000000 /* reserved range for processor */
#define PT_HIPROC 0x7fffffff /* specific segment types */
#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */
#define PT_GANDR_KERNEL 0x67646b6c /* gdkl */
/* Segment flags - p_flags */
#define PF_X 0x1 /* Executable */
#define PF_W 0x2 /* Writable */
#define PF_R 0x4 /* Readable */
#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */
/* specific segment flags */
/* Dynamic structure */
typedef struct
{
Elf32_Sword d_tag; /* controls meaning of d_val */
union {
Elf32_Word d_val; /* Multiple meanings - see d_tag */
Elf32_Addr d_ptr; /* program virtual address */
} d_un;
} Elf32_Dyn;
typedef struct
{
Elf64_Xword d_tag; /* controls meaning of d_val */
union {
Elf64_Addr d_ptr;
Elf64_Xword d_val;
} d_un;
} Elf64_Dyn;
/* Dynamic Array Tags - d_tag */
#define DT_NULL 0 /* marks end of _DYNAMIC array */
#define DT_NEEDED 1 /* string table offset of needed lib */
#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */
#define DT_PLTGOT 3 /* address PLT/GOT */
#define DT_HASH 4 /* address of symbol hash table */
#define DT_STRTAB 5 /* address of string table */
#define DT_SYMTAB 6 /* address of symbol table */
#define DT_RELA 7 /* address of relocation table */
#define DT_RELASZ 8 /* size of relocation table */
#define DT_RELAENT 9 /* size of relocation entry */
#define DT_STRSZ 10 /* size of string table */
#define DT_SYMENT 11 /* size of symbol table entry */
#define DT_INIT 12 /* address of initialization func. */
#define DT_FINI 13 /* address of termination function */
#define DT_SONAME 14 /* string table offset of shared obj */
#define DT_RPATH 15 /* string table offset of library \
* search path */
#define DT_SYMBOLIC 16 /* start sym search in shared obj. */
#define DT_REL 17 /* address of rel. tbl. w addends */
#define DT_RELSZ 18 /* size of DT_REL relocation table */
#define DT_RELENT 19 /* size of DT_REL relocation entry */
#define DT_PLTREL 20 /* PLT referenced relocation entry */
#define DT_DEBUG 21 /* bugger */
#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */
#define DT_JMPREL 23 /* add. of PLT's relocation entries */
#define DT_BIND_NOW 24 /* Bind now regardless of env setting */
#define DT_LOOS 0x6000000d /* reserved range for OS */
#define DT_HIOS 0x6ffff000 /* specific dynamic array tags */
#define DT_LOPROC 0x70000000 /* reserved range for processor */
#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */
/* some other useful tags */
#define DT_RELACOUNT 0x6ffffff9 /* if present, number of RELATIVE */
#define DT_RELCOUNT 0x6ffffffa /* relocs, which must come first */
#define DT_FLAGS_1 0x6ffffffb
/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */
#define DF_1_NOW 0x00000001
#define DF_1_GLOBAL 0x00000002
#define DF_1_GROUP 0x00000004
#define DF_1_NODELETE 0x00000008
#define DF_1_LOADFLTR 0x00000010
#define DF_1_INITFIRST 0x00000020
#define DF_1_NOOPEN 0x00000040
#define DF_1_ORIGIN 0x00000080
#define DF_1_DIRECT 0x00000100
#define DF_1_TRANS 0x00000200
#define DF_1_INTERPOSE 0x00000400
#define DF_1_NODEFLIB 0x00000800
#define DF_1_NODUMP 0x00001000
#define DF_1_CONLFAT 0x00002000
/* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */
#define DT_NUM (DT_JMPREL + 1)
/*
* Note Definitions
*/
typedef struct
{
Elf32_Word namesz;
Elf32_Word descsz;
Elf32_Word type;
} Elf32_Note;
typedef struct
{
Elf64_Half namesz;
Elf64_Half descsz;
Elf64_Half type;
} Elf64_Note;
#if defined(ELFSIZE) && (ELFSIZE == 32)
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Phdr Elf32_Phdr
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Rel Elf32_Rel
#define Elf_RelA Elf32_Rela
#define Elf_Dyn Elf32_Dyn
#define Elf_Half Elf32_Half
#define Elf_Word Elf32_Word
#define Elf_Sword Elf32_Sword
#define Elf_Addr Elf32_Addr
#define Elf_Off Elf32_Off
#define Elf_Nhdr Elf32_Nhdr
#define Elf_Note Elf32_Note
#define ELF_R_SYM ELF32_R_SYM
#define ELF_R_TYPE ELF32_R_TYPE
#define ELF_R_INFO ELF32_R_INFO
#define ELFCLASS ELFCLASS32
#define ELF_ST_BIND ELF32_ST_BIND
#define ELF_ST_TYPE ELF32_ST_TYPE
#define ELF_ST_INFO ELF32_ST_INFO
#elif defined(ELFSIZE) && (ELFSIZE == 64)
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Phdr Elf64_Phdr
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Rel Elf64_Rel
#define Elf_RelA Elf64_Rela
#define Elf_Dyn Elf64_Dyn
#define Elf_Half Elf64_Half
#define Elf_Word Elf64_Word
#define Elf_Sword Elf64_Sword
#define Elf_Addr Elf64_Addr
#define Elf_Off Elf64_Off
#define Elf_Nhdr Elf64_Nhdr
#define Elf_Note Elf64_Note
#define ELF_R_SYM ELF64_R_SYM
#define ELF_R_TYPE ELF64_R_TYPE
#define ELF_R_INFO ELF64_R_INFO
#define ELFCLASS ELFCLASS64
#define ELF_ST_BIND ELF64_ST_BIND
#define ELF_ST_TYPE ELF64_ST_TYPE
#define ELF_ST_INFO ELF64_ST_INFO
#endif
#endif

View File

@ -0,0 +1,49 @@
/*
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ELFARCH_H
#define ELFARCH_H
#if defined(__i386__)
#define EM_THIS EM_386
#define EL_ARCH_USES_REL
#elif defined(__amd64__)
#define EM_THIS EM_AMD64
#define EL_ARCH_USES_RELA
#elif defined(__arm__)
#define EM_THIS EM_ARM
#define EL_ARCH_USES_REL
#elif defined(__aarch64__)
#define EM_THIS EM_AARCH64
#define EL_ARCH_USES_RELA
#define EL_ARCH_USES_REL
#else
#error specify your ELF architecture
#endif
#if defined(__LP64__) || defined(__LLP64__)
#define ELFSIZE 64
#else
#define ELFSIZE 32
#endif
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define ELFDATATHIS ELFDATA2LSB
#else
#define ELFDATATHIS ELFDATA2MSB
#endif
#endif

View File

@ -0,0 +1,329 @@
/*
* Copyright © 2018, M4xw
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include "elfload.h"
#pragma GCC push_options
#pragma GCC target ("thumb")
el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset)
{
return ctx->pread(ctx, def, nb, offset) ? EL_OK : EL_EIO;
}
#define EL_PHOFF(ctx, num) (((ctx)->ehdr.e_phoff + (num) *(ctx)->ehdr.e_phentsize))
el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i)
{
el_status rv = EL_OK;
for (; *i < ctx->ehdr.e_phnum; (*i)++)
{
if ((rv = el_pread(ctx, phdr, sizeof *phdr, EL_PHOFF(ctx, *i))))
return rv;
if (phdr->p_type == type)
{
return rv;
}
}
*i = -1;
return rv;
}
#define EL_SHOFF(ctx, num) (((ctx)->ehdr.e_shoff + (num) *(ctx)->ehdr.e_shentsize))
el_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, uint32_t type, unsigned *i)
{
el_status rv = EL_OK;
for (; *i < ctx->ehdr.e_shnum; (*i)++)
{
if ((rv = el_pread(ctx, shdr, sizeof *shdr, EL_SHOFF(ctx, *i))))
return rv;
if (shdr->sh_type == type)
{
return rv;
}
}
*i = -1;
return rv;
}
el_status el_init(el_ctx *ctx)
{
el_status rv = EL_OK;
if ((rv = el_pread(ctx, &ctx->ehdr, sizeof ctx->ehdr, 0)))
return rv;
/* validate header */
if (!IS_ELF(ctx->ehdr))
return EL_NOTELF;
if (ctx->ehdr.e_ident[EI_CLASS] != ELFCLASS)
return EL_WRONGBITS;
if (ctx->ehdr.e_ident[EI_DATA] != ELFDATATHIS)
return EL_WRONGENDIAN;
if (ctx->ehdr.e_ident[EI_VERSION] != EV_CURRENT)
return EL_NOTELF;
if (ctx->ehdr.e_type != ET_EXEC && ctx->ehdr.e_type != ET_DYN)
return EL_NOTEXEC;
if (ctx->ehdr.e_machine != EM_THIS)
return EL_WRONGARCH;
if (ctx->ehdr.e_version != EV_CURRENT)
return EL_NOTELF;
/* load phdrs */
Elf_Phdr ph;
/* iterate through, calculate extents */
ctx->base_load_paddr = ctx->base_load_vaddr = 0;
ctx->align = 1;
ctx->memsz = 0;
unsigned i = 0;
for (;;)
{
if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))
return rv;
if (i == (unsigned)-1)
break;
Elf_Addr phend = ph.p_vaddr + ph.p_memsz;
if (phend > ctx->memsz)
ctx->memsz = phend;
if (ph.p_align > ctx->align)
ctx->align = ph.p_align;
i++;
}
// Program Header
if (ctx->ehdr.e_type == ET_DYN)
{
i = 0;
if ((rv = el_findphdr(ctx, &ph, PT_DYNAMIC, &i)))
return rv;
if (i == (unsigned)-1)
return EL_NODYN;
ctx->dynoff = ph.p_offset;
ctx->dynsize = ph.p_filesz;
}
else
{
ctx->dynoff = 0;
ctx->dynsize = 0;
}
// Section String Table
if (ctx->ehdr.e_type == ET_DYN)
{
i = ctx->ehdr.e_shstrndx - 1;
if ((rv = el_findshdr(ctx, &ctx->shstr, SHT_STRTAB, &i)))
return rv;
// Reset
i = 0;
if ((rv = el_findshdr(ctx, &ctx->symtab, SHT_SYMTAB, &i)))
return rv;
if (i == (unsigned)-1)
return EL_NODYN;
}
return rv;
}
/*
typedef void* (*el_alloc_cb)(
el_ctx *ctx,
Elf_Addr phys,
Elf_Addr virt,
Elf_Addr size);
*/
el_status el_load(el_ctx *ctx, el_alloc_cb alloc)
{
el_status rv = EL_OK;
/* address deltas */
Elf_Addr pdelta = ctx->base_load_paddr;
Elf_Addr vdelta = ctx->base_load_vaddr;
/* iterate paddrs */
Elf_Phdr ph;
unsigned i = 0;
for (;;)
{
if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))
return rv;
if (i == (unsigned)-1)
break;
Elf_Addr pload = ph.p_paddr + pdelta;
Elf_Addr vload = ph.p_vaddr + vdelta;
/* allocate mem */
char *dest = alloc(ctx, pload, vload, ph.p_memsz);
if (!dest)
return EL_ENOMEM;
EL_DEBUG("Loading seg fileoff %x, vaddr %x to %p\n",
ph.p_offset, ph.p_vaddr, dest);
/* read loaded portion */
if ((rv = el_pread(ctx, dest, ph.p_filesz, ph.p_offset)))
return rv;
/* zero mem-only portion */
memset(dest + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz);
i++;
}
return rv;
}
el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t tag)
{
el_status rv = EL_OK;
size_t ndyn = ctx->dynsize / sizeof(Elf_Dyn);
for (unsigned i = 0; i < ndyn; i++)
{
if ((rv = el_pread(ctx, dyn, sizeof *dyn, ctx->dynoff + i * sizeof *dyn)))
return rv;
if (dyn->d_tag == tag)
return EL_OK;
}
dyn->d_tag = DT_NULL;
return EL_OK;
}
el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type)
{
el_status rv = EL_OK;
Elf_Dyn rel, relsz, relent;
if ((rv = el_finddyn(ctx, &rel, type)))
return rv;
if ((rv = el_finddyn(ctx, &relsz, type + 1)))
return rv;
if ((rv = el_finddyn(ctx, &relent, type + 2)))
return rv;
if (rel.d_tag == DT_NULL || relsz.d_tag == DT_NULL || relent.d_tag == DT_NULL)
{
ri->entrysize = 0;
ri->tablesize = 0;
ri->tableoff = 0;
}
else
{
ri->tableoff = rel.d_un.d_ptr;
ri->tablesize = relsz.d_un.d_val;
ri->entrysize = relent.d_un.d_val;
}
return rv;
}
extern el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel);
extern el_status el_applyrela(el_ctx *ctx, Elf_RelA *rela);
el_status el_relocate(el_ctx *ctx)
{
el_status rv = EL_OK;
// not dynamic
if (ctx->ehdr.e_type != ET_DYN)
return EL_OK;
char *base = (char *)ctx->base_load_paddr;
el_relocinfo ri;
#ifdef EL_ARCH_USES_REL
if ((rv = el_findrelocs(ctx, &ri, DT_REL)))
return rv;
if (ri.entrysize != sizeof(Elf_Rel) && ri.tablesize)
{
EL_DEBUG("Relocation size %u doesn't match expected %u\n",
ri.entrysize, sizeof(Elf_Rel));
return EL_BADREL;
}
size_t relcnt = ri.tablesize / sizeof(Elf_Rel);
Elf_Rel *reltab = (Elf_Rel *)(base + ri.tableoff);
for (size_t i = 0; i < relcnt; i++)
{
if ((rv = el_applyrel(ctx, &reltab[i])))
return rv;
}
#endif
#ifdef EL_ARCH_USES_RELA
if ((rv = el_findrelocs(ctx, &ri, DT_RELA)))
return rv;
if (ri.entrysize != sizeof(Elf_RelA) && ri.tablesize)
{
EL_DEBUG("Relocation size %u doesn't match expected %u\n",
ri.entrysize, sizeof(Elf_RelA));
return EL_BADREL;
}
size_t relacnt = ri.tablesize / sizeof(Elf_RelA);
Elf_RelA *relatab = (Elf_RelA *)(base + ri.tableoff);
for (size_t i = 0; i < relacnt; i++)
{
if ((rv = el_applyrela(ctx, &relatab[i])))
return rv;
}
#endif
#if !defined(EL_ARCH_USES_REL) && !defined(EL_ARCH_USES_RELA)
#error No relocation type defined!
#endif
return rv;
}
#pragma GCC pop_options

View File

@ -0,0 +1,127 @@
/*
* Copyright © 2018, M4xw
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ELFLOAD_H
#define ELFLOAD_H
#include <stddef.h>
#include "elfarch.h"
#include "elf.h"
#include "../../utils/types.h"
#ifdef DEBUG
#include "../../gfx/gfx.h"
#define EL_DEBUG(format, ...) \
gfx_printf(format __VA_OPT__(, ) __VA_ARGS__)
#else
#define EL_DEBUG(...) \
do \
{ \
} while (0)
#endif
typedef enum
{
EL_OK = 0,
EL_EIO,
EL_ENOMEM,
EL_NOTELF,
EL_WRONGBITS,
EL_WRONGENDIAN,
EL_WRONGARCH,
EL_WRONGOS,
EL_NOTEXEC,
EL_NODYN,
EL_BADREL,
} el_status;
typedef struct el_ctx
{
bool (*pread)(struct el_ctx *ctx, void *dest, size_t nb, size_t offset);
/* base_load_* -> address we are actually going to load at
*/
Elf_Addr
base_load_paddr,
base_load_vaddr;
/* size in memory of binary */
Elf_Addr memsz;
/* required alignment */
Elf_Addr align;
/* ELF header */
Elf_Ehdr ehdr;
// Section Header Str Table
Elf_Shdr shstr;
Elf_Shdr symtab;
/* Offset of dynamic table (0 if not ET_DYN) */
Elf_Off dynoff;
/* Size of dynamic table (0 if not ET_DYN) */
Elf_Addr dynsize;
} el_ctx;
el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset);
el_status el_init(el_ctx *ctx);
typedef void *(*el_alloc_cb)(
el_ctx *ctx,
Elf_Addr phys,
Elf_Addr virt,
Elf_Addr size);
el_status el_load(el_ctx *ctx, el_alloc_cb alloccb);
/* find the next phdr of type \p type, starting at \p *i.
* On success, returns EL_OK with *i set to the phdr number, and the phdr loaded
* in *phdr.
*
* If the end of the phdrs table was reached, *i is set to -1 and the contents
* of *phdr are undefined
*/
el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i);
/* Relocate the loaded executable */
el_status el_relocate(el_ctx *ctx);
/* find a dynamic table entry
* returns the entry on success, dyn->d_tag = DT_NULL on failure
*/
el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t type);
typedef struct
{
Elf_Off tableoff;
Elf_Addr tablesize;
Elf_Addr entrysize;
} el_relocinfo;
/* find all information regarding relocations of a specific type.
*
* pass DT_REL or DT_RELA for type
* sets ri->entrysize = 0 if not found
*/
el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type);
#endif

View File

@ -0,0 +1,84 @@
/*
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "elfload.h"
#if defined(__aarch64__)
#define R_AARCH64_NONE 0
#define R_AARCH64_RELATIVE 1027
el_status el_applyrela(el_ctx *ctx, Elf_RelA *rel)
{
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr);
uint32_t type = ELF_R_TYPE(rel->r_info);
uint32_t sym = ELF_R_SYM(rel->r_info);
switch (type)
{
case R_AARCH64_NONE:
EL_DEBUG("R_AARCH64_NONE\n");
break;
case R_AARCH64_RELATIVE:
if (sym)
{
EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n");
return EL_BADREL;
}
EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p);
*p = rel->r_addend + ctx->base_load_vaddr;
break;
default:
EL_DEBUG("Bad relocation %u\n", type);
return EL_BADREL;
}
return EL_OK;
}
el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel)
{
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr);
uint32_t type = ELF_R_TYPE(rel->r_info);
uint32_t sym = ELF_R_SYM(rel->r_info);
switch (type)
{
case R_AARCH64_NONE:
EL_DEBUG("R_AARCH64_NONE\n");
break;
case R_AARCH64_RELATIVE:
if (sym)
{
EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n");
return EL_BADREL;
}
EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p);
*p += ctx->base_load_vaddr;
break;
default:
EL_DEBUG("Bad relocation %u\n", type);
return EL_BADREL;
}
return EL_OK;
}
#endif

View File

@ -0,0 +1,66 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <m4x@m4xw.net> wrote this file. As long as you retain this notice you can do
* whatever you want with this stuff. If we meet some day, and you think this
* stuff is worth it, you can buy me a beer in return. M4xw
* ----------------------------------------------------------------------------
*/
#include "elfload.h"
#if defined(__arm__)
// Taken from http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf
#define R_ARM_NONE 0
#define R_ARM_ABS32 2
#define R_ARM_JUMP_SLOT 22
#define R_ARM_GLOB_DAT 21
#define R_ARM_RELATIVE 23
el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel)
{
uint32_t sym = ELF_R_SYM(rel->r_info); // Symbol offset
uint32_t type = ELF_R_TYPE(rel->r_info); // Relocation Type
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); // Target Addr
#if 0 // For later symbol usage
Elf32_Sym *elfSym;
const char *symbolName;
// We resolve relocs from the originating elf-image
elfSym = (Elf32_Sym *)(ctx->symtab.sh_offset + (char *)buffteg) + sym;
int strtab_offset = ctx->shstr.sh_offset;
char *strtab = (char *)buffteg + strtab_offset;
symbolName = strtab + elfSym->st_name;
//EL_DEBUG("Str: %s sz: %x val: %x\n", symbolName, elfSym->st_size, elfSym->st_value);
#endif
switch (type)
{
case R_ARM_NONE:
EL_DEBUG("R_ARM_NONE\n");
break;
case R_ARM_JUMP_SLOT:
case R_ARM_ABS32:
case R_ARM_GLOB_DAT:
// Stubbed for later purpose
//*p += elfSym->st_value; // + vaddr from sec
//*p |= 0; // 1 if Thumb && STT_FUNC, ignored for now
break;
case R_ARM_RELATIVE: // Needed for PIE
if (sym)
{
return EL_BADREL;
}
*p += ctx->base_load_vaddr;
break;
default:
return EL_BADREL;
}
return EL_OK;
}
#endif

View File

@ -0,0 +1,89 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include <string.h>
#include "diskio.h" /* FatFs lower layer API */
#include "../../storage/sdmmc.h"
#define SDMMC_UPPER_BUFFER 0xB8000000
#define DRAM_START 0x80000000
extern sdmmc_storage_t sd_storage;
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
return 0;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
return 0;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
if ((u32)buff >= DRAM_START)
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
{
memcpy(buff, buf, 512 * count);
return RES_OK;
}
return RES_ERROR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
if ((u32)buff >= DRAM_START)
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
memcpy(buf, buff, 512 * count);
if (sdmmc_storage_write(&sd_storage, sector, count, buf))
return RES_OK;
return RES_ERROR;
}
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
return RES_OK;
}

View File

@ -0,0 +1,79 @@
/*-----------------------------------------------------------------------/
/ Low level disk interface modlue include file (C)ChaN, 2014 /
/-----------------------------------------------------------------------*/
#ifndef _DISKIO_DEFINED
#define _DISKIO_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
#include "../../utils/types.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
#define CTRL_EJECT 7 /* Eject media */
#define CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status */
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number */
#ifdef __cplusplus
}
#endif
#endif

6866
nyx/nyx_gui/libs/fatfs/ff.c Normal file

File diff suppressed because it is too large Load Diff

391
nyx/nyx_gui/libs/fatfs/ff.h Normal file
View File

@ -0,0 +1,391 @@
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.13c /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2018, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
/ that the following condition is met:
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/
/----------------------------------------------------------------------------*/
#ifndef FF_DEFINED
#define FF_DEFINED 86604 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "../../utils/types.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */
#if FF_DEFINED != FFCONF_DEF
#error Wrong configuration file (ffconf.h).
#endif
/* Definitions of volume management */
#if FF_MULTI_PARTITION /* Multiple partition configuration */
typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#endif
#if FF_STR_VOLUME_ID
#ifndef FF_VOLUME_STRS
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
#endif
#endif
/* Type of path name strings on FatFs API */
#ifndef _INC_TCHAR
#define _INC_TCHAR
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */
typedef char TCHAR;
#define _T(x) u8 ## x
#define _TEXT(x) u8 ## x
#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */
typedef DWORD TCHAR;
#define _T(x) U ## x
#define _TEXT(x) U ## x
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3)
#error Wrong FF_LFN_UNICODE setting
#else /* ANSI/OEM code in SBCS/DBCS */
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#endif
#endif
/* Type of file size variables */
#if FF_FS_EXFAT
typedef QWORD FSIZE_t;
#else
typedef DWORD FSIZE_t;
#endif
/* Filesystem object structure (FATFS) */
typedef struct {
BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Associated physical drive */
BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
WORD id; /* Volume mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
WORD csize; /* Cluster size [sectors] */
#if FF_MAX_SS != FF_MIN_SS
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
#endif
#if FF_USE_LFN
WCHAR* lfnbuf; /* LFN working buffer */
#endif
#if FF_FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
#endif
#if FF_FS_REENTRANT
FF_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !FF_FS_READONLY
DWORD last_clst; /* Last allocated cluster */
DWORD free_clst; /* Number of free clusters */
#endif
#if FF_FS_RPATH
DWORD cdir; /* Current directory start cluster (0:root) */
#if FF_FS_EXFAT
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
#endif
#endif
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
DWORD fsize; /* Size of an FAT [sectors] */
DWORD volbase; /* Volume base sector */
DWORD fatbase; /* FAT base sector */
DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */
#if FF_FS_EXFAT
DWORD bitbase; /* Allocation bitmap base sector */
#endif
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS;
/* Object ID and allocation information (FFOBJID) */
typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */
BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if FF_FS_EXFAT
DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
#endif
#if FF_FS_LOCK
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif
} FFOBJID;
/* File object structure (FIL) */
typedef struct {
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
BYTE flag; /* File status flags */
BYTE err; /* Abort flag (error code) */
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
#if !FF_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
#endif
#if !FF_FS_TINY
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
#endif
#if FF_USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif
} FIL;
/* Directory object structure (DIR) */
typedef struct {
FFOBJID obj; /* Object identifier */
DWORD dptr; /* Current read/write offset */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector (0:Read operation has terminated) */
BYTE* dir; /* Pointer to the directory item in the win[] */
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
#if FF_USE_LFN
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
#endif
#if FF_USE_FIND
const TCHAR* pat; /* Pointer to the name matching pattern */
#endif
} DIR;
/* File information structure (FILINFO) */
typedef struct {
FSIZE_t fsize; /* File size */
WORD fdate; /* Modified date */
WORD ftime; /* Modified time */
BYTE fattrib; /* File attribute */
#if FF_USE_LFN
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
#else
TCHAR fname[12 + 1]; /* File name */
#endif
} FILINFO;
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* (0) Succeeded */
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
FR_INT_ERR, /* (2) Assertion failed */
FR_NOT_READY, /* (3) The physical drive cannot work */
FR_NO_FILE, /* (4) Could not find the file */
FR_NO_PATH, /* (5) Could not find the path */
FR_INVALID_NAME, /* (6) The path name format is invalid */
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
FR_EXIST, /* (8) Access denied due to prohibited access */
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
#ifdef FF_FASTFS
FR_INVALID_PARAMETER, /* (19) Given parameter is invalid */
FR_CLTBL_NO_INIT /* (20) The cluster table for fast seek/read/write was not created */
#else
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
#endif
} FRESULT;
/*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
#ifdef FF_FASTFS
FRESULT f_read_fast (FIL* fp, const void* buff, UINT btr); /* Fast read data from the file */
FRESULT f_write_fast (FIL* fp, const void* buff, UINT btw); /* Fast write data to the file */
#endif
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
FRESULT f_truncate (FIL* fp); /* Truncate the file */
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
FRESULT f_closedir (DIR* dp); /* Close an open directory */
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
#ifdef FF_FASTFS
DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, FSIZE_t ofs); /* Expand file and populate cluster table */
#endif
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
FRESULT f_setcp (WORD cp); /* Set current code page */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->obj.objsize)
#define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0)
#define f_rmdir(path) f_unlink(path)
#define f_unmount(path) f_mount(0, path, 0)
#ifndef EOF
#define EOF (-1)
#endif
/*--------------------------------------------------------------*/
/* Additional user defined functions */
/* RTC function */
#if !FF_FS_READONLY && !FF_FS_NORTC
DWORD get_fattime (void);
#endif
/* LFN support functions */
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
#endif
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
void* ff_memalloc (UINT msize); /* Allocate memory block */
void ff_memfree (void* mblock); /* Free memory block */
#endif
/* Sync functions */
#if FF_FS_REENTRANT
int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */
int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
#endif
/*--------------------------------------------------------------*/
/* Flags and offset address */
/* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ 0x01
#define FA_WRITE 0x02
#define FA_OPEN_EXISTING 0x00
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define FA_OPEN_APPEND 0x30
/* Fast seek controls (2nd argument of f_lseek) */
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
/* Format options (2nd argument of f_mkfs) */
#define FM_FAT 0x01
#define FM_FAT32 0x02
#define FM_EXFAT 0x04
#define FM_ANY 0x07
#define FM_SFD 0x08
/* Filesystem type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
#define FS_EXFAT 4
/* File attribute bits for directory entry (FILINFO.fattrib) */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#ifdef __cplusplus
}
#endif
#endif /* FF_DEFINED */

View File

@ -0,0 +1,293 @@
/*---------------------------------------------------------------------------/
/ FatFs Functional Configurations
/---------------------------------------------------------------------------*/
#define FFCONF_DEF 86604 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_READONLY 0
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ and optional writing functions as well. */
#define FF_FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions.
/
/ 0: Basic functions are fully enabled.
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
/ are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define FF_USE_STRFUNC 2
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
/
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define FF_USE_FIND 1
/* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
#define FF_USE_MKFS 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define FF_FASTFS 1
#ifdef FF_FASTFS
#define FF_USE_FASTSEEK 1
#else
#define FF_USE_FASTSEEK 0
#endif
/* This option switches fast seek function. (0:Disable or 1:Enable) */
#define FF_USE_EXPAND 0
/* This option switches f_expand function. (0:Disable or 1:Enable) */
#define FF_USE_CHMOD 1
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
#define FF_USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define FF_USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define FF_CODE_PAGE 850
/* This option specifies the OEM code page to be used on the target system.
/ Incorrect code page setting can cause a file open failure.
/
/ 437 - U.S.
/ 720 - Arabic
/ 737 - Greek
/ 771 - KBL
/ 775 - Baltic
/ 850 - Latin 1
/ 852 - Latin 2
/ 855 - Cyrillic
/ 857 - Turkish
/ 860 - Portuguese
/ 861 - Icelandic
/ 862 - Hebrew
/ 863 - Canadian French
/ 864 - Arabic
/ 865 - Nordic
/ 866 - Russian
/ 869 - Greek 2
/ 932 - Japanese (DBCS)
/ 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS)
/ 950 - Traditional Chinese (DBCS)
/ 0 - Include all code pages above and configured by f_setcp()
*/
#define FF_USE_LFN 3
#define FF_MAX_LFN 255
/* The FF_USE_LFN switches the support for LFN (long file name).
/
/ 0: Disable LFN. FF_MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
/ be in range of 12 to 255. It is recommended to be set 255 to fully support LFN
/ specification.
/ When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree() in ffsystem.c, need to be added to the project. */
#define FF_LFN_UNICODE 0
/* This option switches the character encoding on the API when LFN is enabled.
/
/ 0: ANSI/OEM in current CP (TCHAR = char)
/ 1: Unicode in UTF-16 (TCHAR = WCHAR)
/ 2: Unicode in UTF-8 (TCHAR = char)
/ 3: Unicode in UTF-32 (TCHAR = DWORD)
/
/ Also behavior of string I/O functions will be affected by this option.
/ When LFN is not enabled, this option has no effect. */
#define FF_LFN_BUF 255
#define FF_SFN_BUF 12
/* This set of options defines size of file name members in the FILINFO structure
/ which is used to read out directory items. These values should be suffcient for
/ the file names to read. The maximum possible length of the read file name depends
/ on character encoding. When LFN is not enabled, these options have no effect. */
#define FF_STRF_ENCODE 0
/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
/ f_putc(), f_puts and f_printf() convert the character encoding in it.
/ This option selects assumption of character encoding ON THE FILE to be
/ read/written via those functions.
/
/ 0: ANSI/OEM in current CP
/ 1: Unicode in UTF-16LE
/ 2: Unicode in UTF-16BE
/ 3: Unicode in UTF-8
*/
#define FF_FS_RPATH 0
/* This option configures support for relative path.
/
/ 0: Disable relative path and remove related functions.
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
/ 2: f_getcwd() function is available in addition to 1.
*/
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define FF_VOLUMES 1
/* Number of volumes (logical drives) to be used. (1-10) */
#define FF_STR_VOLUME_ID 0
#define FF_VOLUME_STRS "sd"
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
/ not defined, a user defined volume string table needs to be defined as:
/
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
*/
#define FF_MULTI_PARTITION 0
/* This option switches support for multiple volumes on the physical drive.
/ By default (0), each logical drive number is bound to the same physical drive
/ number and only an FAT volume found on the physical drive will be mounted.
/ When this function is enabled (1), each logical drive number can be bound to
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ funciton will be available. */
#define FF_MIN_SS 512
#define FF_MAX_SS 512
/* This set of options configures the range of sector size to be supported. (512,
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
/ harddisk. But a larger value may be required for on-board flash memory and some
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
/ for variable sector size mode and disk_ioctl() function needs to implement
/ GET_SECTOR_SIZE command. */
#define FF_USE_TRIM 0
/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
/ disk_ioctl() function. */
#define FF_FS_NOFSINFO 1
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/ bit0=0: Use free cluster count in the FSINFO if available.
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
/ Instead of private sector buffer eliminated from the file object, common sector
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
#define FF_FS_EXFAT 1
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
#define FF_FS_NORTC 1
#define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2019
/* The option FF_FS_NORTC switches timestamp function. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to read current time form real-time clock. FF_NORTC_MON,
/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
/ These options have no effect at read-only configuration (FF_FS_READONLY = 1). */
#define FF_FS_LOCK 0
/* The option FF_FS_LOCK switches file lock function to control duplicated file open
/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
/ is 1.
/
/ 0: Disable file lock function. To avoid volume corruption, application program
/ should avoid illegal open, remove and rename to the open objects.
/ >0: Enable file lock function. The value defines how many files/sub-directories
/ can be opened simultaneously under file lock control. Note that the file
/ lock control is independent of re-entrancy. */
/* #include <somertos.h> // O/S definitions */
#define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this function.
/
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ function, must be added to the project. Samples are available in
/ option/syscall.c.
/
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick.
/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */
/*--- End of configuration options ---*/

View File

@ -0,0 +1,39 @@
/*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */
/* (C) ChaN, 2018 */
/* (C) CTCaer, 2018 */
/*------------------------------------------------------------------------*/
#include "ff.h"
#include "../../mem/heap.h"
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
/*------------------------------------------------------------------------*/
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */
)
{
return malloc(msize); /* Allocate a new memory block with POSIX API */
}
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do if null) */
)
{
free(mblock); /* Free the memory block with POSIX API */
}
#endif

View File

@ -0,0 +1,632 @@
/*------------------------------------------------------------------------*/
/* Unicode handling functions for FatFs R0.13c */
/*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .const section when the /
/ FatFs is configured for LFN with DBCS. If the system has any Unicode /
/ utilitiy for the code conversion, this module should be modified to use /
/ that function to avoid silly memory consumption. /
/-------------------------------------------------------------------------*/
/*
/ Copyright (C) 2018, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
/ that the following condition is met:
/
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
*/
#include "ff.h"
#if FF_USE_LFN /* This module will be blanked at non-LFN configuration */
#if FF_DEFINED != 86604 /* Revision ID */
#error Wrong include file (ff.h).
#endif
#define MERGE2(a, b) a ## b
#define CVTBL(tbl, cp) MERGE2(tbl, cp)
#pragma GCC push_options
#pragma GCC target ("thumb")
/*------------------------------------------------------------------------*/
/* Code Conversion Tables */
/*------------------------------------------------------------------------*/
#if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0
static const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0
static const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */
0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0
static const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */
0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0
static const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0
static const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */
0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0
static const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0
static const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0
static const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0
static const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0
static const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,
0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0
static const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0
static const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0
static const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,
0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,
0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0
static const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */
0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,
0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,
0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,
0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F,
0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9,
0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1,
0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000
};
#endif
#if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0
static const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0
static const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
};
#endif
#if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0
static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,
0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3,
0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580,
0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384,
0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0
};
#endif
/*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for static code page configuration */
/* SBCS fixed code page */
/*------------------------------------------------------------------------*/
#if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900
WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
DWORD uni, /* UTF-16 encoded character to be converted */
WORD cp /* Code page for the conversion */
)
{
WCHAR c = 0;
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE);
if (uni < 0x80) { /* ASCII? */
c = (WCHAR)uni;
} else { /* Non-ASCII */
if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */
for (c = 0; c < 0x80 && uni != p[c]; c++) ;
c = (c + 0x80) & 0xFF;
}
}
return c;
}
WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
WCHAR oem, /* OEM code to be converted */
WORD cp /* Code page for the conversion */
)
{
WCHAR c = 0;
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE);
if (oem < 0x80) { /* ASCII? */
c = oem;
} else { /* Extended char */
if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */
if (oem < 0x100) c = p[oem - 0x80];
}
}
return c;
}
#endif
/*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for static code page configuration */
/* DBCS fixed code page */
/*------------------------------------------------------------------------*/
#if FF_CODE_PAGE >= 900
WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
DWORD uni, /* UTF-16 encoded character to be converted */
WORD cp /* Code page for the conversion */
)
{
const WCHAR *p;
WCHAR c = 0, uc;
UINT i = 0, n, li, hi;
if (uni < 0x80) { /* ASCII? */
c = (WCHAR)uni;
} else { /* Non-ASCII */
if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */
uc = (WCHAR)uni;
p = CVTBL(uni2oem, FF_CODE_PAGE);
hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1;
li = 0;
for (n = 16; n; n--) {
i = li + (hi - li) / 2;
if (uc == p[i * 2]) break;
if (uc > p[i * 2]) {
li = i;
} else {
hi = i;
}
}
if (n != 0) c = p[i * 2 + 1];
}
}
return c;
}
WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
WCHAR oem, /* OEM code to be converted */
WORD cp /* Code page for the conversion */
)
{
const WCHAR *p;
WCHAR c = 0;
UINT i = 0, n, li, hi;
if (oem < 0x80) { /* ASCII? */
c = oem;
} else { /* Extended char */
if (cp == FF_CODE_PAGE) { /* Is it valid code page? */
p = CVTBL(oem2uni, FF_CODE_PAGE);
hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1;
li = 0;
for (n = 16; n; n--) {
i = li + (hi - li) / 2;
if (oem == p[i * 2]) break;
if (oem > p[i * 2]) {
li = i;
} else {
hi = i;
}
}
if (n != 0) c = p[i * 2 + 1];
}
}
return c;
}
#endif
/*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for dynamic code page configuration */
/*------------------------------------------------------------------------*/
#if FF_CODE_PAGE == 0
static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0};
static const WCHAR* const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0};
WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
DWORD uni, /* UTF-16 encoded character to be converted */
WORD cp /* Code page for the conversion */
)
{
const WCHAR *p;
WCHAR c = 0, uc;
UINT i, n, li, hi;
if (uni < 0x80) { /* ASCII? */
c = (WCHAR)uni;
} else { /* Non-ASCII */
if (uni < 0x10000) { /* Is it in BMP? */
uc = (WCHAR)uni;
p = 0;
if (cp < 900) { /* SBCS */
for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get conversion table */
p = cp_table[i];
if (p) { /* Is it valid code page ? */
for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */
c = (c + 0x80) & 0xFF;
}
} else { /* DBCS */
switch (cp) { /* Get conversion table */
case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break;
case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break;
case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break;
case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break;
}
if (p) { /* Is it valid code page? */
li = 0;
for (n = 16; n; n--) { /* Find OEM code */
i = li + (hi - li) / 2;
if (uc == p[i * 2]) break;
if (uc > p[i * 2]) {
li = i;
} else {
hi = i;
}
}
if (n != 0) c = p[i * 2 + 1];
}
}
}
}
return c;
}
WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
WCHAR oem, /* OEM code to be converted (DBC if >=0x100) */
WORD cp /* Code page for the conversion */
)
{
const WCHAR *p;
WCHAR c = 0;
UINT i, n, li, hi;
if (oem < 0x80) { /* ASCII? */
c = oem;
} else { /* Extended char */
p = 0;
if (cp < 900) { /* SBCS */
for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */
p = cp_table[i];
if (p) { /* Is it a valid CP ? */
if (oem < 0x100) c = p[oem - 0x80];
}
} else { /* DBCS */
switch (cp) {
case 932 : p = oem2uni932; hi = sizeof oem2uni932 / 4 - 1; break;
case 936 : p = oem2uni936; hi = sizeof oem2uni936 / 4 - 1; break;
case 949 : p = oem2uni949; hi = sizeof oem2uni949 / 4 - 1; break;
case 950 : p = oem2uni950; hi = sizeof oem2uni950 / 4 - 1; break;
}
if (p) {
li = 0;
for (n = 16; n; n--) {
i = li + (hi - li) / 2;
if (oem == p[i * 2]) break;
if (oem > p[i * 2]) {
li = i;
} else {
hi = i;
}
}
if (n != 0) c = p[i * 2 + 1];
}
}
}
return c;
}
#endif
/*------------------------------------------------------------------------*/
/* Unicode up-case conversion */
/*------------------------------------------------------------------------*/
DWORD ff_wtoupper ( /* Returns up-converted code point */
DWORD uni /* Unicode code point to be up-converted */
)
{
const WORD *p;
WORD uc, bc, nc, cmd;
static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */
/* Basic Latin */
0x0061,0x031A,
/* Latin-1 Supplement */
0x00E0,0x0317,
0x00F8,0x0307,
0x00FF,0x0001,0x0178,
/* Latin Extended-A */
0x0100,0x0130,
0x0132,0x0106,
0x0139,0x0110,
0x014A,0x012E,
0x0179,0x0106,
/* Latin Extended-B */
0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA,
0x01CD,0x0110,
0x01DD,0x0001,0x018E,
0x01DE,0x0112,
0x01F3,0x0003,0x01F1,0x01F4,0x01F4,
0x01F8,0x0128,
0x0222,0x0112,
0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241,
0x0246,0x010A,
/* IPA Extensions */
0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7,
/* Greek, Coptic */
0x037B,0x0003,0x03FD,0x03FE,0x03FF,
0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A,
0x03B1,0x0311,
0x03C2,0x0002,0x03A3,0x03A3,
0x03C4,0x0308,
0x03CC,0x0003,0x038C,0x038E,0x038F,
0x03D8,0x0118,
0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA,
/* Cyrillic */
0x0430,0x0320,
0x0450,0x0710,
0x0460,0x0122,
0x048A,0x0136,
0x04C1,0x010E,
0x04CF,0x0001,0x04C0,
0x04D0,0x0144,
/* Armenian */
0x0561,0x0426,
0x0000 /* EOT */
};
static const WORD cvt2[] = { /* Compressed up conversion table for U+1000 - U+FFFF */
/* Phonetic Extensions */
0x1D7D,0x0001,0x2C63,
/* Latin Extended Additional */
0x1E00,0x0196,
0x1EA0,0x015A,
/* Greek Extended */
0x1F00,0x0608,
0x1F10,0x0606,
0x1F20,0x0608,
0x1F30,0x0608,
0x1F40,0x0606,
0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F,
0x1F60,0x0608,
0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB,
0x1F80,0x0608,
0x1F90,0x0608,
0x1FA0,0x0608,
0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC,
0x1FCC,0x0001,0x1FC3,
0x1FD0,0x0602,
0x1FE0,0x0602,
0x1FE5,0x0001,0x1FEC,
0x1FF3,0x0001,0x1FFC,
/* Letterlike Symbols */
0x214E,0x0001,0x2132,
/* Number forms */
0x2170,0x0210,
0x2184,0x0001,0x2183,
/* Enclosed Alphanumerics */
0x24D0,0x051A,
0x2C30,0x042F,
/* Latin Extended-C */
0x2C60,0x0102,
0x2C67,0x0106, 0x2C75,0x0102,
/* Coptic */
0x2C80,0x0164,
/* Georgian Supplement */
0x2D00,0x0826,
/* Full-width */
0xFF41,0x031A,
0x0000 /* EOT */
};
if (uni < 0x10000) { /* Is it in BMP? */
uc = (WORD)uni;
p = uc < 0x1000 ? cvt1 : cvt2;
for (;;) {
bc = *p++; /* Get the block base */
if (bc == 0 || uc < bc) break; /* Not matched? */
nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */
if (uc < bc + nc) { /* In the block? */
switch (cmd) {
case 0: uc = p[uc - bc]; break; /* Table conversion */
case 1: uc -= (uc - bc) & 1; break; /* Case pairs */
case 2: uc -= 16; break; /* Shift -16 */
case 3: uc -= 32; break; /* Shift -32 */
case 4: uc -= 48; break; /* Shift -48 */
case 5: uc -= 26; break; /* Shift -26 */
case 6: uc += 8; break; /* Shift +8 */
case 7: uc -= 80; break; /* Shift -80 */
case 8: uc -= 0x1C60; break; /* Shift -0x1C60 */
}
break;
}
if (cmd == 0) p += nc; /* Skip table if needed */
}
uni = uc;
}
return uni;
}
#pragma GCC pop_options
#endif /* #if FF_USE_LFN */

376
nyx/nyx_gui/libs/lv_conf.h Normal file
View File

@ -0,0 +1,376 @@
/*
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LV_CONF_H
#define LV_CONF_H
#include "../utils/types.h"
/*===================
Dynamic memory
*===================*/
/* Memory size which will be used by the library
* to store the graphical objects and other data */
#define LV_MEM_CUSTOM 0 /*1: use custom malloc/free, 0: use the built-in lv_mem_alloc/lv_mem_free*/
#if LV_MEM_CUSTOM == 0
# define LV_MEM_SIZE (0x38000U * 1024U) /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/
# define LV_MEM_ATTR /*Complier prefix for big array declaration*/
# define LV_MEM_ADR 0xF1000000 /*Set an address for memory pool instead of allocation it as an array. Can be in external SRAM too.*/
# define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/
#else /*LV_MEM_CUSTOM*/
# define LV_MEM_CUSTOM_INCLUDE "../../../mem/heap.h" /*Header for the dynamic memory function*/
# define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/
# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/
#endif /*LV_MEM_CUSTOM*/
/* Garbage Collector settings
* Used if lvgl is binded to higher language and the memory is managed by that language */
#define LV_ENABLE_GC 0
#if LV_ENABLE_GC != 0
# define LV_MEM_CUSTOM_REALLOC your_realloc /*Wrapper to realloc*/
# define LV_MEM_CUSTOM_GET_SIZE your_mem_get_size /*Wrapper to lv_mem_get_size*/
# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/
#endif /* LV_ENABLE_GC */
/*===================
Graphical settings
*===================*/
/* Horizontal and vertical resolution of the library.*/
#define LV_HOR_RES (1280)
#define LV_VER_RES (720)
/* Dot Per Inch: used to initialize default sizes. E.g. a button with width = LV_DPI / 2 -> half inch wide
* (Not so important, you can adjust it to modify default sizes and spaces)*/
#define LV_DPI 100
/* Enable anti-aliasing (lines, and radiuses will be smoothed) */
#define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/
/*Screen refresh period in milliseconds*/
#define LV_REFR_PERIOD 33
/*-----------------
* VDB settings
*----------------*/
/* VDB (Virtual Display Buffer) is an internal graphics buffer.
* The GUI will be drawn into this buffer first and then
* the buffer will be passed to your `disp_drv.disp_flush` function to
* copy it to your frame buffer.
* VDB is required for: buffered drawing, opacity, anti-aliasing and shadows
* Learn more: https://docs.littlevgl.com/#Drawing*/
/* Size of the VDB in pixels. Typical size: ~1/10 screen. Must be >= LV_HOR_RES
* Setting it to 0 will disable VDB and `disp_drv.disp_fill` and `disp_drv.disp_map` functions
* will be called to draw to the frame buffer directly*/
#define LV_VDB_SIZE (LV_VER_RES * LV_HOR_RES)
/* Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays.
* Special formats are handled with `disp_drv.vdb_wr`)*/
#define LV_VDB_PX_BPP LV_COLOR_SIZE /*LV_COLOR_SIZE comes from LV_COLOR_DEPTH below to set 8, 16 or 32 bit pixel size automatically */
/* Place VDB to a specific address (e.g. in external RAM)
* 0: allocate automatically into RAM
* LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/
#define LV_VDB_ADR 0xF0000000
/* Use two Virtual Display buffers (VDB) to parallelize rendering and flushing
* The flushing should use DMA to write the frame buffer in the background */
#define LV_VDB_DOUBLE 0
/* Place VDB2 to a specific address (e.g. in external RAM)
* 0: allocate automatically into RAM
* LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/
#define LV_VDB2_ADR 0
/* Using true double buffering in `disp_drv.disp_flush` you will always get the image of the whole screen.
* Your only task is to set the rendered image (`color_p` parameter) as frame buffer address or send it to your display.
* The best if you do in the blank period of you display to avoid tearing effect.
* Requires:
* - LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES
* - LV_VDB_DOUBLE = 1
*/
#define LV_VDB_TRUE_DOUBLE_BUFFERED 0
/*=================
Misc. setting
*=================*/
/*Input device settings*/
#define LV_INDEV_READ_PERIOD 33 /*Input device read period in milliseconds*/
#define LV_INDEV_POINT_MARKER 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/
#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */
#define LV_INDEV_DRAG_THROW 20 /*Drag throw slow-down in [%]. Greater value means faster slow-down */
#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/
#define LV_INDEV_LONG_PRESS_REP_TIME 1000 //Fix keyb /*Repeated trigger period in long press [ms] */
/*Color settings*/
#define LV_COLOR_DEPTH 32 /*Color depth: 1/8/16/32*/
#define LV_COLOR_16_SWAP 0 /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/
#define LV_COLOR_SCREEN_TRANSP 0 /*1: Enable screen transparency. Useful for OSD or other overlapping GUIs. Requires ARGB8888 colors*/
#define LV_COLOR_TRANSP LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma keying)*/
/*Text settings*/
#define LV_TXT_UTF8 0 /*Enable UTF-8 coded Unicode character usage */
#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/
#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */
/*Feature usage*/
#define USE_LV_ANIMATION 1 /*1: Enable all animations*/
#define USE_LV_SHADOW 1 /*1: Enable shadows*/
#define USE_LV_GROUP 0 /*1: Enable object groups (for keyboards)*/
#define USE_LV_GPU 0 /*1: Enable GPU interface*/
#define USE_LV_REAL_DRAW 0 /*1: Enable function which draw directly to the frame buffer instead of VDB (required if LV_VDB_SIZE = 0)*/
#define USE_LV_FILESYSTEM 0 /*1: Enable file system (might be required for images*/
#define USE_LV_MULTI_LANG 0 /* Number of languages for labels to store (0: to disable this feature)*/
/*Compiler settings*/
#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to `lv_tick_inc` function */
#define LV_ATTRIBUTE_TASK_HANDLER /* Define a custom attribute to `lv_task_handler` function */
#define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/
#define LV_COMPILER_NON_CONST_INIT_SUPPORTED 1 /* 1: Initialization with non constant values are supported */
/*HAL settings*/
#define LV_TICK_CUSTOM 1 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */
#if LV_TICK_CUSTOM == 1
#define LV_TICK_CUSTOM_INCLUDE "../../../utils/util.h" /*Header for the sys time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (get_tmr_ms()) /*Expression evaluating to current systime in ms*/
#endif /*LV_TICK_CUSTOM*/
/*Log settings*/
#define USE_LV_LOG 0 /*Enable/disable the log module*/
#if USE_LV_LOG
/* How important log should be added:
* LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
* LV_LOG_LEVEL_INFO Log important events
* LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't caused problem
* LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
*/
# define LV_LOG_LEVEL LV_LOG_LEVEL_TRACE
/* 1: Print the log with 'printf'; 0: user need to register a callback*/
# define LV_LOG_PRINTF 1
#endif /*USE_LV_LOG*/
/*================
* THEME USAGE
*================*/
#define LV_THEME_LIVE_UPDATE 0 /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/
#define USE_LV_THEME_HEKATE 1 /*Flat theme with bold colors and light shadows*/
/*==================
* FONT USAGE
*===================*/
/* More info about fonts: https://docs.littlevgl.com/#Fonts
* To enable a built-in font use 1,2,4 or 8 values
* which will determine the bit-per-pixel. Higher value means smoother fonts */
#define LV_FONT_QUALITY 8
#define USE_UBUNTU_MONO LV_FONT_QUALITY
#define USE_INTERUI_20 LV_FONT_QUALITY
#define USE_INTERUI_30 LV_FONT_QUALITY
#define USE_HEKATE_SYMBOL_20 USE_INTERUI_20
#define USE_HEKATE_SYMBOL_30 USE_INTERUI_30
#define USE_HEKATE_SYMBOL_120 LV_FONT_QUALITY
/* Optionally declare your custom fonts here.
* You can use these fonts as default font too
* and they will be available globally. E.g.
* #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \
* LV_FONT_DECLARE(my_font_2) \
*/
#define LV_FONT_CUSTOM_DECLARE
#define LV_FONT_DEFAULT &interui_30 /*Always set a default font from the built-in fonts*/
/*===================
* LV_OBJ SETTINGS
*==================*/
#define LV_OBJ_FREE_NUM_TYPE uint32_t /*Type of free number attribute (comment out disable free number)*/
#define LV_OBJ_FREE_PTR 1 /*Enable the free pointer attribute*/
#define LV_OBJ_REALIGN 1 // 0 in OG gui /*Enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/
/*==================
* LV OBJ X USAGE
*================*/
/*
* Documentation of the object types: https://docs.littlevgl.com/#Object-types
*/
/*****************
* Simple object
*****************/
/*Label (dependencies: -*/
#define USE_LV_LABEL 1
#if USE_LV_LABEL != 0
# define LV_LABEL_SCROLL_SPEED 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/
#endif
/*Image (dependencies: lv_label*/
#define USE_LV_IMG 1
#if USE_LV_IMG != 0
# define LV_IMG_CF_INDEXED 0 /*Enable indexed (palette) images*/
# define LV_IMG_CF_ALPHA 1 /*Enable alpha indexed images*/
#endif
/*Line (dependencies: -*/
#define USE_LV_LINE 1
/*Arc (dependencies: -)*/
#define USE_LV_ARC 0
/*******************
* Container objects
*******************/
/*Container (dependencies: -*/
#define USE_LV_CONT 1
/*Page (dependencies: lv_cont)*/
#define USE_LV_PAGE 1
/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/
#define USE_LV_WIN 1
/*Tab (dependencies: lv_page, lv_btnm)*/
#define USE_LV_TABVIEW 1
# if USE_LV_TABVIEW != 0
# define LV_TABVIEW_ANIM_TIME 0 /*Time of slide animation [ms] (0: no animation)*/
#endif
/*Tileview (dependencies: lv_page) */
#define USE_LV_TILEVIEW 0
#if USE_LV_TILEVIEW
# define LV_TILEVIEW_ANIM_TIME 0 /*Time of slide animation [ms] (0: no animation)*/
#endif
/*************************
* Data visualizer objects
*************************/
/*Bar (dependencies: -)*/
#define USE_LV_BAR 1
/*Line meter (dependencies: *;)*/
#define USE_LV_LMETER 0
/*Gauge (dependencies:lv_bar, lv_lmeter)*/
#define USE_LV_GAUGE 0
/*Chart (dependencies: -)*/
#define USE_LV_CHART 0
/*Table (dependencies: lv_label)*/
#define USE_LV_TABLE 1
#if USE_LV_TABLE
# define LV_TABLE_COL_MAX 12
#endif
/*LED (dependencies: -)*/
#define USE_LV_LED 0
/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/
#define USE_LV_MBOX 1
/*Text area (dependencies: lv_label, lv_page)*/
#define USE_LV_TA 1
#if USE_LV_TA != 0
# define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/
# define LV_TA_PWD_SHOW_TIME 1500 /*ms*/
#endif
/*Spinbox (dependencies: lv_ta)*/
#define USE_LV_SPINBOX 0
/*Calendar (dependencies: -)*/
#define USE_LV_CALENDAR 0
/*Preload (dependencies: lv_arc)*/
#define USE_LV_PRELOAD 0
#if USE_LV_PRELOAD != 0
# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/
# define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/
# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC
#endif
/*Canvas (dependencies: lv_img)*/
#define USE_LV_CANVAS 0
/*************************
* User input objects
*************************/
/*Button (dependencies: lv_cont*/
#define USE_LV_BTN 1
#if USE_LV_BTN != 0
# define LV_BTN_INK_EFFECT 0 /*Enable button-state animations - draw a circle on click (dependencies: USE_LV_ANIMATION)*/
#endif
/*Image Button (dependencies: lv_btn*/
#define USE_LV_IMGBTN 1
#if USE_LV_IMGBTN
# define LV_IMGBTN_TILED 0 /*1: The imgbtn requires left, mid and right parts and the width can be set freely*/
#endif
/*Button matrix (dependencies: -)*/
#define USE_LV_BTNM 1
/*Keyboard (dependencies: lv_btnm)*/
#define USE_LV_KB 0
/*Check box (dependencies: lv_btn, lv_label)*/
#define USE_LV_CB 1
/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/
#define USE_LV_LIST 1
#if USE_LV_LIST != 0
# define LV_LIST_FOCUS_TIME 100 /*Default animation time of focusing to a list element [ms] (0: no animation) */
#endif
/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/
#define USE_LV_DDLIST 1
#if USE_LV_DDLIST != 0
# define LV_DDLIST_ANIM_TIME 100 /*Open and close default animation time [ms] (0: no animation)*/
#endif
/*Roller (dependencies: lv_ddlist)*/
#define USE_LV_ROLLER 1
#if USE_LV_ROLLER != 0
# define LV_ROLLER_ANIM_TIME 200 /*Focus animation time [ms] (0: no animation)*/
#endif
/*Slider (dependencies: lv_bar)*/
#define USE_LV_SLIDER 1
/*Switch (dependencies: lv_slider)*/
#define USE_LV_SW 1
/*************************
* Non-user section
*************************/
#ifdef _MSC_VER /* Disable warnings for Visual Studio*/
#define _CRT_SECURE_NO_WARNINGS
#endif
#endif /*LV_CONF_H*/

View File

@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [atom@github.com](mailto:atom@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@ -0,0 +1,103 @@
# Contributing to Littlev Graphics Library
**Welcome! It's glad to see that you are interested in contributing to LittlevGL! There are several types of task where you can help to build a better library! Let's see how to get started!**
There are many different possibilities to join the community. If you have some time to work with us I'm sure you will find something that fits you! You can:
- answer other's questions
- report and/or fix bugs
- suggest and/or implement new features
- improve and/or translate the documentation
- write a blog post about your experiences
But first, start with the most Frequently Asked Questions.
## FAQ about contributing
### What license does my code need to be under?
Any code added to LittlevGL must be licensed under [MIT](https://choosealicense.com/licenses/mit/) or another license that is fully compatible. Contributions under other licenses are highly likely to be rejected.
If you borrow code from another project, please make sure to add their copyright notice to your contribution.
### Where do I ask questions, give feedback, or report bugs?
We use the [forum](http://forum.littlevgl.com/) for questions, feature suggestions, and discussions.
We use [GitHub's issue tracker](https://github.com/littlevgl/lvgl/issues) to report bugs.
For both of these there are some rules:
- Be kind and friendly.
- Speak about one thing in one issue.
- Give feedback and close the issue if your question is answered.
- Explain exactly what you experience or expect. _"The button is not working"_ is not enough info to get help.
- For most issues you should send an absolute minimal code example in order to reproduce the issue. Ideally this should be easily usable in the PC simulator.
- Use [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) to format your post.
- If you don't get any answer in a week write a comment like "Can somebody help?". Maybe your issue wasn't noticed.
### How can I send fixes and improvements?
Merging new code happens via Pull Requests. If you are still not familiar with the Pull Requests (PR for short) here is a quick guide about them:
1. **Fork** the [lvgl repository](https://github.com/littlevgl/lvgl). To do this click the "Fork" button in the top right corner. It will "copy" the `lvgl` repository to your GitHub account (`https://github.com/your_name?tab=repositories`)
2. **Clone** the forked repository and add your updates
3. **Create a PR** on the GitHub on the page of you `lvgl` repository(`https://github.com/your_name/lvgl`) by hitting the "New pull request" button
4. **Set the base branch**. It means where you want to merge your update. Bugfixes for the last release go to `master`, new features to the actual `dev-x.y` branch.
5. **Describe** what is in the update. An example code is welcome if applicable.
Some advice:
- If you are not sure about your fix or feature it's better to open an issue first, and discuss the details there.
- Maybe your fix or update won't be perfect at first. Don't be afraid, just improve it and push the new commits. The PR will be updated accordingly.
- If your update needs some extra work it's okay to say: _"I'm busy now and I will improve it soon"_ or _"Sorry, I don't have time to improve it, I hope it helps in this form too"_. So it's better to say don't have time to continue then saying nothing.
- Please read and follow this [guide about the coding style](https://docs.littlevgl.com/#Coding-Style-Guide)
### Where is the documentation?
You can read the documentation here: https://docs.littlevgl.com/
You can edit the documentation here: https://github.com/littlevgl/doc
### Where is the blog?
You can read the blog here: https://blog.littlevgl.com/
You can edit the blog here: https://github.com/littlevgl/blog
## So how and where can I contribute?
### Answering other's questions
It's a great way to contribute to the library if you already use it. Just go the [issue tracker](https://github.com/littlevgl/lvgl/issues), read the titles and if you are already familiar with a topic, don't be shy, and write your suggestion.
### Reporting and/or fixing bugs
For simple bugfixes (typos, missing error handling, fixing a warning) is fine to send a Pull request directly. However, for more complex bugs it's better to open an issue first. In the issue, you should describe how to reproduce the bug and even add the minimal code snippet.
### Suggesting and/or implementing new features
If you have a good idea don't hesitate to share with us. It's even better if you have time to deal with its implementation. Don't be afraid if you still don't know LittlevGL well enough. We will help you to get started.
During the implementation don't forget the [Code style guide](https://docs.littlevgl.com/#Coding-Style-Guide).
### Improving and/or translating the documentation
The documentation of LittlevGL is written in Markdown and available [here](https://github.com/littlevgl/doc) for editing. If you find some parts of the documentation obscure or insufficient just search the related `.md` file, hit the edit icon and add your updates. This way a new Pull request will be generated automatically.
If you can devote more time to improve the documentation you can translate it!
1. Just copy the English `.md` files from the root folder to `locale/LANGUAGE_CODE` (language code is e.g. DE, FR, ES etc)
2. Append the language code the end of files (e.g. Welcome_fr.md)
3. Update the filenames in `_Sidebar.md`
4. Translate the page(s) you want
5. Create a Pull request
### Writing a blog post about your experiences
Have ported LittlevGL to a new platform? Have you created a fancy GUI? Do you know a great trick?
You can share your knowledge on LittelvGL's blog! It's super easy to add your own post:
- Fork and clone the [blog repository](https://github.com/littlevgl/blog)
- Add your post in Markdown to the `_posts` folder.
- Store the images and other resources in a dedicated folder in `assets`
- Create a Pull Request
The blog uses [Jekyll](https://jekyllrb.com/) to convert the `.md` files to a webpage. You can easily [run Jekyll offline](https://jekyllrb.com/docs/) to check your post before creating the Pull request
## Summary
I hope you have taken a liking to contribute to LittelvGL. A helpful and friendly community is waiting for you! :)

View File

@ -0,0 +1 @@
--style=kr --convert-tabs --indent=spaces=4 --indent-switches --pad-oper --unpad-paren --align-pointer=middle --suffix=.bak --lineend=linux --min-conditional-indent=

View File

@ -0,0 +1 @@
--convert-tabs --indent=spaces=4

View File

@ -0,0 +1,8 @@
MIT licence
Copyright (c) 2016 Gábor Kiss-Vámosi
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,12 @@
CSRCS += lv_group.c
CSRCS += lv_indev.c
CSRCS += lv_obj.c
CSRCS += lv_refr.c
CSRCS += lv_style.c
CSRCS += lv_vdb.c
CSRCS += lv_lang.c
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_core
VPATH += :$(LVGL_DIR)/lvgl/lv_core
CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_core"

View File

@ -0,0 +1,554 @@
/**
* @file lv_group.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_group.h"
#if USE_LV_GROUP != 0
#include <stddef.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void style_mod_def(lv_style_t * style);
static void style_mod_edit_def(lv_style_t * style);
static void lv_group_refocus(lv_group_t *g);
static void obj_to_foreground(lv_obj_t * obj);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Create a new object group
* @return pointer to the new object group
*/
lv_group_t * lv_group_create(void)
{
lv_group_t * group = lv_mem_alloc(sizeof(lv_group_t));
lv_mem_assert(group);
if(group == NULL) return NULL;
lv_ll_init(&group->obj_ll, sizeof(lv_obj_t *));
group->style_mod = style_mod_def;
group->style_mod_edit = style_mod_edit_def;
group->obj_focus = NULL;
group->frozen = 0;
group->focus_cb = NULL;
group->click_focus = 1;
group->editing = 0;
return group;
}
/**
* Delete a group object
* @param group pointer to a group
*/
void lv_group_del(lv_group_t * group)
{
/*Defocus the the currently focused object*/
if(group->obj_focus != NULL) {
(*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
lv_obj_invalidate(*group->obj_focus);
}
/*Remove the objects from the group*/
lv_obj_t ** obj;
LL_READ(group->obj_ll, obj) {
(*obj)->group_p = NULL;
}
lv_ll_clear(&(group->obj_ll));
lv_mem_free(group);
}
/**
* Add an object to a group
* @param group pointer to a group
* @param obj pointer to an object to add
*/
void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj)
{
if(group == NULL) return;
/*If the object is already in a group and focused then defocus it*/
if(obj->group_p) {
if(lv_obj_is_focused(obj)) {
lv_group_refocus(obj->group_p);
LV_LOG_INFO("group: assign object to an other group");
}
}
obj->group_p = group;
lv_obj_t ** next = lv_ll_ins_tail(&group->obj_ll);
lv_mem_assert(next);
if(next == NULL) return;
*next = obj;
/* If the head and the tail is equal then there is only one object in the linked list.
* In this case automatically activate it*/
if(lv_ll_get_head(&group->obj_ll) == next) {
lv_group_refocus(group);
}
}
/**
* Remove an object from its group
* @param obj pointer to an object to remove
*/
void lv_group_remove_obj(lv_obj_t * obj)
{
lv_group_t * g = obj->group_p;
if(g == NULL) return;
if(g->obj_focus == NULL) return; /*Just to be sure (Not possible if there is at least one object in the group)*/
/*Focus on the next object*/
if(*g->obj_focus == obj) {
/*If this is the only object in the group then focus to nothing.*/
if(lv_ll_get_head(&g->obj_ll) == g->obj_focus && lv_ll_get_tail(&g->obj_ll) == g->obj_focus) {
(*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
}
/*If there more objects in the group then focus to the next/prev object*/
else {
lv_group_refocus(g);
}
}
/* If the focuses object is still the same then it was the only object in the group but it will be deleted.
* Set the `obj_focus` to NULL to get back to the initial state of the group with zero objects*/
if(*g->obj_focus == obj) {
g->obj_focus = NULL;
}
/*Search the object and remove it from its group */
lv_obj_t ** i;
LL_READ(g->obj_ll, i) {
if(*i == obj) {
lv_ll_rem(&g->obj_ll, i);
lv_mem_free(i);
obj->group_p = NULL;
break;
}
}
}
/**
* Focus on an object (defocus the current)
* @param obj pointer to an object to focus on
*/
void lv_group_focus_obj(lv_obj_t * obj)
{
lv_group_t * g = obj->group_p;
if(g == NULL) return;
if(g->frozen != 0) return;
/*On defocus edit mode must be leaved*/
lv_group_set_editing(g, false);
lv_obj_t ** i;
LL_READ(g->obj_ll, i) {
if(*i == obj) {
if(g->obj_focus == i) return; /*Don't focus the already focused object again*/
if(g->obj_focus != NULL) {
(*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
lv_obj_invalidate(*g->obj_focus);
}
g->obj_focus = i;
if(g->obj_focus != NULL) {
(*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_FOCUS, NULL);
if(g->focus_cb) g->focus_cb(g);
lv_obj_invalidate(*g->obj_focus);
/*If the object or its parent has `top == true` bring it to the foregorund*/
obj_to_foreground(*g->obj_focus);
}
break;
}
}
}
/**
* Focus the next object in a group (defocus the current)
* @param group pointer to a group
*/
void lv_group_focus_next(lv_group_t * group)
{
if(group->frozen) return;
if(group->obj_focus) {
(*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
lv_obj_invalidate(*group->obj_focus);
}
lv_obj_t ** obj_next;
if(group->obj_focus == NULL) obj_next = lv_ll_get_head(&group->obj_ll);
else obj_next = lv_ll_get_next(&group->obj_ll, group->obj_focus);
if(obj_next == NULL) {
if(group->wrap) obj_next = lv_ll_get_head(&group->obj_ll);
else obj_next = lv_ll_get_tail(&group->obj_ll);
}
group->obj_focus = obj_next;
if(group->obj_focus) {
(*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_FOCUS, NULL);
lv_obj_invalidate(*group->obj_focus);
if(group->focus_cb) group->focus_cb(group);
/*If the object or its parent has `top == true` bring it to the foregorund*/
obj_to_foreground(*group->obj_focus);
}
}
/**
* Focus the previous object in a group (defocus the current)
* @param group pointer to a group
*/
void lv_group_focus_prev(lv_group_t * group)
{
if(group->frozen) return;
if(group->obj_focus) {
(*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
lv_obj_invalidate(*group->obj_focus);
}
lv_obj_t ** obj_next;
if(group->obj_focus == NULL) obj_next = lv_ll_get_tail(&group->obj_ll);
else obj_next = lv_ll_get_prev(&group->obj_ll, group->obj_focus);
if(obj_next == NULL) {
if(group->wrap) obj_next = lv_ll_get_tail(&group->obj_ll);
else obj_next = lv_ll_get_head(&group->obj_ll);
}
group->obj_focus = obj_next;
if(group->obj_focus != NULL) {
(*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_FOCUS, NULL);
lv_obj_invalidate(*group->obj_focus);
if(group->focus_cb) group->focus_cb(group);
/*If the object or its parent has `top == true` bring it to the foregorund*/
obj_to_foreground(*group->obj_focus);
}
}
/**
* Do not let to change the focus from the current object
* @param group pointer to a group
* @param en true: freeze, false: release freezing (normal mode)
*/
void lv_group_focus_freeze(lv_group_t * group, bool en)
{
if(en == false) group->frozen = 0;
else group->frozen = 1;
}
/**
* Send a control character to the focuses object of a group
* @param group pointer to a group
* @param c a character (use LV_GROUP_KEY_.. to navigate)
* @return result of focused object in group.
*/
lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c)
{
lv_obj_t * act = lv_group_get_focused(group);
if(act == NULL) return LV_RES_OK;
return act->signal_func(act, LV_SIGNAL_CONTROLL, &c);
}
/**
* Set a function for a group which will modify the object's style if it is in focus
* @param group pointer to a group
* @param style_mod_func the style modifier function pointer
*/
void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func)
{
group->style_mod = style_mod_func;
if(group->obj_focus != NULL) lv_obj_invalidate(*group->obj_focus);
}
/**
* Set a function for a group which will modify the object's style if it is in focus in edit mode
* @param group pointer to a group
* @param style_mod_func the style modifier function pointer
*/
void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func)
{
group->style_mod_edit = style_mod_func;
if(group->obj_focus != NULL) lv_obj_invalidate(*group->obj_focus);
}
/**
* Set a function for a group which will be called when a new object is focused
* @param group pointer to a group
* @param focus_cb the call back function or NULL if unused
*/
void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb)
{
group->focus_cb = focus_cb;
}
/**
* Manually set the current mode (edit or navigate).
* @param group pointer to group
* @param edit: true: edit mode; false: navigate mode
*/
void lv_group_set_editing(lv_group_t * group, bool edit)
{
uint8_t en_val = edit ? 1 : 0;
if(en_val == group->editing) return; /*Do not set the same mode again*/
group->editing = en_val;
lv_obj_t * focused = lv_group_get_focused(group);
if(focused) focused->signal_func(focused, LV_SIGNAL_FOCUS, NULL); /*Focus again to properly leave edit mode*/
lv_obj_invalidate(focused);
}
/**
* Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked.
* @param group pointer to group
* @param en: true: enable `click_focus`
*/
void lv_group_set_click_focus(lv_group_t * group, bool en)
{
group->click_focus = en ? 1 : 0;
}
void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy) {
group->refocus_policy = policy & 0x01;
}
static void lv_group_refocus(lv_group_t *g) {
/*Refocus must temporarily allow wrapping to work correctly*/
uint8_t temp_wrap = g->wrap;
g->wrap = 1;
if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_NEXT)
lv_group_focus_next(g);
else if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_PREV)
lv_group_focus_prev(g);
/*Restore wrap property*/
g->wrap = temp_wrap;
}
/**
* Set whether focus next/prev will allow wrapping from first->last or last->first.
* @param group pointer to group
* @param en: true: enable `click_focus`
*/
void lv_group_set_wrap(lv_group_t * group, bool en)
{
group->wrap = en ? 1 : 0;
}
/**
* Modify a style with the set 'style_mod' function. The input style remains unchanged.
* @param group pointer to group
* @param style pointer to a style to modify
* @return a copy of the input style but modified with the 'style_mod' function
*/
lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style)
{
lv_style_copy(&group->style_tmp, style);
if(group->editing) {
if(group->style_mod_edit) group->style_mod_edit(&group->style_tmp);
} else {
if(group->style_mod) group->style_mod(&group->style_tmp);
}
return &group->style_tmp;
}
/**
* Get the focused object or NULL if there isn't one
* @param group pointer to a group
* @return pointer to the focused object
*/
lv_obj_t * lv_group_get_focused(const lv_group_t * group)
{
if(!group) return NULL;
if(group->obj_focus == NULL) return NULL;
return *group->obj_focus;
}
/**
* Get a the style modifier function of a group
* @param group pointer to a group
* @return pointer to the style modifier function
*/
lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group)
{
if(!group) return false;
return group->style_mod ;
}
/**
* Get a the style modifier function of a group in edit mode
* @param group pointer to a group
* @return pointer to the style modifier function
*/
lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group)
{
if(!group) return false;
return group->style_mod_edit;
}
/**
* Get the focus callback function of a group
* @param group pointer to a group
* @return the call back function or NULL if not set
*/
lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group)
{
if(!group) return false;
return group->focus_cb;
}
/**
* Get the current mode (edit or navigate).
* @param group pointer to group
* @return true: edit mode; false: navigate mode
*/
bool lv_group_get_editing(const lv_group_t * group)
{
if(!group) return false;
return group->editing ? true : false;
}
/**
* Get the `click_focus` attribute.
* @param group pointer to group
* @return true: `click_focus` is enabled; false: disabled
*/
bool lv_group_get_click_focus(const lv_group_t * group)
{
if(!group) return false;
return group->click_focus ? true : false;
}
/**
* Get whether focus next/prev will allow wrapping from first->last or last->first object.
* @param group pointer to group
* @param en: true: wrapping enabled; false: wrapping disabled
*/
bool lv_group_get_wrap(lv_group_t * group)
{
if(!group) return false;
return group->wrap ? true : false;
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Default style modifier function
* @param style pointer to a style to modify. (Typically group.style_tmp) It will be OVERWRITTEN.
*/
static void style_mod_def(lv_style_t * style)
{
#if LV_COLOR_DEPTH != 1
/*Make the style to be a little bit orange*/
style->body.border.opa = LV_OPA_COVER;
style->body.border.color = LV_COLOR_ORANGE;
/*If not empty or has border then emphasis the border*/
if(style->body.empty == 0 || style->body.border.width != 0) style->body.border.width = LV_DPI / 20;
style->body.main_color = lv_color_mix(style->body.main_color, LV_COLOR_ORANGE, LV_OPA_70);
style->body.grad_color = lv_color_mix(style->body.grad_color, LV_COLOR_ORANGE, LV_OPA_70);
style->body.shadow.color = lv_color_mix(style->body.shadow.color, LV_COLOR_ORANGE, LV_OPA_60);
style->text.color = lv_color_mix(style->text.color, LV_COLOR_ORANGE, LV_OPA_70);
#else
style->body.border.opa = LV_OPA_COVER;
style->body.border.color = LV_COLOR_BLACK;
style->body.border.width = 2;
#endif
}
/**
* Default style modifier function
* @param style pointer to a style to modify. (Typically group.style_tmp) It will be OVERWRITTEN.
*/
static void style_mod_edit_def(lv_style_t * style)
{
#if LV_COLOR_DEPTH != 1
/*Make the style to be a little bit orange*/
style->body.border.opa = LV_OPA_COVER;
style->body.border.color = LV_COLOR_GREEN;
/*If not empty or has border then emphasis the border*/
if(style->body.empty == 0 || style->body.border.width != 0) style->body.border.width = LV_DPI / 20;
style->body.main_color = lv_color_mix(style->body.main_color, LV_COLOR_GREEN, LV_OPA_70);
style->body.grad_color = lv_color_mix(style->body.grad_color, LV_COLOR_GREEN, LV_OPA_70);
style->body.shadow.color = lv_color_mix(style->body.shadow.color, LV_COLOR_GREEN, LV_OPA_60);
style->text.color = lv_color_mix(style->text.color, LV_COLOR_GREEN, LV_OPA_70);
#else
style->body.border.opa = LV_OPA_COVER;
style->body.border.color = LV_COLOR_BLACK;
style->body.border.width = 3;
#endif
}
static void obj_to_foreground(lv_obj_t * obj)
{
/*Search for 'top' attribute*/
lv_obj_t * i = obj;
lv_obj_t * last_top = NULL;
while(i != NULL) {
if(i->top != 0) last_top = i;
i = lv_obj_get_parent(i);
}
if(last_top != NULL) {
/*Move the last_top object to the foreground*/
lv_obj_t * par = lv_obj_get_parent(last_top);
/*After list change it will be the new head*/
lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top);
lv_obj_invalidate(last_top);
}
}
#endif /*USE_LV_GROUP != 0*/

View File

@ -0,0 +1,247 @@
/**
* @file lv_group.h
*
*/
#ifndef LV_GROUP_H
#define LV_GROUP_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_conf.h"
#else
#include "../../lv_conf.h"
#endif
#include "lv_obj.h"
/*********************
* DEFINES
*********************/
/*Predefined keys to control the focused object via lv_group_send(group, c)*/
/*For compatibility in signal function define the keys regardless to LV_GROUP*/
#define LV_GROUP_KEY_UP 17 /*0x11*/
#define LV_GROUP_KEY_DOWN 18 /*0x12*/
#define LV_GROUP_KEY_RIGHT 19 /*0x13*/
#define LV_GROUP_KEY_LEFT 20 /*0x14*/
#define LV_GROUP_KEY_ESC 27 /*0x1B*/
#define LV_GROUP_KEY_DEL 127 /*0x7F*/
#define LV_GROUP_KEY_BACKSPACE 8 /*0x08*/
#define LV_GROUP_KEY_ENTER 10 /*0x0A, '\n'*/
#define LV_GROUP_KEY_NEXT 9 /*0x09, '\t'*/
#define LV_GROUP_KEY_PREV 11 /*0x0B, '*/
#if USE_LV_GROUP != 0
/**********************
* TYPEDEFS
**********************/
struct _lv_group_t;
typedef void (*lv_group_style_mod_func_t)(lv_style_t *);
typedef void (*lv_group_focus_cb_t)(struct _lv_group_t *);
typedef struct _lv_group_t
{
lv_ll_t obj_ll; /*Linked list to store the objects in the group */
lv_obj_t ** obj_focus; /*The object in focus*/
lv_group_style_mod_func_t style_mod; /*A function which modifies the style of the focused object*/
lv_group_style_mod_func_t style_mod_edit;/*A function which modifies the style of the focused object*/
lv_group_focus_cb_t focus_cb; /*A function to call when a new object is focused (optional)*/
lv_style_t style_tmp; /*Stores the modified style of the focused object */
uint8_t frozen :1; /*1: can't focus to new object*/
uint8_t editing :1; /*1: Edit mode, 0: Navigate mode*/
uint8_t click_focus :1; /*1: If an object in a group is clicked by an indev then it will be focused */
uint8_t refocus_policy :1; /*1: Focus prev if focused on deletion. 0: Focus prev if focused on deletion.*/
uint8_t wrap :1; /*1: Focus next/prev can wrap at end of list. 0: Focus next/prev stops at end of list.*/
} lv_group_t;
typedef enum _lv_group_refocus_policy_t {
LV_GROUP_REFOCUS_POLICY_NEXT = 0,
LV_GROUP_REFOCUS_POLICY_PREV = 1
} lv_group_refocus_policy_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a new object group
* @return pointer to the new object group
*/
lv_group_t * lv_group_create(void);
/**
* Delete a group object
* @param group pointer to a group
*/
void lv_group_del(lv_group_t * group);
/**
* Add an object to a group
* @param group pointer to a group
* @param obj pointer to an object to add
*/
void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj);
/**
* Remove an object from its group
* @param obj pointer to an object to remove
*/
void lv_group_remove_obj(lv_obj_t * obj);
/**
* Focus on an object (defocus the current)
* @param obj pointer to an object to focus on
*/
void lv_group_focus_obj(lv_obj_t * obj);
/**
* Focus the next object in a group (defocus the current)
* @param group pointer to a group
*/
void lv_group_focus_next(lv_group_t * group);
/**
* Focus the previous object in a group (defocus the current)
* @param group pointer to a group
*/
void lv_group_focus_prev(lv_group_t * group);
/**
* Do not let to change the focus from the current object
* @param group pointer to a group
* @param en true: freeze, false: release freezing (normal mode)
*/
void lv_group_focus_freeze(lv_group_t * group, bool en);
/**
* Send a control character to the focuses object of a group
* @param group pointer to a group
* @param c a character (use LV_GROUP_KEY_.. to navigate)
* @return result of focused object in group.
*/
lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c);
/**
* Set a function for a group which will modify the object's style if it is in focus
* @param group pointer to a group
* @param style_mod_func the style modifier function pointer
*/
void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func);
/**
* Set a function for a group which will modify the object's style if it is in focus in edit mode
* @param group pointer to a group
* @param style_mod_func the style modifier function pointer
*/
void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func);
/**
* Set a function for a group which will be called when a new object is focused
* @param group pointer to a group
* @param focus_cb the call back function or NULL if unused
*/
void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb);
/**
* Set whether the next or previous item in a group is focused if the currently focussed obj is deleted.
* @param group pointer to a group
* @param new refocus policy enum
*/
void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy);
/**
* Manually set the current mode (edit or navigate).
* @param group pointer to group
* @param edit: true: edit mode; false: navigate mode
*/
void lv_group_set_editing(lv_group_t * group, bool edit);
/**
* Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked.
* @param group pointer to group
* @param en: true: enable `click_focus`
*/
void lv_group_set_click_focus(lv_group_t * group, bool en);
/**
* Set whether focus next/prev will allow wrapping from first->last or last->first object.
* @param group pointer to group
* @param en: true: wrapping enabled; false: wrapping disabled
*/
void lv_group_set_wrap(lv_group_t * group, bool en);
/**
* Modify a style with the set 'style_mod' function. The input style remains unchanged.
* @param group pointer to group
* @param style pointer to a style to modify
* @return a copy of the input style but modified with the 'style_mod' function
*/
lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style);
/**
* Get the focused object or NULL if there isn't one
* @param group pointer to a group
* @return pointer to the focused object
*/
lv_obj_t * lv_group_get_focused(const lv_group_t * group);
/**
* Get a the style modifier function of a group
* @param group pointer to a group
* @return pointer to the style modifier function
*/
lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group);
/**
* Get a the style modifier function of a group in edit mode
* @param group pointer to a group
* @return pointer to the style modifier function
*/
lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group);
/**
* Get the focus callback function of a group
* @param group pointer to a group
* @return the call back function or NULL if not set
*/
lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group);
/**
* Get the current mode (edit or navigate).
* @param group pointer to group
* @return true: edit mode; false: navigate mode
*/
bool lv_group_get_editing(const lv_group_t * group);
/**
* Get the `click_focus` attribute.
* @param group pointer to group
* @return true: `click_focus` is enabled; false: disabled
*/
bool lv_group_get_click_focus(const lv_group_t * group);
/**
* Get whether focus next/prev will allow wrapping from first->last or last->first object.
* @param group pointer to group
* @param en: true: wrapping enabled; false: wrapping disabled
*/
bool lv_group_get_wrap(lv_group_t * group);
/**********************
* MACROS
**********************/
#endif /*USE_LV_GROUP != 0*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_GROUP_H*/

View File

@ -0,0 +1,965 @@
/**
* @file lv_indev_proc.c
*
*/
/*********************
* INCLUDES
********************/
#include "lv_indev.h"
#include "../lv_hal/lv_hal_tick.h"
#include "../lv_core/lv_group.h"
#include "../lv_core/lv_refr.h"
#include "../lv_misc/lv_task.h"
#include "../lv_misc/lv_math.h"
#include "../lv_draw/lv_draw_rbasic.h"
#include "lv_obj.h"
/*********************
* DEFINES
*********************/
#if LV_INDEV_DRAG_THROW <= 0
#warning "LV_INDEV_DRAG_THROW must be greater than 0"
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
#if LV_INDEV_READ_PERIOD != 0
static void indev_proc_task(void * param);
static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data);
static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data);
static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data);
static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data);
static void indev_proc_press(lv_indev_proc_t * proc);
static void indev_proc_release(lv_indev_proc_t * proc);
static void indev_proc_reset_query_handler(lv_indev_t * indev);
static lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj);
static void indev_drag(lv_indev_proc_t * state);
static void indev_drag_throw(lv_indev_proc_t * state);
#endif
/**********************
* STATIC VARIABLES
**********************/
static lv_indev_t * indev_act;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the display input device subsystem
*/
void lv_indev_init(void)
{
#if LV_INDEV_READ_PERIOD != 0
lv_task_create(indev_proc_task, LV_INDEV_READ_PERIOD, LV_TASK_PRIO_MID, NULL);
#endif
lv_indev_reset(NULL); /*Reset all input devices*/
}
/**
* Get the currently processed input device. Can be used in action functions too.
* @return pointer to the currently processed input device or NULL if no input device processing right now
*/
lv_indev_t * lv_indev_get_act(void)
{
return indev_act;
}
/**
* Get the type of an input device
* @param indev pointer to an input device
* @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`)
*/
lv_hal_indev_type_t lv_indev_get_type(const lv_indev_t * indev)
{
if(indev == NULL) return LV_INDEV_TYPE_NONE;
return indev->driver.type;
}
/**
* Reset one or all input devices
* @param indev pointer to an input device to reset or NULL to reset all of them
*/
void lv_indev_reset(lv_indev_t * indev)
{
if(indev) indev->proc.reset_query = 1;
else {
lv_indev_t * i = lv_indev_next(NULL);
while(i) {
i->proc.reset_query = 1;
i = lv_indev_next(i);
}
}
}
/**
* Reset the long press state of an input device
* @param indev pointer to an input device
*/
void lv_indev_reset_lpr(lv_indev_t * indev)
{
indev->proc.long_pr_sent = 0;
indev->proc.longpr_rep_timestamp = lv_tick_get();
indev->proc.pr_timestamp = lv_tick_get();
}
/**
* Enable input devices device by type
* @param type Input device type
* @param enable true: enable this type; false: disable this type
*/
void lv_indev_enable(lv_hal_indev_type_t type, bool enable)
{
lv_indev_t * i = lv_indev_next(NULL);
while(i) {
if(i->driver.type == type) i->proc.disabled = enable == false ? 1 : 0;
i = lv_indev_next(i);
}
}
/**
* Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON)
* @param indev pointer to an input device
* @param cur_obj pointer to an object to be used as cursor
*/
void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj)
{
if(indev->driver.type != LV_INDEV_TYPE_POINTER) return;
indev->cursor = cur_obj;
lv_obj_set_parent(indev->cursor, lv_layer_sys());
lv_obj_set_pos(indev->cursor, indev->proc.act_point.x, indev->proc.act_point.y);
}
#if USE_LV_GROUP
/**
* Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD)
* @param indev pointer to an input device
* @param group point to a group
*/
void lv_indev_set_group(lv_indev_t * indev, lv_group_t * group)
{
if(indev->driver.type == LV_INDEV_TYPE_KEYPAD || indev->driver.type == LV_INDEV_TYPE_ENCODER) indev->group = group;
}
#endif
/**
* Set the an array of points for LV_INDEV_TYPE_BUTTON.
* These points will be assigned to the buttons to press a specific point on the screen
* @param indev pointer to an input device
* @param group point to a group
*/
void lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t * points)
{
if(indev->driver.type == LV_INDEV_TYPE_BUTTON) indev->btn_points = points;
}
/**
* Set feedback callback for indev.
* @param indev pointer to an input device
* @param feedback feedback callback
*/
void lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback)
{
indev->feedback = feedback;
}
/**
* Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
* @param indev pointer to an input device
* @param point pointer to a point to store the result
*/
void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point)
{
if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) {
point->x = -1;
point->y = -1;
} else {
point->x = indev->proc.act_point.x;
point->y = indev->proc.act_point.y;
}
}
/**
* Get the last key of an input device (for LV_INDEV_TYPE_KEYPAD)
* @param indev pointer to an input device
* @return the last pressed key (0 on error)
*/
uint32_t lv_indev_get_key(const lv_indev_t * indev)
{
if(indev->driver.type != LV_INDEV_TYPE_KEYPAD) return 0;
else return indev->proc.last_key;
}
/**
* Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
* @param indev pointer to an input device
* @return true: drag is in progress
*/
bool lv_indev_is_dragging(const lv_indev_t * indev)
{
if(indev == NULL) return false;
if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) return false;
return indev->proc.drag_in_prog == 0 ? false : true;
}
/**
* Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
* @param indev pointer to an input device
* @param point pointer to a point to store the vector
*/
void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point)
{
if(indev == NULL) {
point->x = 0;
point->y = 0;
return;
}
if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) {
point->x = 0;
point->y = 0;
} else {
point->x = indev->proc.vect.x;
point->y = indev->proc.vect.y;
}
}
/**
* Get elapsed time since last press
* @param indev pointer to an input device (NULL to get the overall smallest inactivity)
* @return Elapsed ticks (milliseconds) since last press
*/
uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev)
{
uint32_t t;
if(indev) return t = lv_tick_elaps(indev->last_activity_time);
lv_indev_t * i;
t = UINT16_MAX;
i = lv_indev_next(NULL);
while(i) {
t = LV_MATH_MIN(t, lv_tick_elaps(i->last_activity_time));
i = lv_indev_next(i);
}
return t;
}
/**
* Get feedback callback for indev.
* @param indev pointer to an input device
* @return feedback callback
*/
lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev)
{
return indev->feedback;
}
/**
* Do nothing until the next release
* @param indev pointer to an input device
*/
void lv_indev_wait_release(lv_indev_t * indev)
{
indev->proc.wait_unil_release = 1;
}
/**********************
* STATIC FUNCTIONS
**********************/
#if LV_INDEV_READ_PERIOD != 0
/**
* Called periodically to handle the input devices
* @param param unused
*/
static void indev_proc_task(void * param)
{
(void)param;
LV_LOG_TRACE("indev task started");
lv_indev_data_t data;
lv_indev_t * i;
i = lv_indev_next(NULL);
/*Read and process all indevs*/
while(i) {
indev_act = i;
/*Handle reset query before processing the point*/
indev_proc_reset_query_handler(i);
if(i->proc.disabled == 0) {
bool more_to_read;
do {
/*Read the data*/
more_to_read = lv_indev_read(i, &data);
indev_proc_reset_query_handler(i); /*The active object might deleted even in the read function*/
i->proc.state = data.state;
if(i->proc.state == LV_INDEV_STATE_PR) {
i->last_activity_time = lv_tick_get();
}
if(i->driver.type == LV_INDEV_TYPE_POINTER) {
indev_pointer_proc(i, &data);
} else if(i->driver.type == LV_INDEV_TYPE_KEYPAD) {
indev_keypad_proc(i, &data);
} else if(i->driver.type == LV_INDEV_TYPE_ENCODER) {
indev_encoder_proc(i, &data);
} else if(i->driver.type == LV_INDEV_TYPE_BUTTON) {
indev_button_proc(i, &data);
}
/*Handle reset query if it happened in during processing*/
indev_proc_reset_query_handler(i);
} while(more_to_read);
}
i = lv_indev_next(i); /*Go to the next indev*/
}
indev_act = NULL; /*End of indev processing, so no act indev*/
LV_LOG_TRACE("indev task finished");
}
/**
* Process a new point from LV_INDEV_TYPE_POINTER input device
* @param i pointer to an input device
* @param data pointer to the data read from the input device
*/
static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data)
{
/*Move the cursor if set and moved*/
if(i->cursor != NULL &&
(i->proc.last_point.x != data->point.x ||
i->proc.last_point.y != data->point.y)) {
lv_obj_set_pos(i->cursor, data->point.x, data->point.y);
}
i->proc.act_point.x = data->point.x;
i->proc.act_point.y = data->point.y;
if(i->proc.state == LV_INDEV_STATE_PR) {
#if LV_INDEV_POINT_MARKER != 0
lv_area_t area;
area.x1 = i->proc.act_point.x - (LV_INDEV_POINT_MARKER >> 1);
area.y1 = i->proc.act_point.y - (LV_INDEV_POINT_MARKER >> 1);
area.x2 = i->proc.act_point.x + ((LV_INDEV_POINT_MARKER >> 1) | 0x1);
area.y2 = i->proc.act_point.y + ((LV_INDEV_POINT_MARKER >> 1) | 0x1);
lv_rfill(&area, NULL, LV_COLOR_MAKE(0xFF, 0, 0), LV_OPA_COVER);
#endif
indev_proc_press(&i->proc);
} else {
indev_proc_release(&i->proc);
}
i->proc.last_point.x = i->proc.act_point.x;
i->proc.last_point.y = i->proc.act_point.y;
}
/**
* Process a new point from LV_INDEV_TYPE_KEYPAD input device
* @param i pointer to an input device
* @param data pointer to the data read from the input device
*/
static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)
{
#if USE_LV_GROUP
if(i->group == NULL) return;
/*Key press happened*/
if(data->state == LV_INDEV_STATE_PR &&
i->proc.last_state == LV_INDEV_STATE_REL) {
i->proc.pr_timestamp = lv_tick_get();
lv_obj_t * focused = lv_group_get_focused(i->group);
if(focused && data->key == LV_GROUP_KEY_ENTER) {
focused->signal_func(focused, LV_SIGNAL_PRESSED, indev_act);
}
}
/*Pressing*/
else if(data->state == LV_INDEV_STATE_PR && i->proc.last_state == LV_INDEV_STATE_PR) {
if(data->key == LV_GROUP_KEY_ENTER &&
i->proc.long_pr_sent == 0 &&
lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) {
/*On enter long press leave edit mode.*/
lv_obj_t * focused = lv_group_get_focused(i->group);
if(focused) {
focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act);
i->proc.long_pr_sent = 1;
}
}
}
/*Release happened*/
else if(data->state == LV_INDEV_STATE_REL && i->proc.last_state == LV_INDEV_STATE_PR) {
/*The user might clear the key when it was released. Always release the pressed key*/
data->key = i->proc.last_key;
/* Edit mode is not used by KEYPAD devices.
* So leave edit mode if we are in it before focusing on the next/prev object*/
if(data->key == LV_GROUP_KEY_NEXT || data->key == LV_GROUP_KEY_PREV) {
lv_group_set_editing(i->group, false);
}
if(data->key == LV_GROUP_KEY_NEXT) {
lv_group_focus_next(i->group);
} else if(data->key == LV_GROUP_KEY_PREV) {
lv_group_focus_prev(i->group);
} else if(data->key == LV_GROUP_KEY_ENTER) {
if(!i->proc.long_pr_sent) {
lv_group_send_data(i->group, data->key);
}
} else {
lv_group_send_data(i->group, data->key);
}
if(i->proc.reset_query) return; /*The object might be deleted in `focus_cb` or due to any other user event*/
i->proc.pr_timestamp = 0;
i->proc.long_pr_sent = 0;
}
i->proc.last_state = data->state;
i->proc.last_key = data->key;
#else
(void)data; /*Unused*/
(void)i; /*Unused*/
#endif
}
/**
* Process a new point from LV_INDEV_TYPE_ENCODER input device
* @param i pointer to an input device
* @param data pointer to the data read from the input device
*/
static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
{
#if USE_LV_GROUP
if(i->group == NULL) return;
/*Process the steps first. They are valid only with released button*/
if(data->state == LV_INDEV_STATE_REL) {
/*In edit mode send LEFT/RIGHT keys*/
if(lv_group_get_editing(i->group)) {
int32_t s;
if(data->enc_diff < 0) {
for(s = 0; s < -data->enc_diff; s++) lv_group_send_data(i->group, LV_GROUP_KEY_LEFT);
} else if(data->enc_diff > 0) {
for(s = 0; s < data->enc_diff; s++) lv_group_send_data(i->group, LV_GROUP_KEY_RIGHT);
}
}
/*In navigate mode focus on the next/prev objects*/
else {
int32_t s;
if(data->enc_diff < 0) {
for(s = 0; s < -data->enc_diff; s++) lv_group_focus_prev(i->group);
} else if(data->enc_diff > 0) {
for(s = 0; s < data->enc_diff; s++) lv_group_focus_next(i->group);
}
}
}
/*Key press happened*/
if(data->state == LV_INDEV_STATE_PR &&
i->proc.last_state == LV_INDEV_STATE_REL) {
i->proc.pr_timestamp = lv_tick_get();
}
/*Pressing*/
else if(data->state == LV_INDEV_STATE_PR && i->proc.last_state == LV_INDEV_STATE_PR) {
if(i->proc.long_pr_sent == 0 &&
lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) {
/*On enter long press leave edit mode.*/
lv_obj_t * focused = lv_group_get_focused(i->group);
bool editable = false;
if(focused) focused->signal_func(focused, LV_SIGNAL_GET_EDITABLE, &editable);
if(editable) {
if(i->group->obj_ll.head != i->group->obj_ll.tail)
lv_group_set_editing(i->group, lv_group_get_editing(i->group) ? false : true); /*Toggle edit mode on long press*/
else if(focused)
focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act);
}
/*If not editable then just send a long press signal*/
else {
if(focused)
focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act);
}
i->proc.long_pr_sent = 1;
}
}
/*Release happened*/
else if(data->state == LV_INDEV_STATE_REL && i->proc.last_state == LV_INDEV_STATE_PR) {
lv_obj_t * focused = lv_group_get_focused(i->group);
bool editable = false;
if(focused) focused->signal_func(focused, LV_SIGNAL_GET_EDITABLE, &editable);
/*The button was released on a non-editable object. Just send enter*/
if(!editable) {
lv_group_send_data(i->group, LV_GROUP_KEY_ENTER);
}
/*An object is being edited and the button is releases. Just send enter */
else if(i->group->editing) {
if(!i->proc.long_pr_sent || i->group->obj_ll.head == i->group->obj_ll.tail)
lv_group_send_data(i->group, LV_GROUP_KEY_ENTER); /*Ignore long pressed enter release because it comes from mode switch*/
}
/*If the focused object is editable and now in navigate mode then enter edit mode*/
else if(editable && !i->group->editing && !i->proc.long_pr_sent) {
lv_group_set_editing(i->group, lv_group_get_editing(i->group) ? false : true); /*Toggle edit mode on long press*/
}
if(i->proc.reset_query) return; /*The object might be deleted in `focus_cb` or due to any other user event*/
i->proc.pr_timestamp = 0;
i->proc.long_pr_sent = 0;
}
i->proc.last_state = data->state;
i->proc.last_key = data->key;
#else
(void)data; /*Unused*/
(void)i; /*Unused*/
#endif
}
/**
* Process new points from a input device. indev->state.pressed has to be set
* @param indev pointer to an input device state
* @param x x coordinate of the next point
* @param y y coordinate of the next point
*/
static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data)
{
i->proc.act_point.x = i->btn_points[data->btn].x;
i->proc.act_point.y = i->btn_points[data->btn].y;
/*Still the same point is pressed*/
if(i->proc.last_point.x == i->proc.act_point.x &&
i->proc.last_point.y == i->proc.act_point.y &&
data->state == LV_INDEV_STATE_PR) {
#if LV_INDEV_POINT_MARKER != 0
lv_area_t area;
area.x1 = i->proc.act_point.x - (LV_INDEV_POINT_MARKER >> 1);
area.y1 = i->proc.act_point.y - (LV_INDEV_POINT_MARKER >> 1);
area.x2 = i->proc.act_point.x + ((LV_INDEV_POINT_MARKER >> 1) | 0x1);
area.y2 = i->proc.act_point.y + ((LV_INDEV_POINT_MARKER >> 1) | 0x1);
lv_rfill(&area, NULL, LV_COLOR_MAKE(0xFF, 0, 0), LV_OPA_COVER);
#endif
indev_proc_press(&i->proc);
} else {
/*If a new point comes always make a release*/
indev_proc_release(&i->proc);
}
i->proc.last_point.x = i->proc.act_point.x;
i->proc.last_point.y = i->proc.act_point.y;
}
/**
* Process the pressed state of LV_INDEV_TYPE_POINER input devices
* @param indev pointer to an input device 'proc'
*/
static void indev_proc_press(lv_indev_proc_t * proc)
{
lv_obj_t * pr_obj = proc->act_obj;
if(proc->wait_unil_release != 0) return;
/*If there is no last object then search*/
if(proc->act_obj == NULL) {
pr_obj = indev_search_obj(proc, lv_layer_top());
if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_scr_act());
}
/*If there is last object but it is not dragged and not protected also search*/
else if(proc->drag_in_prog == 0 &&
lv_obj_is_protected(proc->act_obj, LV_PROTECT_PRESS_LOST) == false) {/*Now act_obj != NULL*/
pr_obj = indev_search_obj(proc, lv_layer_top());
if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_scr_act());
}
/*If a dragable or a protected object was the last then keep it*/
else {
}
/*If a new object was found reset some variables and send a pressed signal*/
if(pr_obj != proc->act_obj) {
proc->last_point.x = proc->act_point.x;
proc->last_point.y = proc->act_point.y;
/*If a new object found the previous was lost, so send a signal*/
if(proc->act_obj != NULL) {
proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESS_LOST, indev_act);
if(proc->reset_query != 0) return;
}
proc->act_obj = pr_obj; /*Save the pressed object*/
proc->last_obj = proc->act_obj; /*Refresh the last_obj*/
if(proc->act_obj != NULL) {
/* Save the time when the obj pressed.
* It is necessary to count the long press time.*/
proc->pr_timestamp = lv_tick_get();
proc->long_pr_sent = 0;
proc->drag_range_out = 0;
proc->drag_in_prog = 0;
proc->drag_sum.x = 0;
proc->drag_sum.y = 0;
proc->vect.x = 0;
proc->vect.y = 0;
/*Search for 'top' attribute*/
lv_obj_t * i = proc->act_obj;
lv_obj_t * last_top = NULL;
while(i != NULL) {
if(i->top != 0) last_top = i;
i = lv_obj_get_parent(i);
}
if(last_top != NULL) {
/*Move the last_top object to the foreground*/
lv_obj_t * par = lv_obj_get_parent(last_top);
/*After list change it will be the new head*/
lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top);
lv_obj_invalidate(last_top);
}
/*Send a signal about the press*/
proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESSED, indev_act);
if(proc->reset_query != 0) return;
}
}
/*Calculate the vector*/
proc->vect.x = proc->act_point.x - proc->last_point.x;
proc->vect.y = proc->act_point.y - proc->last_point.y;
/*If there is active object and it can be dragged run the drag*/
if(proc->act_obj != NULL) {
proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESSING, indev_act);
if(proc->reset_query != 0) return;
indev_drag(proc);
if(proc->reset_query != 0) return;
/*If there is no drag then check for long press time*/
if(proc->drag_in_prog == 0 && proc->long_pr_sent == 0) {
/*Send a signal about the long press if enough time elapsed*/
if(lv_tick_elaps(proc->pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) {
pr_obj->signal_func(pr_obj, LV_SIGNAL_LONG_PRESS, indev_act);
if(proc->reset_query != 0) return;
/*Mark the signal sending to do not send it again*/
proc->long_pr_sent = 1;
/*Save the long press time stamp for the long press repeat handler*/
proc->longpr_rep_timestamp = lv_tick_get();
}
}
/*Send long press repeated signal*/
if(proc->drag_in_prog == 0 && proc->long_pr_sent == 1) {
/*Send a signal about the long press repeate if enough time elapsed*/
if(lv_tick_elaps(proc->longpr_rep_timestamp) > LV_INDEV_LONG_PRESS_REP_TIME) {
pr_obj->signal_func(pr_obj, LV_SIGNAL_LONG_PRESS_REP, indev_act);
if(proc->reset_query != 0) return;
proc->longpr_rep_timestamp = lv_tick_get();
}
}
}
}
/**
* Process the released state of LV_INDEV_TYPE_POINER input devices
* @param proc pointer to an input device 'proc'
*/
static void indev_proc_release(lv_indev_proc_t * proc)
{
if(proc->wait_unil_release != 0) {
proc->act_obj = NULL;
proc->last_obj = NULL;
proc->pr_timestamp = 0;
proc->longpr_rep_timestamp = 0;
proc->wait_unil_release = 0;
}
/*Forgot the act obj and send a released signal */
if(proc->act_obj != NULL) {
/* If the object was protected against press lost then it possible that
* the object is already not pressed but still it is the `act_obj`.
* In this case send the `LV_SIGNAL_RELEASED` if the indev is ON the `act_obj` */
if(lv_obj_is_protected(proc->act_obj, LV_PROTECT_PRESS_LOST)) {
/* Search the object on the current current coordinates.
* The start object is the object itself. If not ON it the the result will be NULL*/
lv_obj_t * obj_on = indev_search_obj(proc, proc->act_obj);
if(obj_on == proc->act_obj) proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_RELEASED, indev_act);
else proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESS_LOST, indev_act);
}
/* The simple case: `act_obj` was not protected against press lost.
* If it is already not pressed then was handled in `indev_proc_press`*/
else {
proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_RELEASED, indev_act);
}
if(proc->reset_query != 0) return;
/*Handle click focus*/
#if USE_LV_GROUP
/*Edit mode is not used by POINTER devices. So leave edit mode if we are in it*/
lv_group_t * act_g = lv_obj_get_group(proc->act_obj);
if(lv_group_get_editing(act_g)) {
lv_group_set_editing(act_g, false);
}
/*Check, if the parent is in a group focus on it.*/
if(lv_obj_is_protected(proc->act_obj, LV_PROTECT_CLICK_FOCUS) == false) { /*Respect the click protection*/
lv_group_t * g = lv_obj_get_group(proc->act_obj);
lv_obj_t * parent = proc->act_obj;
while(g == NULL) {
parent = lv_obj_get_parent(parent);
if(parent == NULL) break;
if(lv_obj_is_protected(parent, LV_PROTECT_CLICK_FOCUS)) { /*Ignore is the protected against click focus*/
parent = NULL;
break;
}
g = lv_obj_get_group(parent);
}
if(g != NULL && parent != NULL)
if(lv_group_get_click_focus(g)) {
lv_group_focus_obj(parent);
}
}
#endif
if(proc->reset_query != 0) return;
proc->act_obj = NULL;
proc->pr_timestamp = 0;
proc->longpr_rep_timestamp = 0;
}
/*The reset can be set in the signal function.
* In case of reset query ignore the remaining parts.*/
if(proc->last_obj != NULL && proc->reset_query == 0) {
indev_drag_throw(proc);
if(proc->reset_query != 0) return;
}
}
/**
* Process a new point from LV_INDEV_TYPE_BUTTON input device
* @param i pointer to an input device
* @param data pointer to the data read from the input device
* Reset input device if a reset query has been sent to it
* @param indev pointer to an input device
*/
static void indev_proc_reset_query_handler(lv_indev_t * indev)
{
if(indev->proc.reset_query) {
indev->proc.act_obj = NULL;
indev->proc.last_obj = NULL;
indev->proc.drag_range_out = 0;
indev->proc.drag_in_prog = 0;
indev->proc.long_pr_sent = 0;
indev->proc.pr_timestamp = 0;
indev->proc.longpr_rep_timestamp = 0;
indev->proc.drag_sum.x = 0;
indev->proc.drag_sum.y = 0;
indev->proc.reset_query = 0;
}
}
/**
* Search the most top, clickable object on the last point of an input device
* @param proc pointer to the `lv_indev_proc_t` part of the input device
* @param obj pointer to a start object, typically the screen
* @return pointer to the found object or NULL if there was no suitable object
*/
static lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj)
{
lv_obj_t * found_p = NULL;
/*If the point is on this object*/
/*Check its children too*/
if(lv_area_is_point_on(&obj->coords, &proc->act_point)) {
lv_obj_t * i;
LL_READ(obj->child_ll, i) {
found_p = indev_search_obj(proc, i);
/*If a child was found then break*/
if(found_p != NULL) {
break;
}
}
/*If then the children was not ok, and this obj is clickable
* and it or its parent is not hidden then save this object*/
if(found_p == NULL && lv_obj_get_click(obj) != false) {
lv_obj_t * hidden_i = obj;
while(hidden_i != NULL) {
if(lv_obj_get_hidden(hidden_i) == true) break;
hidden_i = lv_obj_get_parent(hidden_i);
}
/*No parent found with hidden == true*/
if(hidden_i == NULL) found_p = obj;
}
}
return found_p;
}
/**
* Handle the dragging of indev_proc_p->act_obj
* @param indev pointer to a input device state
*/
static void indev_drag(lv_indev_proc_t * state)
{
lv_obj_t * drag_obj = state->act_obj;
/*If drag parent is active check recursively the drag_parent attribute*/
while(lv_obj_get_drag_parent(drag_obj) != false &&
drag_obj != NULL) {
drag_obj = lv_obj_get_parent(drag_obj);
}
if(drag_obj == NULL) return;
if(lv_obj_get_drag(drag_obj) == false) return;
/*Count the movement by drag*/
state->drag_sum.x += state->vect.x;
state->drag_sum.y += state->vect.y;
/*Enough move?*/
if(state->drag_range_out == 0) {
/*If a move is greater then LV_DRAG_LIMIT then begin the drag*/
if(LV_MATH_ABS(state->drag_sum.x) >= LV_INDEV_DRAG_LIMIT ||
LV_MATH_ABS(state->drag_sum.y) >= LV_INDEV_DRAG_LIMIT) {
state->drag_range_out = 1;
}
}
/*If the drag limit is stepped over then handle the dragging*/
if(state->drag_range_out != 0) {
/*Set new position if the vector is not zero*/
if(state->vect.x != 0 ||
state->vect.y != 0) {
/*Get the coordinates of the object and modify them*/
lv_coord_t act_x = lv_obj_get_x(drag_obj);
lv_coord_t act_y = lv_obj_get_y(drag_obj);
uint16_t inv_buf_size = lv_refr_get_buf_size(); /*Get the number of currently invalidated areas*/
lv_coord_t prev_x = drag_obj->coords.x1;
lv_coord_t prev_y = drag_obj->coords.y1;
lv_coord_t prev_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj));
lv_coord_t prev_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj));
lv_obj_set_pos(drag_obj, act_x + state->vect.x, act_y + state->vect.y);
/*Set the drag in progress flag if the object is really moved*/
if(drag_obj->coords.x1 != prev_x || drag_obj->coords.y1 != prev_y) {
if(state->drag_range_out != 0) { /*Send the drag begin signal on first move*/
drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_BEGIN, indev_act);
if(state->reset_query != 0) return;
}
state->drag_in_prog = 1;
}
/*If the object didn't moved then clear the invalidated areas*/
else {
/*In a special case if the object is moved on a page and
* the scrollable has fit == true and the object is dragged of the page then
* while its coordinate is not changing only the parent's size is reduced */
lv_coord_t act_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj));
lv_coord_t act_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj));
if(act_par_w == prev_par_w && act_par_h == prev_par_h) {
uint16_t new_inv_buf_size = lv_refr_get_buf_size();
lv_refr_pop_from_buf(new_inv_buf_size - inv_buf_size);
}
}
}
}
}
/**
* Handle throwing by drag if the drag is ended
* @param indev pointer to an input device state
*/
static void indev_drag_throw(lv_indev_proc_t * state)
{
if(state->drag_in_prog == 0) return;
/*Set new position if the vector is not zero*/
lv_obj_t * drag_obj = state->last_obj;
/*If drag parent is active check recursively the drag_parent attribute*/
while(lv_obj_get_drag_parent(drag_obj) != false &&
drag_obj != NULL) {
drag_obj = lv_obj_get_parent(drag_obj);
}
if(drag_obj == NULL) return;
/*Return if the drag throw is not enabled*/
if(lv_obj_get_drag_throw(drag_obj) == false) {
state->drag_in_prog = 0;
drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act);
return;
}
/*Reduce the vectors*/
state->vect.x = state->vect.x * (100 - LV_INDEV_DRAG_THROW) / 100;
state->vect.y = state->vect.y * (100 - LV_INDEV_DRAG_THROW) / 100;
if(state->vect.x != 0 ||
state->vect.y != 0) {
/*Get the coordinates and modify them*/
lv_area_t coords_ori;
lv_obj_get_coords(drag_obj, &coords_ori);
lv_coord_t act_x = lv_obj_get_x(drag_obj) + state->vect.x;
lv_coord_t act_y = lv_obj_get_y(drag_obj) + state->vect.y;
lv_obj_set_pos(drag_obj, act_x, act_y);
lv_area_t coord_new;
lv_obj_get_coords(drag_obj, &coord_new);
/*If non of the coordinates are changed then do not continue throwing*/
if((coords_ori.x1 == coord_new.x1 || state->vect.x == 0) &&
(coords_ori.y1 == coord_new.y1 || state->vect.y == 0)) {
state->drag_in_prog = 0;
state->vect.x = 0;
state->vect.y = 0;
drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act);
}
}
/*If the vectors become 0 -> drag_in_prog = 0 and send a drag end signal*/
else {
state->drag_in_prog = 0;
drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act);
}
}
#endif

View File

@ -0,0 +1,157 @@
/**
* @file lv_indev_proc.h
*
*/
#ifndef LV_INDEV_H
#define LV_INDEV_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_obj.h"
#include "../lv_hal/lv_hal_indev.h"
#include "../lv_core/lv_group.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize the display input device subsystem
*/
void lv_indev_init(void);
/**
* Get the currently processed input device. Can be used in action functions too.
* @return pointer to the currently processed input device or NULL if no input device processing right now
*/
lv_indev_t * lv_indev_get_act(void);
/**
* Get the type of an input device
* @param indev pointer to an input device
* @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`)
*/
lv_hal_indev_type_t lv_indev_get_type(const lv_indev_t * indev);
/**
* Reset one or all input devices
* @param indev pointer to an input device to reset or NULL to reset all of them
*/
void lv_indev_reset(lv_indev_t * indev);
/**
* Reset the long press state of an input device
* @param indev_proc pointer to an input device
*/
void lv_indev_reset_lpr(lv_indev_t * indev);
/**
* Enable input devices device by type
* @param type Input device type
* @param enable true: enable this type; false: disable this type
*/
void lv_indev_enable(lv_hal_indev_type_t type, bool enable);
/**
* Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON)
* @param indev pointer to an input device
* @param cur_obj pointer to an object to be used as cursor
*/
void lv_indev_set_cursor(lv_indev_t *indev, lv_obj_t *cur_obj);
#if USE_LV_GROUP
/**
* Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD)
* @param indev pointer to an input device
* @param group point to a group
*/
void lv_indev_set_group(lv_indev_t *indev, lv_group_t *group);
#endif
/**
* Set the an array of points for LV_INDEV_TYPE_BUTTON.
* These points will be assigned to the buttons to press a specific point on the screen
* @param indev pointer to an input device
* @param group point to a group
*/
void lv_indev_set_button_points(lv_indev_t *indev, const lv_point_t *points);
/**
* Set feedback callback for indev.
* @param indev pointer to an input device
* @param feedback feedback callback
*/
void lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback);
/**
* Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
* @param indev pointer to an input device
* @param point pointer to a point to store the result
*/
void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point);
/**
* Get the last key of an input device (for LV_INDEV_TYPE_KEYPAD)
* @param indev pointer to an input device
* @return the last pressed key (0 on error)
*/
uint32_t lv_indev_get_key(const lv_indev_t * indev);
/**
* Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
* @param indev pointer to an input device
* @return true: drag is in progress
*/
bool lv_indev_is_dragging(const lv_indev_t * indev);
/**
* Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
* @param indev pointer to an input device
* @param point pointer to a point to store the vector
*/
void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point);
/**
* Get elapsed time since last press
* @param indev pointer to an input device (NULL to get the overall smallest inactivity)
* @return Elapsed ticks (milliseconds) since last press
*/
uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev);
/**
* Get feedback callback for indev.
* @param indev pointer to an input device
* @return feedback callback
*/
lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev);
/**
* Do nothing until the next release
* @param indev pointer to an input device
*/
void lv_indev_wait_release(lv_indev_t * indev);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_INDEV_H*/

View File

@ -0,0 +1,117 @@
/**
* @file lv_lang.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_lang.h"
#if USE_LV_MULTI_LANG
#include "lv_obj.h"
#include "../lv_misc/lv_gc.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void lang_set_core(lv_obj_t * obj);
/**********************
* STATIC VARIABLES
**********************/
static uint8_t lang_act = 0;
static const void * (*get_txt)(uint16_t);
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Change the language
* @param lang_id the id of the
*/
void lv_lang_set(uint8_t lang_id)
{
lang_act = lang_id;
lv_obj_t * i;
LL_READ(LV_GC_ROOT(_lv_scr_ll), i) {
i->signal_func(i, LV_SIGNAL_LANG_CHG, NULL);
lang_set_core(i);
}
lang_set_core(lv_scr_act());
}
/**
* Set a function to get the texts of the set languages from a `txt_id`
* @param fp a function pointer to get the texts
*/
void lv_lang_set_text_func(const void * (*fp)(uint16_t))
{
get_txt = fp;
}
/**
* Use the function set by `lv_lang_set_text_func` to get the `txt_id` text in the set language
* @param txt_id an ID of the text to get
* @return the `txt_id` txt on the set language
*/
const void * lv_lang_get_text(uint16_t txt_id)
{
if(get_txt == NULL) {
LV_LOG_WARN("lv_lang_get_text: text_func is not specified");
return NULL; /*No text_get function specified */
}
if(txt_id == LV_LANG_TXT_ID_NONE) {
LV_LOG_WARN("lv_lang_get_text: attempts to get invalid text ID");
return NULL; /*Invalid txt_id*/
}
return get_txt(txt_id);
}
/**
* Return with ID of the currently selected language
* @return pointer to the active screen object (loaded by 'lv_scr_load()')
*/
uint8_t lv_lang_act(void)
{
return lang_act;
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Change the language of the children. (Called recursively)
* @param obj pointer to an object
*/
static void lang_set_core(lv_obj_t * obj)
{
lv_obj_t * i;
LL_READ(obj->child_ll, i) {
i->signal_func(i, LV_SIGNAL_LANG_CHG, NULL);
lang_set_core(i);
}
}
#endif /*USE_LV_MULTI_LANG*/

View File

@ -0,0 +1,74 @@
/**
* @file lv_lang.h
*
*/
#ifndef LV_LANG_H
#define LV_LANG_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_conf.h"
#else
#include "../../lv_conf.h"
#endif
#if USE_LV_MULTI_LANG
#include <stdint.h>
/*********************
* DEFINES
*********************/
#define LV_LANG_TXT_ID_NONE 0xFFFF /*Used to not assign any text IDs for a multi-language object.*/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Change the language
* @param lang_id the id of the
*/
void lv_lang_set(uint8_t lang_id);
/**
* Set a function to get the texts of the set languages from a `txt_id`
* @param fp a function pointer to get the texts
*/
void lv_lang_set_text_func(const void * (*fp)(uint16_t));
/**
* Use the function set by `lv_lang_set_text_func` to get the `txt_id` text in the set language
* @param txt_id an ID of the text to get
* @return the `txt_id` txt on the set language
*/
const void * lv_lang_get_text(uint16_t txt_id);
/**
* Return with ID of the currently selected language
* @return pointer to the active screen object (loaded by 'lv_scr_load()')
*/
uint8_t lv_lang_act(void);
/**********************
* MACROS
**********************/
#endif /*USE_LV_MULTI_LANG*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_LANG_H*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,840 @@
/**
* @file lv_obj.h
*
*/
#ifndef LV_OBJ_H
#define LV_OBJ_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_conf.h"
#else
#include "../../lv_conf.h"
#endif
#include <stddef.h>
#include "lv_style.h"
#include "../lv_misc/lv_area.h"
#include "../lv_misc/lv_mem.h"
#include "../lv_misc/lv_ll.h"
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_log.h"
/*********************
* DEFINES
*********************/
/*Error check of lv_conf.h*/
#if LV_HOR_RES == 0 || LV_VER_RES == 0
#error "LittlevGL: LV_HOR_RES and LV_VER_RES must be greater than 0"
#endif
#if LV_ANTIALIAS > 1
#error "LittlevGL: LV_ANTIALIAS can be only 0 or 1"
#endif
#if LV_VDB_SIZE == 0 && LV_ANTIALIAS != 0
#error "LittlevGL: If LV_VDB_SIZE == 0 the anti-aliasing must be disabled"
#endif
#if LV_VDB_SIZE > 0 && LV_VDB_SIZE < LV_HOR_RES
#error "LittlevGL: Small Virtual Display Buffer (lv_conf.h: LV_VDB_SIZE >= LV_HOR_RES)"
#endif
#if LV_VDB_SIZE == 0 && USE_LV_REAL_DRAW == 0
#error "LittlevGL: If LV_VDB_SIZE = 0 Real drawing function are required (lv_conf.h: USE_LV_REAL_DRAW 1)"
#endif
#define LV_ANIM_IN 0x00 /*Animation to show an object. 'OR' it with lv_anim_builtin_t*/
#define LV_ANIM_OUT 0x80 /*Animation to hide an object. 'OR' it with lv_anim_builtin_t*/
#define LV_ANIM_DIR_MASK 0x80 /*ANIM_IN/ANIM_OUT mask*/
#define LV_MAX_ANCESTOR_NUM 8
/**********************
* TYPEDEFS
**********************/
struct _lv_obj_t;
enum
{
LV_DESIGN_DRAW_MAIN,
LV_DESIGN_DRAW_POST,
LV_DESIGN_COVER_CHK,
};
typedef uint8_t lv_design_mode_t;
typedef bool (* lv_design_func_t) (struct _lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode);
enum
{
LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action function or an operation was failed*/
LV_RES_OK, /*The object is valid (no deleted) after the action*/
};
typedef uint8_t lv_res_t;
enum
{
/*General signals*/
LV_SIGNAL_CLEANUP,
LV_SIGNAL_CHILD_CHG,
LV_SIGNAL_CORD_CHG,
LV_SIGNAL_STYLE_CHG,
LV_SIGNAL_REFR_EXT_SIZE,
LV_SIGNAL_LANG_CHG,
LV_SIGNAL_GET_TYPE,
_LV_SIGNAL_FEEDBACK_SECTION_START,
/*Input device related*/
LV_SIGNAL_PRESSED,
LV_SIGNAL_PRESSING,
LV_SIGNAL_PRESS_LOST,
LV_SIGNAL_RELEASED,
LV_SIGNAL_LONG_PRESS,
LV_SIGNAL_LONG_PRESS_REP,
LV_SIGNAL_DRAG_BEGIN,
LV_SIGNAL_DRAG_END,
/*Group related*/
LV_SIGNAL_FOCUS,
LV_SIGNAL_DEFOCUS,
LV_SIGNAL_CONTROLL,
_LV_SIGNAL_FEEDBACK_SECTION_END,
LV_SIGNAL_GET_EDITABLE,
};
typedef uint8_t lv_signal_t;
typedef lv_res_t (* lv_signal_func_t) (struct _lv_obj_t * obj, lv_signal_t sign, void * param);
enum
{
LV_ALIGN_CENTER = 0,
LV_ALIGN_IN_TOP_LEFT,
LV_ALIGN_IN_TOP_MID,
LV_ALIGN_IN_TOP_RIGHT,
LV_ALIGN_IN_BOTTOM_LEFT,
LV_ALIGN_IN_BOTTOM_MID,
LV_ALIGN_IN_BOTTOM_RIGHT,
LV_ALIGN_IN_LEFT_MID,
LV_ALIGN_IN_RIGHT_MID,
LV_ALIGN_OUT_TOP_LEFT,
LV_ALIGN_OUT_TOP_MID,
LV_ALIGN_OUT_TOP_RIGHT,
LV_ALIGN_OUT_BOTTOM_LEFT,
LV_ALIGN_OUT_BOTTOM_MID,
LV_ALIGN_OUT_BOTTOM_RIGHT,
LV_ALIGN_OUT_LEFT_TOP,
LV_ALIGN_OUT_LEFT_MID,
LV_ALIGN_OUT_LEFT_BOTTOM,
LV_ALIGN_OUT_RIGHT_TOP,
LV_ALIGN_OUT_RIGHT_MID,
LV_ALIGN_OUT_RIGHT_BOTTOM,
};
typedef uint8_t lv_align_t;
#if LV_OBJ_REALIGN
typedef struct {
const struct _lv_obj_t * base;
lv_coord_t xofs;
lv_coord_t yofs;
lv_align_t align;
uint8_t auto_realign :1;
uint8_t origo_align :1; /*1: the oigo (center of the object) was aligned with `lv_obj_align_origo`*/
}lv_reailgn_t;
#endif
typedef struct _lv_obj_t
{
struct _lv_obj_t * par; /*Pointer to the parent object*/
lv_ll_t child_ll; /*Linked list to store the children objects*/
lv_area_t coords; /*Coordinates of the object (x1, y1, x2, y2)*/
lv_signal_func_t signal_func; /*Object type specific signal function*/
lv_design_func_t design_func; /*Object type specific design function*/
void * ext_attr; /*Object type specific extended data*/
lv_style_t * style_p; /*Pointer to the object's style*/
#if LV_OBJ_FREE_PTR != 0
void * free_ptr; /*Application specific pointer (set it freely)*/
#endif
#if USE_LV_GROUP != 0
void * group_p; /*Pointer to the group of the object*/
#endif
/*Attributes and states*/
uint8_t click :1; /*1: Can be pressed by an input device*/
uint8_t drag :1; /*1: Enable the dragging*/
uint8_t drag_throw :1; /*1: Enable throwing with drag*/
uint8_t drag_parent :1; /*1: Parent will be dragged instead*/
uint8_t hidden :1; /*1: Object is hidden*/
uint8_t top :1; /*1: If the object or its children is clicked it goes to the foreground*/
uint8_t opa_scale_en :1; /*1: opa_scale is set*/
uint8_t protect; /*Automatically happening actions can be prevented. 'OR'ed values from `lv_protect_t`*/
lv_opa_t opa_scale; /*Scale down the opacity by this factor. Effects all children as well*/
lv_coord_t ext_size; /*EXTtend the size of the object in every direction. E.g. for shadow drawing*/
#if LV_OBJ_REALIGN
lv_reailgn_t realign;
#endif
#ifdef LV_OBJ_FREE_NUM_TYPE
LV_OBJ_FREE_NUM_TYPE free_num; /*Application specific identifier (set it freely)*/
#endif
} lv_obj_t;
typedef lv_res_t (*lv_action_t) (struct _lv_obj_t * obj);
/*Protect some attributes (max. 8 bit)*/
enum
{
LV_PROTECT_NONE = 0x00,
LV_PROTECT_CHILD_CHG = 0x01, /*Disable the child change signal. Used by the library*/
LV_PROTECT_PARENT = 0x02, /*Prevent automatic parent change (e.g. in lv_page)*/
LV_PROTECT_POS = 0x04, /*Prevent automatic positioning (e.g. in lv_cont layout)*/
LV_PROTECT_FOLLOW = 0x08, /*Prevent the object be followed in automatic ordering (e.g. in lv_cont PRETTY layout)*/
LV_PROTECT_PRESS_LOST= 0x10, /*If the `indev` was pressing this object but swiped out while pressing do not search other object.*/
LV_PROTECT_CLICK_FOCUS= 0x20,/*Prevent focusing the object by clicking on it*/
};
typedef uint8_t lv_protect_t;
/*Used by `lv_obj_get_type()`. The object's and its ancestor types are stored here*/
typedef struct {
const char * type[LV_MAX_ANCESTOR_NUM]; /*[0]: the actual type, [1]: ancestor, [2] #1's ancestor ... [x]: "lv_obj" */
} lv_obj_type_t;
enum
{
LV_ANIM_NONE = 0,
LV_ANIM_FLOAT_TOP, /*Float from/to the top*/
LV_ANIM_FLOAT_LEFT, /*Float from/to the left*/
LV_ANIM_FLOAT_BOTTOM, /*Float from/to the bottom*/
LV_ANIM_FLOAT_RIGHT, /*Float from/to the right*/
LV_ANIM_GROW_H, /*Grow/shrink horizontally*/
LV_ANIM_GROW_V, /*Grow/shrink vertically*/
};
typedef uint8_t lv_anim_builtin_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Init. the 'lv' library.
*/
void lv_init(void);
/*--------------------
* Create and delete
*-------------------*/
/**
* Create a basic object
* @param parent pointer to a parent object.
* If NULL then a screen will be created
* @param copy pointer to a base object, if not NULL then the new object will be copied from it
* @return pointer to the new object
*/
lv_obj_t * lv_obj_create(lv_obj_t * parent,const lv_obj_t * copy);
/**
* Delete 'obj' and all of its children
* @param obj pointer to an object to delete
* @return LV_RES_INV because the object is deleted
*/
lv_res_t lv_obj_del(lv_obj_t * obj);
/**
* Delete all children of an object
* @param obj pointer to an object
*/
void lv_obj_clean(lv_obj_t *obj);
/**
* Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task'
* @param obj pointer to an object
*/
void lv_obj_invalidate(const lv_obj_t * obj);
/*=====================
* Setter functions
*====================*/
/*--------------
* Screen set
*--------------*/
/**
* Load a new screen
* @param scr pointer to a screen
*/
void lv_scr_load(lv_obj_t * scr);
/*--------------------
* Parent/children set
*--------------------*/
/**
* Set a new parent for an object. Its relative position will be the same.
* @param obj pointer to an object. Can't be a screen.
* @param parent pointer to the new parent object. (Can't be NULL)
*/
void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent);
/*--------------------
* Coordinate set
* ------------------*/
/**
* Set relative the position of an object (relative to the parent)
* @param obj pointer to an object
* @param x new distance from the left side of the parent
* @param y new distance from the top of the parent
*/
void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y);
/**
* Set the x coordinate of a object
* @param obj pointer to an object
* @param x new distance from the left side from the parent
*/
void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x);
/**
* Set the y coordinate of a object
* @param obj pointer to an object
* @param y new distance from the top of the parent
*/
void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y);
/**
* Set the size of an object
* @param obj pointer to an object
* @param w new width
* @param h new height
*/
void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h);
/**
* Set the width of an object
* @param obj pointer to an object
* @param w new width
*/
void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w);
/**
* Set the height of an object
* @param obj pointer to an object
* @param h new height
*/
void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h);
/**
* Align an object to an other object.
* @param obj pointer to an object to align
* @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.
* @param align type of alignment (see 'lv_align_t' enum)
* @param x_mod x coordinate shift after alignment
* @param y_mod y coordinate shift after alignment
*/
void lv_obj_align(lv_obj_t * obj,const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod);
/**
* Align an object to an other object.
* @param obj pointer to an object to align
* @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.
* @param align type of alignment (see 'lv_align_t' enum)
* @param x_mod x coordinate shift after alignment
* @param y_mod y coordinate shift after alignment
*/
void lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod);
/**
* Realign the object based on the last `lv_obj_align` parameters.
* @param obj pointer to an object
*/
void lv_obj_realign(lv_obj_t * obj);
/**
* Enable the automatic realign of the object when its size has changed based on the last `lv_obj_align` parameters.
* @param obj pointer to an object
* @param en true: enable auto realign; false: disable auto realign
*/
void lv_obj_set_auto_realign(lv_obj_t * obj, bool en);
/*---------------------
* Appearance set
*--------------------*/
/**
* Set a new style for an object
* @param obj pointer to an object
* @param style_p pointer to the new style
*/
void lv_obj_set_style(lv_obj_t * obj, lv_style_t * style);
/**
* Notify an object about its style is modified
* @param obj pointer to an object
*/
void lv_obj_refresh_style(lv_obj_t * obj);
/**
* Notify all object if a style is modified
* @param style pointer to a style. Only the objects with this style will be notified
* (NULL to notify all objects)
*/
void lv_obj_report_style_mod(lv_style_t * style);
/*-----------------
* Attribute set
*----------------*/
/**
* Hide an object. It won't be visible and clickable.
* @param obj pointer to an object
* @param en true: hide the object
*/
void lv_obj_set_hidden(lv_obj_t * obj, bool en);
/**
* Enable or disable the clicking of an object
* @param obj pointer to an object
* @param en true: make the object clickable
*/
void lv_obj_set_click(lv_obj_t * obj, bool en);
/**
* Enable to bring this object to the foreground if it
* or any of its children is clicked
* @param obj pointer to an object
* @param en true: enable the auto top feature
*/
void lv_obj_set_top(lv_obj_t * obj, bool en);
/**
* Enable the dragging of an object
* @param obj pointer to an object
* @param en true: make the object dragable
*/
void lv_obj_set_drag(lv_obj_t * obj, bool en);
/**
* Enable the throwing of an object after is is dragged
* @param obj pointer to an object
* @param en true: enable the drag throw
*/
void lv_obj_set_drag_throw(lv_obj_t * obj, bool en);
/**
* Enable to use parent for drag related operations.
* If trying to drag the object the parent will be moved instead
* @param obj pointer to an object
* @param en true: enable the 'drag parent' for the object
*/
void lv_obj_set_drag_parent(lv_obj_t * obj, bool en);
/**
* Set editable parameter Used by groups and keyboard/encoder control.
* Editable object has something inside to choose (the elements of a list)
* @param obj pointer to an object
* @param en true: enable editing
*/
//void lv_obj_set_editable(lv_obj_t * obj, bool en);
/**
* Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`)
* @param obj pointer to an object
* @param en true: opa scaling is enabled for this object and all children; false: no opa scaling
*/
void lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en);
/**
* Set the opa scale of an object
* @param obj pointer to an object
* @param opa_scale a factor to scale down opacity [0..255]
*/
void lv_obj_set_opa_scale(lv_obj_t * obj, lv_opa_t opa_scale);
/**
* Set a bit or bits in the protect filed
* @param obj pointer to an object
* @param prot 'OR'-ed values from `lv_protect_t`
*/
void lv_obj_set_protect(lv_obj_t * obj, uint8_t prot);
/**
* Clear a bit or bits in the protect filed
* @param obj pointer to an object
* @param prot 'OR'-ed values from `lv_protect_t`
*/
void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot);
/**
* Set the signal function of an object.
* Always call the previous signal function in the new.
* @param obj pointer to an object
* @param fp the new signal function
*/
void lv_obj_set_signal_func(lv_obj_t * obj, lv_signal_func_t fp);
/**
* Set a new design function for an object
* @param obj pointer to an object
* @param fp the new design function
*/
void lv_obj_set_design_func(lv_obj_t * obj, lv_design_func_t fp);
/*----------------
* Other set
*--------------*/
/**
* Allocate a new ext. data for an object
* @param obj pointer to an object
* @param ext_size the size of the new ext. data
* @return pointer to the allocated ext
*/
void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size);
/**
* Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object
* @param obj pointer to an object
*/
void lv_obj_refresh_ext_size(lv_obj_t * obj);
#ifdef LV_OBJ_FREE_NUM_TYPE
/**
* Set an application specific number for an object.
* It can help to identify objects in the application.
* @param obj pointer to an object
* @param free_num the new free number
*/
void lv_obj_set_free_num(lv_obj_t * obj, LV_OBJ_FREE_NUM_TYPE free_num);
#endif
#if LV_OBJ_FREE_PTR != 0
/**
* Set an application specific pointer for an object.
* It can help to identify objects in the application.
* @param obj pointer to an object
* @param free_p the new free pinter
*/
void lv_obj_set_free_ptr(lv_obj_t * obj, void * free_p);
#endif
#if USE_LV_ANIMATION
/**
* Animate an object
* @param obj pointer to an object to animate
* @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT
* @param time time of animation in milliseconds
* @param delay delay before the animation in milliseconds
* @param cb a function to call when the animation is ready
*/
void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay, void (*cb) (lv_obj_t *));
#endif
/*=======================
* Getter functions
*======================*/
/*------------------
* Screen get
*-----------------*/
/**
* Return with a pointer to the active screen
* @return pointer to the active screen object (loaded by 'lv_scr_load()')
*/
lv_obj_t * lv_scr_act(void);
/**
* Return with the top layer. (Same on every screen and it is above the normal screen layer)
* @return pointer to the top layer object (transparent screen sized lv_obj)
*/
lv_obj_t * lv_layer_top(void);
/**
* Return with the system layer. (Same on every screen and it is above the all other layers)
* It is used for example by the cursor
* @return pointer to the system layer object (transparent screen sized lv_obj)
*/
lv_obj_t * lv_layer_sys(void);
/**
* Return with the screen of an object
* @param obj pointer to an object
* @return pointer to a screen
*/
lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj);
/*---------------------
* Parent/children get
*--------------------*/
/**
* Returns with the parent of an object
* @param obj pointer to an object
* @return pointer to the parent of 'obj'
*/
lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj);
/**
* Iterate through the children of an object (start from the "youngest, lastly created")
* @param obj pointer to an object
* @param child NULL at first call to get the next children
* and the previous return value later
* @return the child after 'act_child' or NULL if no more child
*/
lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child);
/**
* Iterate through the children of an object (start from the "oldest", firstly created)
* @param obj pointer to an object
* @param child NULL at first call to get the next children
* and the previous return value later
* @return the child after 'act_child' or NULL if no more child
*/
lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child);
/**
* Count the children of an object (only children directly on 'obj')
* @param obj pointer to an object
* @return children number of 'obj'
*/
uint16_t lv_obj_count_children(const lv_obj_t * obj);
/*---------------------
* Coordinate get
*--------------------*/
/**
* Copy the coordinates of an object to an area
* @param obj pointer to an object
* @param cords_p pointer to an area to store the coordinates
*/
void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p);
/**
* Get the x coordinate of object
* @param obj pointer to an object
* @return distance of 'obj' from the left side of its parent
*/
lv_coord_t lv_obj_get_x(const lv_obj_t * obj);
/**
* Get the y coordinate of object
* @param obj pointer to an object
* @return distance of 'obj' from the top of its parent
*/
lv_coord_t lv_obj_get_y(const lv_obj_t * obj);
/**
* Get the width of an object
* @param obj pointer to an object
* @return the width
*/
lv_coord_t lv_obj_get_width(const lv_obj_t * obj);
/**
* Get the height of an object
* @param obj pointer to an object
* @return the height
*/
lv_coord_t lv_obj_get_height(const lv_obj_t * obj);
/**
* Get the extended size attribute of an object
* @param obj pointer to an object
* @return the extended size attribute
*/
lv_coord_t lv_obj_get_ext_size(const lv_obj_t * obj);
/**
* Get the automatic realign property of the object.
* @param obj pointer to an object
* @return true: auto realign is enabled; false: auto realign is disabled
*/
bool lv_obj_get_auto_realign(lv_obj_t * obj);
/*-----------------
* Appearance get
*---------------*/
/**
* Get the style pointer of an object (if NULL get style of the parent)
* @param obj pointer to an object
* @return pointer to a style
*/
lv_style_t * lv_obj_get_style(const lv_obj_t * obj);
/*-----------------
* Attribute get
*----------------*/
/**
* Get the hidden attribute of an object
* @param obj pointer to an object
* @return true: the object is hidden
*/
bool lv_obj_get_hidden(const lv_obj_t * obj);
/**
* Get the click enable attribute of an object
* @param obj pointer to an object
* @return true: the object is clickable
*/
bool lv_obj_get_click(const lv_obj_t * obj);
/**
* Get the top enable attribute of an object
* @param obj pointer to an object
* @return true: the auto top feature is enabled
*/
bool lv_obj_get_top(const lv_obj_t * obj);
/**
* Get the drag enable attribute of an object
* @param obj pointer to an object
* @return true: the object is dragable
*/
bool lv_obj_get_drag(const lv_obj_t * obj);
/**
* Get the drag throw enable attribute of an object
* @param obj pointer to an object
* @return true: drag throw is enabled
*/
bool lv_obj_get_drag_throw(const lv_obj_t * obj);
/**
* Get the drag parent attribute of an object
* @param obj pointer to an object
* @return true: drag parent is enabled
*/
bool lv_obj_get_drag_parent(const lv_obj_t * obj);
/**
* Get the opa scale enable parameter
* @param obj pointer to an object
* @return true: opa scaling is enabled for this object and all children; false: no opa scaling
*/
lv_opa_t lv_obj_get_opa_scale_enable(const lv_obj_t * obj);
/**
* Get the opa scale parameter of an object
* @param obj pointer to an object
* @return opa scale [0..255]
*/
lv_opa_t lv_obj_get_opa_scale(const lv_obj_t * obj);
/**
* Get the protect field of an object
* @param obj pointer to an object
* @return protect field ('OR'ed values of `lv_protect_t`)
*/
uint8_t lv_obj_get_protect(const lv_obj_t * obj);
/**
* Check at least one bit of a given protect bitfield is set
* @param obj pointer to an object
* @param prot protect bits to test ('OR'ed values of `lv_protect_t`)
* @return false: none of the given bits are set, true: at least one bit is set
*/
bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot);
/**
* Get the signal function of an object
* @param obj pointer to an object
* @return the signal function
*/
lv_signal_func_t lv_obj_get_signal_func(const lv_obj_t * obj);
/**
* Get the design function of an object
* @param obj pointer to an object
* @return the design function
*/
lv_design_func_t lv_obj_get_design_func(const lv_obj_t * obj);
/*------------------
* Other get
*-----------------*/
/**
* Get the ext pointer
* @param obj pointer to an object
* @return the ext pointer but not the dynamic version
* Use it as ext->data1, and NOT da(ext)->data1
*/
void * lv_obj_get_ext_attr(const lv_obj_t * obj);
/**
* Get object's and its ancestors type. Put their name in `type_buf` starting with the current type.
* E.g. buf.type[0]="lv_btn", buf.type[1]="lv_cont", buf.type[2]="lv_obj"
* @param obj pointer to an object which type should be get
* @param buf pointer to an `lv_obj_type_t` buffer to store the types
*/
void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf);
#ifdef LV_OBJ_FREE_NUM_TYPE
/**
* Get the free number
* @param obj pointer to an object
* @return the free number
*/
LV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(const lv_obj_t * obj);
#endif
#if LV_OBJ_FREE_PTR != 0
/**
* Get the free pointer
* @param obj pointer to an object
* @return the free pointer
*/
void * lv_obj_get_free_ptr(const lv_obj_t * obj);
#endif
#if USE_LV_GROUP
/**
* Get the group of the object
* @param obj pointer to an object
* @return the pointer to group of the object
*/
void * lv_obj_get_group(const lv_obj_t * obj);
/**
* Tell whether the object is the focused object of a group or not.
* @param obj pointer to an object
* @return true: the object is focused, false: the object is not focused or not in a group
*/
bool lv_obj_is_focused(const lv_obj_t * obj);
#endif
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_OBJ_H*/

View File

@ -0,0 +1,614 @@
/**
* @file lv_refr.c
*
*/
/*********************
* INCLUDES
*********************/
#include <stddef.h>
#include "lv_refr.h"
#include "lv_vdb.h"
#include "../lv_hal/lv_hal_tick.h"
#include "../lv_hal/lv_hal_disp.h"
#include "../lv_misc/lv_task.h"
#include "../lv_misc/lv_mem.h"
/*********************
* DEFINES
*********************/
#ifndef LV_INV_FIFO_SIZE
#define LV_INV_FIFO_SIZE 32 /*The average count of objects on a screen */
#endif
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_area_t area;
uint8_t joined;
} lv_join_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_refr_task(void * param);
static void lv_refr_join_area(void);
static void lv_refr_areas(void);
#if LV_VDB_SIZE == 0
static void lv_refr_area_no_vdb(const lv_area_t * area_p);
#else
static void lv_refr_area_with_vdb(const lv_area_t * area_p);
static void lv_refr_area_part_vdb(const lv_area_t * area_p);
#endif
static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj);
static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p);
static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p);
/**********************
* STATIC VARIABLES
**********************/
static lv_join_t inv_buf[LV_INV_FIFO_SIZE];
static uint16_t inv_buf_p;
static void (*monitor_cb)(uint32_t, uint32_t); /*Monitor the rendering time*/
static void (*round_cb)(lv_area_t *); /*If set then called to modify invalidated areas for special display controllers*/
static uint32_t px_num;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the screen refresh subsystem
*/
void lv_refr_init(void)
{
inv_buf_p = 0;
memset(inv_buf, 0, sizeof(inv_buf));
lv_task_t * task;
task = lv_task_create(lv_refr_task, LV_REFR_PERIOD, LV_TASK_PRIO_MID, NULL);
lv_task_ready(task); /*Be sure the screen will be refreshed immediately on start up*/
}
/**
* Redraw the invalidated areas now.
* Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process can
* prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar)
* this function can be called when the screen should be updated.
*/
void lv_refr_now(void)
{
lv_refr_task(NULL);
}
/**
* Invalidate an area
* @param area_p pointer to area which should be invalidated
*/
void lv_inv_area(const lv_area_t * area_p)
{
/*Clear the invalidate buffer if the parameter is NULL*/
if(area_p == NULL) {
inv_buf_p = 0;
return;
}
lv_area_t scr_area;
scr_area.x1 = 0;
scr_area.y1 = 0;
scr_area.x2 = LV_HOR_RES - 1;
scr_area.y2 = LV_VER_RES - 1;
lv_area_t com_area;
bool suc;
suc = lv_area_intersect(&com_area, area_p, &scr_area);
/*The area is truncated to the screen*/
if(suc != false) {
if(round_cb) round_cb(&com_area);
/*Save only if this area is not in one of the saved areas*/
uint16_t i;
for(i = 0; i < inv_buf_p; i++) {
if(lv_area_is_in(&com_area, &inv_buf[i].area) != false) return;
}
/*Save the area*/
if(inv_buf_p < LV_INV_FIFO_SIZE) {
lv_area_copy(&inv_buf[inv_buf_p].area, &com_area);
} else {/*If no place for the area add the screen*/
inv_buf_p = 0;
lv_area_copy(&inv_buf[inv_buf_p].area, &scr_area);
}
inv_buf_p ++;
}
}
/**
* Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels
* @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num))
* time_ms: refresh time in [ms]
* px_num: not the drawn pixels but the number of affected pixels of the screen
* (more pixels are drawn because of overlapping objects)
*/
void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t))
{
monitor_cb = cb;
}
/**
* Called when an area is invalidated to modify the coordinates of the area.
* Special display controllers may require special coordinate rounding
* @param cb pointer to the a function which will modify the area
*/
void lv_refr_set_round_cb(void(*cb)(lv_area_t *))
{
round_cb = cb;
}
/**
* Get the number of areas in the buffer
* @return number of invalid areas
*/
uint16_t lv_refr_get_buf_size(void)
{
return inv_buf_p;
}
/**
* Pop (delete) the last 'num' invalidated areas from the buffer
* @param num number of areas to delete
*/
void lv_refr_pop_from_buf(uint16_t num)
{
if(inv_buf_p < num) inv_buf_p = 0;
else inv_buf_p -= num;
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Called periodically to handle the refreshing
* @param param unused
*/
static void lv_refr_task(void * param)
{
(void)param;
LV_LOG_TRACE("display refresh task started");
uint32_t start = lv_tick_get();
if(lv_disp_get_active() == NULL) {
LV_LOG_TRACE("No display is registered");
return;
}
lv_refr_join_area();
lv_refr_areas();
/*If refresh happened ...*/
if(inv_buf_p != 0) {
/*In true double buffered mode copy the refreshed areas to the new VDB to keep it up to date*/
#if LV_VDB_TRUE_DOUBLE_BUFFERED
lv_vdb_t * vdb_p = lv_vdb_get();
vdb_p->area.x1 = 0;
vdb_p->area.x2 = LV_HOR_RES-1;
vdb_p->area.y1 = 0;
vdb_p->area.y2 = LV_VER_RES - 1;
/*Flush the content of the VDB*/
lv_vdb_flush();
/* With true double buffering the flushing should be only the address change of the current frame buffer
* Wait until the address change is ready and copy the active content to the other frame buffer (new active VDB)
* The changes will be written to the new VDB.*/
lv_vdb_t * vdb_act = lv_vdb_get_active();
lv_vdb_t * vdb_ina = lv_vdb_get_inactive();
uint8_t * buf_act = (uint8_t *) vdb_act->buf;
uint8_t * buf_ina = (uint8_t *) vdb_ina->buf;
uint16_t a;
for(a = 0; a < inv_buf_p; a++) {
if(inv_buf[a].joined == 0) {
lv_coord_t y;
uint32_t start_offs = ((LV_HOR_RES * inv_buf[a].area.y1 + inv_buf[a].area.x1) * LV_VDB_PX_BPP) >> 3;
uint32_t line_length = (lv_area_get_width(&inv_buf[a].area) * LV_VDB_PX_BPP) >> 3;
for(y = inv_buf[a].area.y1; y <= inv_buf[a].area.y2; y++) {
memcpy(buf_act + start_offs, buf_ina + start_offs, line_length);
start_offs += (LV_HOR_RES * LV_VDB_PX_BPP) >> 3;
}
}
}
#endif
/*Clean up*/
memset(inv_buf, 0, sizeof(inv_buf));
inv_buf_p = 0;
/*Call monitor cb if present*/
if(monitor_cb != NULL) {
monitor_cb(lv_tick_elaps(start), px_num);
}
}
LV_LOG_TRACE("display refresh task finished");
}
/**
* Join the areas which has got common parts
*/
static void lv_refr_join_area(void)
{
uint32_t join_from;
uint32_t join_in;
lv_area_t joined_area;
for(join_in = 0; join_in < inv_buf_p; join_in++) {
if(inv_buf[join_in].joined != 0) continue;
/*Check all areas to join them in 'join_in'*/
for(join_from = 0; join_from < inv_buf_p; join_from++) {
/*Handle only unjoined areas and ignore itself*/
if(inv_buf[join_from].joined != 0 || join_in == join_from) {
continue;
}
/*Check if the areas are on each other*/
if(lv_area_is_on(&inv_buf[join_in].area,
&inv_buf[join_from].area) == false) {
continue;
}
lv_area_join(&joined_area, &inv_buf[join_in].area,
&inv_buf[join_from].area);
/*Join two area only if the joined area size is smaller*/
if(lv_area_get_size(&joined_area) <
(lv_area_get_size(&inv_buf[join_in].area) + lv_area_get_size(&inv_buf[join_from].area))) {
lv_area_copy(&inv_buf[join_in].area, &joined_area);
/*Mark 'join_form' is joined into 'join_in'*/
inv_buf[join_from].joined = 1;
}
}
}
}
/**
* Refresh the joined areas
*/
static void lv_refr_areas(void)
{
px_num = 0;
uint32_t i;
for(i = 0; i < inv_buf_p; i++) {
/*Refresh the unjoined areas*/
if(inv_buf[i].joined == 0) {
/*If there is no VDB do simple drawing*/
#if LV_VDB_SIZE == 0
lv_refr_area_no_vdb(&inv_buf[i].area);
#else
/*If VDB is used...*/
lv_refr_area_with_vdb(&inv_buf[i].area);
#endif
if(monitor_cb != NULL) px_num += lv_area_get_size(&inv_buf[i].area);
}
}
}
#if LV_VDB_SIZE == 0
/**
* Refresh an area if there is no Virtual Display Buffer
* @param area_p pointer to an area to refresh
*/
static void lv_refr_area_no_vdb(const lv_area_t * area_p)
{
lv_obj_t * top_p;
/*Get top object which is not covered by others*/
top_p = lv_refr_get_top_obj(area_p, lv_scr_act());
/*Do the refreshing*/
lv_refr_obj_and_children(top_p, area_p);
/*Also refresh top and sys layer unconditionally*/
lv_refr_obj_and_children(lv_layer_top(), area_p);
lv_refr_obj_and_children(lv_layer_sys(), area_p);
}
#else
/**
* Refresh an area if there is Virtual Display Buffer
* @param area_p pointer to an area to refresh
*/
static void lv_refr_area_with_vdb(const lv_area_t * area_p)
{
#if LV_VDB_TRUE_DOUBLE_BUFFERED == 0
/*Calculate the max row num*/
lv_coord_t w = lv_area_get_width(area_p);
lv_coord_t h = lv_area_get_height(area_p);
lv_coord_t y2 = area_p->y2 >= LV_VER_RES ? y2 = LV_VER_RES - 1 : area_p->y2;
int32_t max_row = (uint32_t) LV_VDB_SIZE / w;
if(max_row > h) max_row = h;
/*Round down the lines of VDB if rounding is added*/
if(round_cb) {
lv_area_t tmp;
tmp.x1 = 0;
tmp.x2 = 0;
tmp.y1 = 0;
lv_coord_t y_tmp = max_row - 1;
do {
tmp.y2 = y_tmp;
round_cb(&tmp);
/*If this height fits into `max_row` then fine*/
if(lv_area_get_height(&tmp) <= max_row) break;
/*Decrement the height of the area until it fits into `max_row` after rounding*/
y_tmp --;
} while(y_tmp != 0);
if(y_tmp == 0) {
LV_LOG_WARN("Can't set VDB height using the round function. (Wrong round_cb or to small VDB)");
return;
} else {
max_row = tmp.y2 + 1;
}
}
/*Always use the full row*/
lv_coord_t row;
lv_coord_t row_last = 0;
for(row = area_p->y1; row + max_row - 1 <= y2; row += max_row) {
lv_vdb_t * vdb_p = lv_vdb_get();
if(!vdb_p) {
LV_LOG_WARN("Invalid VDB pointer");
return;
}
/*Calc. the next y coordinates of VDB*/
vdb_p->area.x1 = area_p->x1;
vdb_p->area.x2 = area_p->x2;
vdb_p->area.y1 = row;
vdb_p->area.y2 = row + max_row - 1;
if(vdb_p->area.y2 > y2) vdb_p->area.y2 = y2;
row_last = vdb_p->area.y2;
lv_refr_area_part_vdb(area_p);
}
/*If the last y coordinates are not handled yet ...*/
if(y2 != row_last) {
lv_vdb_t * vdb_p = lv_vdb_get();
if(!vdb_p) {
LV_LOG_WARN("Invalid VDB pointer");
return;
}
/*Calc. the next y coordinates of VDB*/
vdb_p->area.x1 = area_p->x1;
vdb_p->area.x2 = area_p->x2;
vdb_p->area.y1 = row;
vdb_p->area.y2 = y2;
/*Refresh this part too*/
lv_refr_area_part_vdb(area_p);
}
#else
lv_vdb_t * vdb_p = lv_vdb_get();
vdb_p->area.x1 = 0;
vdb_p->area.x2 = LV_HOR_RES-1;
vdb_p->area.y1 = 0;
vdb_p->area.y2 = LV_VER_RES - 1;
lv_refr_area_part_vdb(area_p);
#endif
}
/**
* Refresh a part of an area which is on the actual Virtual Display Buffer
* @param area_p pointer to an area to refresh
*/
static void lv_refr_area_part_vdb(const lv_area_t * area_p)
{
lv_vdb_t * vdb_p = lv_vdb_get();
if(!vdb_p) {
LV_LOG_WARN("Invalid VDB pointer");
return;
}
lv_obj_t * top_p;
/*Get the new mask from the original area and the act. VDB
It will be a part of 'area_p'*/
lv_area_t start_mask;
lv_area_intersect(&start_mask, area_p, &vdb_p->area);
/*Get the most top object which is not covered by others*/
top_p = lv_refr_get_top_obj(&start_mask, lv_scr_act());
/*Do the refreshing from the top object*/
lv_refr_obj_and_children(top_p, &start_mask);
/*Also refresh top and sys layer unconditionally*/
lv_refr_obj_and_children(lv_layer_top(), &start_mask);
lv_refr_obj_and_children(lv_layer_sys(), &start_mask);
/* In true double buffered mode flush only once when all areas were rendered.
* In normal mode flush after every area */
#if LV_VDB_TRUE_DOUBLE_BUFFERED == 0
/*Flush the content of the VDB*/
lv_vdb_flush();
#endif
}
#endif /*LV_VDB_SIZE == 0*/
/**
* Search the most top object which fully covers an area
* @param area_p pointer to an area
* @param obj the first object to start the searching (typically a screen)
* @return
*/
static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj)
{
lv_obj_t * i;
lv_obj_t * found_p = NULL;
/*If this object is fully cover the draw area check the children too */
if(lv_area_is_in(area_p, &obj->coords) && obj->hidden == 0) {
LL_READ(obj->child_ll, i) {
found_p = lv_refr_get_top_obj(area_p, i);
/*If a children is ok then break*/
if(found_p != NULL) {
break;
}
}
/*If no better children check this object*/
if(found_p == NULL) {
lv_style_t * style = lv_obj_get_style(obj);
if(style->body.opa == LV_OPA_COVER &&
obj->design_func(obj, area_p, LV_DESIGN_COVER_CHK) != false &&
lv_obj_get_opa_scale(obj) == LV_OPA_COVER) {
found_p = obj;
}
}
}
return found_p;
}
/**
* Make the refreshing from an object. Draw all its children and the youngers too.
* @param top_p pointer to an objects. Start the drawing from it.
* @param mask_p pointer to an area, the objects will be drawn only here
*/
static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p)
{
/* Normally always will be a top_obj (at least the screen)
* but in special cases (e.g. if the screen has alpha) it won't.
* In this case use the screen directly */
if(top_p == NULL) top_p = lv_scr_act();
/*Refresh the top object and its children*/
lv_refr_obj(top_p, mask_p);
/*Draw the 'younger' sibling objects because they can be on top_obj */
lv_obj_t * par;
lv_obj_t * i;
lv_obj_t * border_p = top_p;
par = lv_obj_get_parent(top_p);
/*Do until not reach the screen*/
while(par != NULL) {
/*object before border_p has to be redrawn*/
i = lv_ll_get_prev(&(par->child_ll), border_p);
while(i != NULL) {
/*Refresh the objects*/
lv_refr_obj(i, mask_p);
i = lv_ll_get_prev(&(par->child_ll), i);
}
/*The new border will be there last parents,
*so the 'younger' brothers of parent will be refreshed*/
border_p = par;
/*Go a level deeper*/
par = lv_obj_get_parent(par);
}
/*Call the post draw design function of the parents of the to object*/
par = lv_obj_get_parent(top_p);
while(par != NULL) {
par->design_func(par, mask_p, LV_DESIGN_DRAW_POST);
par = lv_obj_get_parent(par);
}
}
/**
* Refresh an object an all of its children. (Called recursively)
* @param obj pointer to an object to refresh
* @param mask_ori_p pointer to an area, the objects will be drawn only here
*/
static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p)
{
/*Do not refresh hidden objects*/
if(obj->hidden != 0) return;
bool union_ok; /* Store the return value of area_union */
/* Truncate the original mask to the coordinates of the parent
* because the parent and its children are visible only here */
lv_area_t obj_mask;
lv_area_t obj_ext_mask;
lv_area_t obj_area;
lv_coord_t ext_size = obj->ext_size;
lv_obj_get_coords(obj, &obj_area);
obj_area.x1 -= ext_size;
obj_area.y1 -= ext_size;
obj_area.x2 += ext_size;
obj_area.y2 += ext_size;
union_ok = lv_area_intersect(&obj_ext_mask, mask_ori_p, &obj_area);
/*Draw the parent and its children only if they ore on 'mask_parent'*/
if(union_ok != false) {
/* Redraw the object */
obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_MAIN);
//usleep(5 * 1000); /*DEBUG: Wait after every object draw to see the order of drawing*/
/*Create a new 'obj_mask' without 'ext_size' because the children can't be visible there*/
lv_obj_get_coords(obj, &obj_area);
union_ok = lv_area_intersect(&obj_mask, mask_ori_p, &obj_area);
if(union_ok != false) {
lv_area_t mask_child; /*Mask from obj and its child*/
lv_obj_t * child_p;
lv_area_t child_area;
LL_READ_BACK(obj->child_ll, child_p) {
lv_obj_get_coords(child_p, &child_area);
ext_size = child_p->ext_size;
child_area.x1 -= ext_size;
child_area.y1 -= ext_size;
child_area.x2 += ext_size;
child_area.y2 += ext_size;
/* Get the union (common parts) of original mask (from obj)
* and its child */
union_ok = lv_area_intersect(&mask_child, &obj_mask, &child_area);
/*If the parent and the child has common area then refresh the child */
if(union_ok) {
/*Refresh the next children*/
lv_refr_obj(child_p, &mask_child);
}
}
}
/* If all the children are redrawn make 'post draw' design */
obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_POST);
}
}

View File

@ -0,0 +1,94 @@
/**
* @file lv_refr.h
*
*/
#ifndef LV_REFR_H
#define LV_REFR_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_obj.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the screen refresh subsystem
*/
void lv_refr_init(void);
/**
* Redraw the invalidated areas now.
* Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process can
* prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar)
* this function can be called when the screen should be updated.
*/
void lv_refr_now(void);
/**
* Invalidate an area
* @param area_p pointer to area which should be invalidated
*/
void lv_inv_area(const lv_area_t * area_p);
/**
* Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels
* @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num))
*/
void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t));
/**
* Called when an area is invalidated to modify the coordinates of the area.
* Special display controllers may require special coordinate rounding
* @param cb pointer to the a function which will modify the area
*/
void lv_refr_set_round_cb(void(*cb)(lv_area_t*));
/**
* Get the number of areas in the buffer
* @return number of invalid areas
*/
uint16_t lv_refr_get_buf_size(void);
/**
* Pop (delete) the last 'num' invalidated areas from the buffer
* @param num number of areas to delete
*/
void lv_refr_pop_from_buf(uint16_t num);
/**********************
* STATIC FUNCTIONS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_REFR_H*/

View File

@ -0,0 +1,357 @@
/*
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*********************
* INCLUDES
*********************/
#include "lv_obj.h"
#include "../lv_misc/lv_mem.h"
/*********************
* DEFINES
*********************/
#define STYLE_MIX_MAX 256
#define STYLE_MIX_SHIFT 8 /*log2(STYLE_MIX_MAX)*/
#define VAL_PROP(v1, v2, r) v1 + (((v2-v1) * r) >> STYLE_MIX_SHIFT)
#define STYLE_ATTR_MIX(attr, r) if(start->attr != end->attr) {res->attr = VAL_PROP(start->attr, end->attr, r);} else {res->attr = start->attr;}
/**********************
* TYPEDEFS
**********************/
#if USE_LV_ANIMATION
typedef struct {
lv_style_t style_start; /*Save not only pointers because can be same as 'style_anim' then it will be modified too*/
lv_style_t style_end;
lv_style_t * style_anim;
void (*end_cb)(void *);
} lv_style_anim_dsc_t;
#endif
/**********************
* STATIC PROTOTYPES
**********************/
#if USE_LV_ANIMATION
static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val);
static void style_animation_common_end_cb(void * ptr);
#endif
/**********************
* STATIC VARIABLES
**********************/
lv_style_t lv_style_scr;
lv_style_t lv_style_transp;
lv_style_t lv_style_transp_fit;
lv_style_t lv_style_transp_tight;
lv_style_t lv_style_plain;
lv_style_t lv_style_plain_color;
lv_style_t lv_style_pretty;
lv_style_t lv_style_pretty_color;
lv_style_t lv_style_btn_rel;
lv_style_t lv_style_btn_pr;
lv_style_t lv_style_btn_tgl_rel;
lv_style_t lv_style_btn_tgl_pr;
lv_style_t lv_style_btn_ina;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Init the basic styles
*/
void lv_style_init(void)
{
/* Not White/Black/Gray colors are created by HSV model with
* HUE = 210*/
/*Screen style*/
lv_style_scr.glass = 0;
lv_style_scr.body.opa = LV_OPA_COVER;
lv_style_scr.body.main_color = LV_COLOR_BLACK;
lv_style_scr.body.grad_color = LV_COLOR_BLACK;
lv_style_scr.body.radius = 0;
lv_style_scr.body.padding.ver = LV_DPI / 12;
lv_style_scr.body.padding.hor = LV_DPI / 12;
lv_style_scr.body.padding.inner = LV_DPI / 12;
lv_style_scr.body.border.color = LV_COLOR_WHITE;
lv_style_scr.body.border.opa = LV_OPA_COVER;
lv_style_scr.body.border.width = 0;
lv_style_scr.body.border.part = LV_BORDER_FULL;
lv_style_scr.body.shadow.color = LV_COLOR_GRAY;
lv_style_scr.body.shadow.type = LV_SHADOW_FULL;
lv_style_scr.body.shadow.width = 0;
lv_style_scr.text.opa = LV_OPA_COVER;
lv_style_scr.text.color = LV_COLOR_HEX(0xFBFBFB);
lv_style_scr.text.font = LV_FONT_DEFAULT;
lv_style_scr.text.letter_space = 3; // Important
lv_style_scr.text.line_space = 2;
lv_style_scr.image.opa = LV_OPA_COVER;
lv_style_scr.image.color = LV_COLOR_MAKE(0x20, 0x20, 0x20);
lv_style_scr.image.intense = LV_OPA_TRANSP;
lv_style_scr.line.opa = LV_OPA_COVER;
lv_style_scr.line.color = LV_COLOR_MAKE(0x20, 0x20, 0x20);
lv_style_scr.line.width = 2;
lv_style_scr.line.rounded = 0;
/*Plain style (by default near the same as the screen style)*/
memcpy(&lv_style_plain, &lv_style_scr, sizeof(lv_style_t));
/*Plain color style*/
memcpy(&lv_style_plain_color, &lv_style_plain, sizeof(lv_style_t));
lv_style_plain_color.text.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0);
lv_style_plain_color.image.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0);
lv_style_plain_color.line.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0);
lv_style_plain_color.body.main_color = LV_COLOR_MAKE(0x55, 0x96, 0xd8);
lv_style_plain_color.body.grad_color = lv_style_plain_color.body.main_color;
/*Pretty style */
memcpy(&lv_style_pretty, &lv_style_plain, sizeof(lv_style_t));
lv_style_pretty.text.color = LV_COLOR_MAKE(0x20, 0x20, 0x20);
lv_style_pretty.image.color = LV_COLOR_MAKE(0x20, 0x20, 0x20);
lv_style_pretty.line.color = LV_COLOR_MAKE(0x20, 0x20, 0x20);
lv_style_pretty.body.main_color = LV_COLOR_WHITE;
lv_style_pretty.body.grad_color = LV_COLOR_SILVER;
lv_style_pretty.body.radius = LV_DPI / 15;
lv_style_pretty.body.border.color = LV_COLOR_MAKE(0x40, 0x40, 0x40);
lv_style_pretty.body.border.width = LV_DPI / 50 >= 1 ? LV_DPI / 50 : 1;
lv_style_pretty.body.border.opa = LV_OPA_30;
/*Pretty color style*/
memcpy(&lv_style_pretty_color, &lv_style_pretty, sizeof(lv_style_t));
lv_style_pretty_color.text.color = LV_COLOR_MAKE(0xe0, 0xe0, 0xe0);
lv_style_pretty_color.image.color = LV_COLOR_MAKE(0xe0, 0xe0, 0xe0);
lv_style_pretty_color.line.color = LV_COLOR_MAKE(0xc0, 0xc0, 0xc0);
lv_style_pretty_color.body.main_color = LV_COLOR_MAKE(0x6b, 0x9a, 0xc7);
lv_style_pretty_color.body.grad_color = LV_COLOR_MAKE(0x2b, 0x59, 0x8b);
lv_style_pretty_color.body.border.color = LV_COLOR_MAKE(0x15, 0x2c, 0x42);
/*Transparent style*/
memcpy(&lv_style_transp, &lv_style_plain, sizeof(lv_style_t));
lv_style_transp.body.empty = 1;
lv_style_transp.glass = 1;
lv_style_transp.body.border.width = 0;
/*Transparent fitting size*/
memcpy(&lv_style_transp_fit, &lv_style_transp, sizeof(lv_style_t));
lv_style_transp_fit.body.padding.hor = 0;
lv_style_transp_fit.body.padding.ver = 0;
/*Transparent tight style*/
memcpy(&lv_style_transp_tight, &lv_style_transp_fit, sizeof(lv_style_t));
lv_style_transp_tight.body.padding.inner = 0;
/*Button released style*/
memcpy(&lv_style_btn_rel, &lv_style_plain, sizeof(lv_style_t));
lv_style_btn_rel.body.main_color = LV_COLOR_MAKE(0x76, 0xa2, 0xd0);
lv_style_btn_rel.body.grad_color = LV_COLOR_MAKE(0x19, 0x3a, 0x5d);
lv_style_btn_rel.body.radius = LV_DPI / 15;
lv_style_btn_rel.body.padding.hor = LV_DPI / 4;
lv_style_btn_rel.body.padding.ver = LV_DPI / 6;
lv_style_btn_rel.body.padding.inner = LV_DPI / 10;
lv_style_btn_rel.body.border.color = LV_COLOR_MAKE(0x0b, 0x19, 0x28);
lv_style_btn_rel.body.border.width = LV_DPI / 50 >= 1 ? LV_DPI / 50 : 1;
lv_style_btn_rel.body.border.opa = LV_OPA_70;
lv_style_btn_rel.body.shadow.color = LV_COLOR_GRAY;
lv_style_btn_rel.body.shadow.width = 0;
lv_style_btn_rel.text.color = LV_COLOR_MAKE(0xff, 0xff, 0xff);
lv_style_btn_rel.image.color = LV_COLOR_MAKE(0xff, 0xff, 0xff);
/*Button pressed style*/
memcpy(&lv_style_btn_pr, &lv_style_btn_rel, sizeof(lv_style_t));
lv_style_btn_pr.body.main_color = LV_COLOR_MAKE(0x33, 0x62, 0x94);
lv_style_btn_pr.body.grad_color = LV_COLOR_MAKE(0x10, 0x26, 0x3c);
lv_style_btn_pr.text.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6);
lv_style_btn_pr.image.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6);
lv_style_btn_pr.line.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6);
/*Button toggle released style*/
memcpy(&lv_style_btn_tgl_rel, &lv_style_btn_rel, sizeof(lv_style_t));
lv_style_btn_tgl_rel.body.main_color = LV_COLOR_MAKE(0x0a, 0x11, 0x22);
lv_style_btn_tgl_rel.body.grad_color = LV_COLOR_MAKE(0x37, 0x62, 0x90);
lv_style_btn_tgl_rel.body.border.color = LV_COLOR_MAKE(0x01, 0x07, 0x0d);
lv_style_btn_tgl_rel.text.color = LV_COLOR_MAKE(0xc8, 0xdd, 0xf4);
lv_style_btn_tgl_rel.image.color = LV_COLOR_MAKE(0xc8, 0xdd, 0xf4);
lv_style_btn_tgl_rel.line.color = LV_COLOR_MAKE(0xc8, 0xdd, 0xf4);
/*Button toggle pressed style*/
memcpy(&lv_style_btn_tgl_pr, &lv_style_btn_tgl_rel, sizeof(lv_style_t));
lv_style_btn_tgl_pr.body.main_color = LV_COLOR_MAKE(0x02, 0x14, 0x27);
lv_style_btn_tgl_pr.body.grad_color = LV_COLOR_MAKE(0x2b, 0x4c, 0x70);
lv_style_btn_tgl_pr.text.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6);
lv_style_btn_tgl_pr.image.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6);
lv_style_btn_tgl_pr.line.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6);
/*Button inactive style*/
memcpy(&lv_style_btn_ina, &lv_style_btn_rel, sizeof(lv_style_t));
lv_style_btn_ina.body.main_color = LV_COLOR_MAKE(0xd8, 0xd8, 0xd8);
lv_style_btn_ina.body.grad_color = LV_COLOR_MAKE(0xd8, 0xd8, 0xd8);
lv_style_btn_ina.body.border.color = LV_COLOR_MAKE(0x90, 0x90, 0x90);
lv_style_btn_ina.text.color = LV_COLOR_MAKE(0x70, 0x70, 0x70);
lv_style_btn_ina.image.color = LV_COLOR_MAKE(0x70, 0x70, 0x70);
lv_style_btn_ina.line.color = LV_COLOR_MAKE(0x70, 0x70, 0x70);
}
/**
* Copy a style to an other
* @param dest pointer to the destination style
* @param src pointer to the source style
*/
void lv_style_copy(lv_style_t * dest, const lv_style_t * src)
{
memcpy(dest, src, sizeof(lv_style_t));
}
/**
* Mix two styles according to a given ratio
* @param start start style
* @param end end style
* @param res store the result style here
* @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style
*/
void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio)
{
STYLE_ATTR_MIX(body.opa, ratio);
STYLE_ATTR_MIX(body.radius, ratio);
STYLE_ATTR_MIX(body.border.width, ratio);
STYLE_ATTR_MIX(body.border.opa, ratio);
STYLE_ATTR_MIX(body.shadow.width, ratio);
STYLE_ATTR_MIX(body.padding.hor, ratio);
STYLE_ATTR_MIX(body.padding.ver, ratio);
STYLE_ATTR_MIX(body.padding.inner, ratio);
STYLE_ATTR_MIX(text.line_space, ratio);
STYLE_ATTR_MIX(text.letter_space, ratio);
STYLE_ATTR_MIX(text.opa, ratio);
STYLE_ATTR_MIX(line.width, ratio);
STYLE_ATTR_MIX(line.opa, ratio);
STYLE_ATTR_MIX(image.intense, ratio);
STYLE_ATTR_MIX(image.opa, ratio);
lv_opa_t opa = ratio == STYLE_MIX_MAX ? LV_OPA_COVER : ratio;
res->body.main_color = lv_color_mix(end->body.main_color, start->body.main_color, opa);
res->body.grad_color = lv_color_mix(end->body.grad_color, start->body.grad_color, opa);
res->body.border.color = lv_color_mix(end->body.border.color, start->body.border.color, opa);
res->body.shadow.color = lv_color_mix(end->body.shadow.color, start->body.shadow.color, opa);
res->text.color = lv_color_mix(end->text.color, start->text.color, opa);
res->image.color = lv_color_mix(end->image.color, start->image.color, opa);
res->line.color = lv_color_mix(end->line.color, start->line.color, opa);
if(ratio < (STYLE_MIX_MAX >> 1)) {
res->body.empty = start->body.empty;
res->body.border.part = start->body.border.part;
res->glass = start->glass;
res->text.font = start->text.font;
res->body.shadow.type = start->body.shadow.type;
res->line.rounded = start->line.rounded;
} else {
res->body.empty = end->body.empty;
res->body.border.part = end->body.border.part;
res->glass = end->glass;
res->text.font = end->text.font;
res->body.shadow.type = end->body.shadow.type;
res->line.rounded = end->line.rounded;
}
}
#if USE_LV_ANIMATION
/**
* Create an animation from a pre-configured 'lv_style_anim_t' variable
* @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied)
* @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`)
*/
void * lv_style_anim_create(lv_style_anim_t * anim)
{
lv_style_anim_dsc_t * dsc;
dsc = lv_mem_alloc(sizeof(lv_style_anim_dsc_t));
lv_mem_assert(dsc);
if(dsc == NULL) return NULL;
dsc->style_anim = anim->style_anim;
memcpy(&dsc->style_start, anim->style_start, sizeof(lv_style_t));
memcpy(&dsc->style_end, anim->style_end, sizeof(lv_style_t));
memcpy(dsc->style_anim, anim->style_start, sizeof(lv_style_t));
dsc->end_cb = anim->end_cb;
lv_anim_t a;
a.var = (void *)dsc;
a.start = 0;
a.end = STYLE_MIX_MAX;
a.fp = (lv_anim_fp_t)style_animator;
a.path = lv_anim_path_linear;
a.end_cb = style_animation_common_end_cb;
a.act_time = anim->act_time;
a.time = anim->time;
a.playback = anim->playback;
a.playback_pause = anim->playback_pause;
a.repeat = anim->repeat;
a.repeat_pause = anim->repeat_pause;
lv_anim_create(&a);
return dsc;
}
#endif
/**********************
* STATIC FUNCTIONS
**********************/
#if USE_LV_ANIMATION
/**
* Used by the style animations to set the values of a style according to start and end style.
* @param dsc the 'animated variable' set by lv_style_anim_create()
* @param val the current state of the animation between 0 and LV_STYLE_ANIM_RES
*/
static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val)
{
const lv_style_t * start = &dsc->style_start;
const lv_style_t * end = &dsc->style_end;
lv_style_t * act = dsc->style_anim;
lv_style_mix(start, end, act, val);
lv_obj_report_style_mod(dsc->style_anim);
}
/**
* Called when a style animation is ready
* It called the user defined call back and free the allocated memories
* @param ptr the 'animated variable' set by lv_style_anim_create()
*/
static void style_animation_common_end_cb(void * ptr)
{
lv_style_anim_dsc_t * dsc = ptr; /*To avoid casting*/
if(dsc->end_cb) dsc->end_cb(dsc);
lv_mem_free(dsc);
}
#endif

View File

@ -0,0 +1,198 @@
/**
* @file lv_style.h
*
*/
#ifndef LV_STYLE_H
#define LV_STYLE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_area.h"
#include "../lv_misc/lv_font.h"
#include "../lv_misc/lv_anim.h"
/*********************
* DEFINES
*********************/
#define LV_RADIUS_CIRCLE (LV_COORD_MAX) /*A very big radius to always draw as circle*/
/**********************
* TYPEDEFS
**********************/
/*Border types (Use 'OR'ed values)*/
enum
{
LV_BORDER_NONE = 0x00,
LV_BORDER_BOTTOM = 0x01,
LV_BORDER_TOP = 0x02,
LV_BORDER_LEFT = 0x04,
LV_BORDER_RIGHT = 0x08,
LV_BORDER_FULL = 0x0F,
LV_BORDER_INTERNAL = 0x10, /*FOR matrix-like objects (e.g. Button matrix)*/
};
typedef uint8_t lv_border_part_t;
/*Shadow types*/
enum
{
LV_SHADOW_BOTTOM = 0,
LV_SHADOW_FULL,
};
typedef uint8_t lv_shadow_type_t;
typedef struct
{
uint8_t glass :1; /*1: Do not inherit this style*/
struct {
lv_color_t main_color;
lv_color_t grad_color; /*`grad_color` will be removed in v6.0, use `aux_color` instead*/
lv_coord_t radius;
lv_opa_t opa;
struct {
lv_color_t color;
lv_coord_t width;
lv_border_part_t part;
lv_opa_t opa;
} border;
struct {
lv_color_t color;
lv_coord_t width;
lv_shadow_type_t type;
} shadow;
struct {
lv_coord_t ver;
lv_coord_t hor;
lv_coord_t inner;
} padding;
uint8_t empty :1; /*Transparent background (border still drawn)*/
} body;
struct {
lv_color_t color;
const lv_font_t * font;
lv_coord_t letter_space;
lv_coord_t line_space;
lv_opa_t opa;
} text;
struct {
lv_color_t color;
lv_opa_t intense;
lv_opa_t opa;
} image;
struct {
lv_color_t color;
lv_coord_t width;
lv_opa_t opa;
uint8_t rounded :1; /*1: rounded line endings*/
} line;
} lv_style_t;
#if USE_LV_ANIMATION
typedef struct {
const lv_style_t * style_start; /*Pointer to the starting style*/
const lv_style_t * style_end; /*Pointer to the destination style*/
lv_style_t * style_anim; /*Pointer to a style to animate*/
lv_anim_cb_t end_cb; /*Call it when the animation is ready (NULL if unused)*/
int16_t time; /*Animation time in ms*/
int16_t act_time; /*Current time in animation. Set to negative to make delay.*/
uint16_t playback_pause; /*Wait before play back*/
uint16_t repeat_pause; /*Wait before repeat*/
uint8_t playback :1; /*When the animation is ready play it back*/
uint8_t repeat :1; /*Repeat the animation infinitely*/
} lv_style_anim_t;
/* Example initialization
lv_style_anim_t a;
a.style_anim = &style_to_anim;
a.style_start = &style_1;
a.style_end = &style_2;
a.act_time = 0;
a.time = 1000;
a.playback = 0;
a.playback_pause = 0;
a.repeat = 0;
a.repeat_pause = 0;
a.end_cb = NULL;
lv_style_anim_create(&a);
*/
#endif
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Init the basic styles
*/
void lv_style_init (void);
/**
* Copy a style to an other
* @param dest pointer to the destination style
* @param src pointer to the source style
*/
void lv_style_copy(lv_style_t * dest, const lv_style_t * src);
/**
* Mix two styles according to a given ratio
* @param start start style
* @param end end style
* @param res store the result style here
* @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style
*/
void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio);
#if USE_LV_ANIMATION
/**
* Create an animation from a pre-configured 'lv_style_anim_t' variable
* @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied)
* @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`)
*/
void * lv_style_anim_create(lv_style_anim_t * anim);
#endif
/*************************
* GLOBAL VARIABLES
*************************/
extern lv_style_t lv_style_scr;
extern lv_style_t lv_style_transp;
extern lv_style_t lv_style_transp_fit;
extern lv_style_t lv_style_transp_tight;
extern lv_style_t lv_style_plain;
extern lv_style_t lv_style_plain_color;
extern lv_style_t lv_style_pretty;
extern lv_style_t lv_style_pretty_color;
extern lv_style_t lv_style_btn_rel;
extern lv_style_t lv_style_btn_pr;
extern lv_style_t lv_style_btn_tgl_rel;
extern lv_style_t lv_style_btn_tgl_pr;
extern lv_style_t lv_style_btn_ina;
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_STYLE_H*/

View File

@ -0,0 +1,207 @@
/**
* @file lv_vdb.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_vdb.h"
#if LV_VDB_SIZE != 0
#include "../lv_hal/lv_hal_disp.h"
#include "../lv_misc/lv_log.h"
#include <stddef.h>
/*********************
* DEFINES
*********************/
#ifndef LV_ATTRIBUTE_FLUSH_READY
#define LV_ATTRIBUTE_FLUSH_READY
#endif
#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/*Simple VDB*/
#if LV_VDB_DOUBLE == 0
# if LV_VDB_ADR == 0
/*If the buffer address is not specified simply allocate it*/
static LV_ATTRIBUTE_MEM_ALIGN uint8_t vdb_buf[LV_VDB_SIZE_IN_BYTES];
static lv_vdb_t vdb = {.buf = (lv_color_t *)vdb_buf};
# else /*LV_VDB_ADR != 0*/
/*If the buffer address is specified use that address*/
static lv_vdb_t vdb = {.buf = (lv_color_t *)LV_VDB_ADR};
# endif
/*LV_VDB_DOUBLE != 0*/
#else
/*Double VDB*/
static uint8_t vdb_active = 0;
# if LV_VDB_ADR == 0
/*If the buffer address is not specified simply allocate it*/
static LV_ATTRIBUTE_MEM_ALIGN uint8_t vdb_buf1[LV_VDB_SIZE_IN_BYTES];
static LV_ATTRIBUTE_MEM_ALIGN uint8_t vdb_buf2[LV_VDB_SIZE_IN_BYTES];
static lv_vdb_t vdb[2] = {{.buf = (lv_color_t *) vdb_buf1}, {.buf = (lv_color_t *) vdb_buf2}};
# else /*LV_VDB_ADR != 0*/
/*If the buffer address is specified use that address*/
static lv_vdb_t vdb[2] = {{.buf = (lv_color_t *)LV_VDB_ADR}, {.buf = (lv_color_t *)LV_VDB2_ADR}};
# endif
#endif
static volatile bool vdb_flushing = false;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode
* @return pointer to a 'vdb' variable
*/
lv_vdb_t * lv_vdb_get(void)
{
#if LV_VDB_DOUBLE == 0
/* Wait until VDB is flushing.
* (Until this user calls of 'lv_flush_ready()' in the display drivers's flush function*/
while(vdb_flushing);
return &vdb;
#else
/*If already there is an active do nothing*/
return &vdb[vdb_active];
#endif
}
/**
* Flush the content of the VDB
*/
void lv_vdb_flush(void)
{
lv_vdb_t * vdb_act = lv_vdb_get();
if(!vdb_act) {
LV_LOG_WARN("Invalid VDB pointer");
return;
}
/*Don't start a new flush while the previous is not finished*/
#if LV_VDB_DOUBLE
while(vdb_flushing);
#endif /*LV_VDB_DOUBLE*/
vdb_flushing = true;
/*Flush the rendered content to the display*/
lv_disp_flush(vdb_act->area.x1, vdb_act->area.y1, vdb_act->area.x2, vdb_act->area.y2, vdb_act->buf);
#if LV_VDB_DOUBLE
/*Make the other VDB active. The content of the current will be kept until the next flush*/
vdb_active++;
vdb_active &= 0x1;
/*If the screen is transparent initialize it when the new VDB is selected*/
# if LV_COLOR_SCREEN_TRANSP
memset(vdb[vdb_active].buf, 0x00, LV_VDB_SIZE_IN_BYTES);
# endif /*LV_COLOR_SCREEN_TRANSP*/
#endif /*#if LV_VDB_DOUBLE*/
}
/**
* Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`.
* It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES`
* @param buf1 address of the VDB.
* @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0`
*/
void lv_vdb_set_adr(void * buf1, void * buf2)
{
#if LV_VDB_DOUBLE == 0
(void) buf2; /*unused*/
vdb.buf = buf1;
#else
vdb[0].buf = buf1;
vdb[1].buf = buf2;
#endif
}
/**
* Call in the display driver's 'disp_flush' function when the flushing is finished
*/
LV_ATTRIBUTE_FLUSH_READY void lv_flush_ready(void)
{
vdb_flushing = false;
/*If the screen is transparent initialize it when the flushing is ready*/
#if LV_VDB_DOUBLE == 0 && LV_COLOR_SCREEN_TRANSP
memset(vdb_buf, 0x00, LV_VDB_SIZE_IN_BYTES);
#endif
}
/**
* Get currently active VDB, where the drawing happens. Used with `LV_VDB_DOUBLE 1`
* @return pointer to the active VDB. If `LV_VDB_DOUBLE 0` give the single VDB
*/
lv_vdb_t * lv_vdb_get_active(void)
{
#if LV_VDB_DOUBLE == 0
return &vdb;
#else
return &vdb[vdb_active];
#endif
}
/**
* Get currently inactive VDB, which is being displayed or being flushed. Used with `LV_VDB_DOUBLE 1`
* @return pointer to the inactive VDB. If `LV_VDB_DOUBLE 0` give the single VDB
*/
lv_vdb_t * lv_vdb_get_inactive(void)
{
#if LV_VDB_DOUBLE == 0
return &vdb;
#else
return &vdb[(vdb_active + 1) & 0x1];
#endif
}
/**
* Whether the flushing is in progress or not
* @return true: flushing is in progress; false: flushing ready
*/
bool lv_vdb_is_flushing(void)
{
return vdb_flushing;
}
/**********************
* STATIC FUNCTIONS
**********************/
#else
/**
* Just for compatibility
*/
void lv_flush_ready(void)
{
/*Do nothing. It is used only for VDB*/
}
#endif

View File

@ -0,0 +1,119 @@
/**
* @file lv_vdb.h
*
*/
#ifndef LV_VDB_H
#define LV_VDB_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_conf.h"
#else
#include "../../lv_conf.h"
#endif
#if LV_VDB_SIZE != 0
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_area.h"
/*********************
* DEFINES
*********************/
/*Can be used in `lv_conf.h` the set an invalid address for the VDB. It should be replaced later by a valid address using `lv_vdb_set_adr()`*/
#define LV_VDB_ADR_INV 8 /*8 is still too small to be valid but it's aligned on 64 bit machines as well*/
#ifndef LV_VDB_PX_BPP
#define LV_VDB_PX_BPP LV_COLOR_SIZE /* Default is LV_COLOR_SIZE */
#endif
#if LV_VDB_TRUE_DOUBLE_BUFFERED && (LV_VDB_SIZE != LV_HOR_RES * LV_VER_RES || LV_VDB_DOUBLE == 0)
#error "With LV_VDB_TRUE_DOUBLE_BUFFERED: (LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES and LV_VDB_DOUBLE = 1 is required"
#endif
/* The size of VDB in bytes.
* (LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3): just divide by 8 to convert bits to bytes
* (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0): add an extra byte to round up.
* E.g. if LV_VDB_SIZE = 10 and LV_VDB_PX_BPP = 1 -> 10 bits -> 2 bytes*/
#define LV_VDB_SIZE_IN_BYTES ((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0)
/**********************
* TYPEDEFS
**********************/
typedef struct
{
lv_area_t area;
lv_color_t *buf;
} lv_vdb_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode
* @return pointer to a 'vdb' variable
*/
lv_vdb_t * lv_vdb_get(void);
/**
* Flush the content of the vdb
*/
void lv_vdb_flush(void);
/**
* Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`.
* It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES`
* @param buf1 address of the VDB.
* @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0`
*/
void lv_vdb_set_adr(void * buf1, void * buf2);
/**
* Call in the display driver's 'disp_flush' function when the flushing is finished
*/
void lv_flush_ready(void);
/**
* Get currently active VDB, where the drawing happens. Used with `LV_VDB_DOUBLE 1`
* @return pointer to the active VDB. If `LV_VDB_DOUBLE 0` give the single VDB
*/
lv_vdb_t * lv_vdb_get_active(void);
/**
* Get currently inactive VDB, which is being displayed or being flushed. Used with `LV_VDB_DOUBLE 1`
* @return pointer to the inactive VDB. If `LV_VDB_DOUBLE 0` give the single VDB
*/
lv_vdb_t * lv_vdb_get_inactive(void);
/**
* Whether the flushing is in progress or not
* @return true: flushing is in progress; false: flushing ready
*/
bool lv_vdb_is_flushing(void);
/**********************
* MACROS
**********************/
#else /*LV_VDB_SIZE != 0*/
/*Just for compatibility*/
void lv_flush_ready(void);
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_VDB_H*/

View File

@ -0,0 +1,163 @@
/**
* @file lv_draw.c
*
*/
/*********************
* INCLUDES
*********************/
#include <stdio.h>
#include "lv_draw.h"
#include "lv_draw_rbasic.h"
#include "lv_draw_vbasic.h"
#include "../lv_misc/lv_fs.h"
#include "../lv_misc/lv_math.h"
#include "../lv_misc/lv_ufs.h"
#include "../lv_objx/lv_img.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
#if LV_VDB_SIZE != 0
void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_vpx;
void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_vfill;
void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa) = lv_vletter;
void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p,
const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,
lv_color_t recolor, lv_opa_t recolor_opa) = lv_vmap;
#else
void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_rpx;
void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_rfill;
void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa) = lv_rletter;
void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p,
const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,
lv_color_t recolor, lv_opa_t recolor_opa) = lv_rmap;
#endif
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**********************
* STATIC FUNCTIONS
**********************/
#if LV_ANTIALIAS != 0
/**
* Get the opacity of a pixel based it's position in a line segment
* @param seg segment length
* @param px_id position of of a pixel which opacity should be get [0..seg-1]
* @param base_opa the base opacity
* @return the opacity of the given pixel
*/
lv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa)
{
/* How to calculate the opacity of pixels on the edges which makes the anti-aliasing?
* For example we have a line like this (y = -0.5 * x):
*
* | _ _
* * * |
*
* Anti-aliased pixels come to the '*' characters
* Calculate what percentage of the pixels should be covered if real line (not rasterized) would be drawn:
* 1. A real line should start on (0;0) and end on (2;1)
* 2. So the line intersection coordinates on the first pixel: (0;0) (1;0.5) -> 25% covered pixel in average
* 3. For the second pixel: (1;0.5) (2;1) -> 75% covered pixel in average
* 4. The equation: (px_id * 2 + 1) / (segment_width * 2)
* segment_width: the line segment which is being anti-aliased (was 2 in the example)
* px_id: pixel ID from 0 to (segment_width - 1)
* result: [0..1] coverage of the pixel
*/
/*Accelerate the common segment sizes to avoid division*/
static const lv_opa_t seg1[1] = {128};
static const lv_opa_t seg2[2] = {64, 192};
static const lv_opa_t seg3[3] = {42, 128, 212};
static const lv_opa_t seg4[4] = {32, 96, 159, 223};
static const lv_opa_t seg5[5] = {26, 76, 128, 178, 230};
static const lv_opa_t seg6[6] = {21, 64, 106, 148, 191, 234};
static const lv_opa_t seg7[7] = {18, 55, 91, 128, 164, 200, 237};
static const lv_opa_t seg8[8] = {16, 48, 80, 112, 143, 175, 207, 239};
static const lv_opa_t * seg_map[] = {seg1, seg2, seg3, seg4,
seg5, seg6, seg7, seg8
};
if(seg == 0) return LV_OPA_TRANSP;
else if(seg < 8) return (uint32_t)((uint32_t)seg_map[seg - 1][px_id] * base_opa) >> 8;
else {
return ((px_id * 2 + 1) * base_opa) / (2 * seg);
}
}
/**
* Add a vertical anti-aliasing segment (pixels with decreasing opacity)
* @param x start point x coordinate
* @param y start point y coordinate
* @param length length of segment (negative value to start from 0 opacity)
* @param mask draw only in this area
* @param color color of pixels
* @param opa maximum opacity
*/
void lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa)
{
bool aa_inv = false;
if(length < 0) {
aa_inv = true;
length = -length;
}
lv_coord_t i;
for(i = 0; i < length; i++) {
lv_opa_t px_opa = lv_draw_aa_get_opa(length, i, opa);
if(aa_inv) px_opa = opa - px_opa;
px_fp(x, y + i, mask, color, px_opa);
}
}
/**
* Add a horizontal anti-aliasing segment (pixels with decreasing opacity)
* @param x start point x coordinate
* @param y start point y coordinate
* @param length length of segment (negative value to start from 0 opacity)
* @param mask draw only in this area
* @param color color of pixels
* @param opa maximum opacity
*/
void lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa)
{
bool aa_inv = false;
if(length < 0) {
aa_inv = true;
length = -length;
}
lv_coord_t i;
for(i = 0; i < length; i++) {
lv_opa_t px_opa = lv_draw_aa_get_opa(length, i, opa);
if(aa_inv) px_opa = opa - px_opa;
px_fp(x + i, y, mask, color, px_opa);
}
}
#endif

View File

@ -0,0 +1,115 @@
/**
* @file lv_draw.h
*
*/
#ifndef LV_DRAW_H
#define LV_DRAW_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_conf.h"
#else
#include "../../lv_conf.h"
#endif
#include "../lv_core/lv_style.h"
#include "../lv_misc/lv_txt.h"
/*********************
* DEFINES
*********************/
/*If image pixels contains alpha we need to know how much byte is a pixel*/
#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
# define LV_IMG_PX_SIZE_ALPHA_BYTE 2
#elif LV_COLOR_DEPTH == 16
# define LV_IMG_PX_SIZE_ALPHA_BYTE 3
#elif LV_COLOR_DEPTH == 32
# define LV_IMG_PX_SIZE_ALPHA_BYTE 4
#endif
/**********************
* TYPEDEFS
**********************/
enum {
LV_IMG_SRC_VARIABLE,
LV_IMG_SRC_FILE,
LV_IMG_SRC_SYMBOL,
LV_IMG_SRC_UNKNOWN,
};
typedef uint8_t lv_img_src_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
#if LV_ANTIALIAS != 0
/**
* Get the opacity of a pixel based it's position in a line segment
* @param seg segment length
* @param px_id position of of a pixel which opacity should be get [0..seg-1]
* @param base_opa the base opacity
* @return the opacity of the given pixel
*/
lv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa);
/**
* Add a vertical anti-aliasing segment (pixels with decreasing opacity)
* @param x start point x coordinate
* @param y start point y coordinate
* @param length length of segment (negative value to start from 0 opacity)
* @param mask draw only in this area
* @param color color of pixels
* @param opa maximum opacity
*/
void lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);
/**
* Add a horizontal anti-aliasing segment (pixels with decreasing opacity)
* @param x start point x coordinate
* @param y start point y coordinate
* @param length length of segment (negative value to start from 0 opacity)
* @param mask draw only in this area
* @param color color of pixels
* @param opa maximum opacity
*/
void lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);
#endif
/**********************
* GLOBAL VARIABLES
**********************/
extern void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);
extern void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);
extern void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa);
extern void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p,
const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,
lv_color_t recolor, lv_opa_t recolor_opa);
/**********************
* MACROS
**********************/
/**********************
* POST INCLUDES
*********************/
#include "lv_draw_rect.h"
#include "lv_draw_label.h"
#include "lv_draw_img.h"
#include "lv_draw_line.h"
#include "lv_draw_triangle.h"
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_DRAW_H*/

View File

@ -0,0 +1,14 @@
CSRCS += lv_draw_vbasic.c
CSRCS += lv_draw_rbasic.c
CSRCS += lv_draw.c
CSRCS += lv_draw_rect.c
CSRCS += lv_draw_label.c
CSRCS += lv_draw_line.c
CSRCS += lv_draw_img.c
CSRCS += lv_draw_arc.c
CSRCS += lv_draw_triangle.c
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_draw
VPATH += :$(LVGL_DIR)/lvgl/lv_draw
CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_draw"

View File

@ -0,0 +1,264 @@
/**
* @file lv_draw_arc.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_arc.h"
#include "../lv_misc/lv_math.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static uint16_t fast_atan2(int x, int y);
static void ver_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa);
static void hor_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa);
static bool deg_test_norm(uint16_t deg, uint16_t start, uint16_t end);
static bool deg_test_inv(uint16_t deg, uint16_t start, uint16_t end);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Draw an arc. (Can draw pie too with great thickness.)
* @param center_x the x coordinate of the center of the arc
* @param center_y the y coordinate of the center of the arc
* @param radius the radius of the arc
* @param mask the arc will be drawn only in this mask
* @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right)
* @param end_angle the end angle of the arc
* @param style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used)
* @param opa_scale scale down all opacities by the factor
*/
void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask,
uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale)
{
lv_coord_t thickness = style->line.width;
if(thickness > radius) thickness = radius;
lv_coord_t r_out = radius;
lv_coord_t r_in = r_out - thickness;
int16_t deg_base;
int16_t deg;
lv_coord_t x_start[4];
lv_coord_t x_end[4];
lv_color_t color = style->line.color;
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8;
bool (*deg_test)(uint16_t, uint16_t, uint16_t);
if(start_angle <= end_angle) deg_test = deg_test_norm;
else deg_test = deg_test_inv;
if(deg_test(270, start_angle, end_angle)) hor_line(center_x - r_out + 1, center_y, mask, thickness - 1, color, opa); // Left Middle
if(deg_test(90, start_angle, end_angle)) hor_line(center_x + r_in, center_y, mask, thickness - 1, color, opa); // Right Middle
if(deg_test(180, start_angle, end_angle)) ver_line(center_x, center_y - r_out + 1, mask, thickness - 1, color, opa); // Top Middle
if(deg_test(0, start_angle, end_angle)) ver_line(center_x, center_y + r_in, mask, thickness - 1, color, opa); // Bottom middle
uint32_t r_out_sqr = r_out * r_out;
uint32_t r_in_sqr = r_in * r_in;
int16_t xi;
int16_t yi;
for(yi = -r_out; yi < 0; yi++) {
x_start[0] = LV_COORD_MIN;
x_start[1] = LV_COORD_MIN;
x_start[2] = LV_COORD_MIN;
x_start[3] = LV_COORD_MIN;
x_end[0] = LV_COORD_MIN;
x_end[1] = LV_COORD_MIN;
x_end[2] = LV_COORD_MIN;
x_end[3] = LV_COORD_MIN;
for(xi = -r_out; xi < 0; xi++) {
uint32_t r_act_sqr = xi * xi + yi * yi;
if(r_act_sqr > r_out_sqr) continue;
deg_base = fast_atan2(xi, yi) - 180;
deg = 180 + deg_base;
if(deg_test(deg, start_angle, end_angle)) {
if(x_start[0] == LV_COORD_MIN) x_start[0] = xi;
} else if(x_start[0] != LV_COORD_MIN && x_end[0] == LV_COORD_MIN) {
x_end[0] = xi - 1;
}
deg = 360 - deg_base;
if(deg_test(deg, start_angle, end_angle)) {
if(x_start[1] == LV_COORD_MIN) x_start[1] = xi;
} else if(x_start[1] != LV_COORD_MIN && x_end[1] == LV_COORD_MIN) {
x_end[1] = xi - 1;
}
deg = 180 - deg_base;
if(deg_test(deg, start_angle, end_angle)) {
if(x_start[2] == LV_COORD_MIN) x_start[2] = xi;
} else if(x_start[2] != LV_COORD_MIN && x_end[2] == LV_COORD_MIN) {
x_end[2] = xi - 1;
}
deg = deg_base;
if(deg_test(deg, start_angle, end_angle)) {
if(x_start[3] == LV_COORD_MIN) x_start[3] = xi;
} else if(x_start[3] != LV_COORD_MIN && x_end[3] == LV_COORD_MIN) {
x_end[3] = xi - 1;
}
if(r_act_sqr < r_in_sqr) break; /*No need to continue the iteration in x once we found the inner edge of the arc*/
}
if(x_start[0] != LV_COORD_MIN) {
if(x_end[0] == LV_COORD_MIN) x_end[0] = xi - 1;
hor_line(center_x + x_start[0], center_y + yi, mask, x_end[0] - x_start[0], color, opa);
}
if(x_start[1] != LV_COORD_MIN) {
if(x_end[1] == LV_COORD_MIN) x_end[1] = xi - 1;
hor_line(center_x + x_start[1], center_y - yi, mask, x_end[1] - x_start[1], color, opa);
}
if(x_start[2] != LV_COORD_MIN) {
if(x_end[2] == LV_COORD_MIN) x_end[2] = xi - 1;
hor_line(center_x - x_end[2], center_y + yi, mask, LV_MATH_ABS(x_end[2] - x_start[2]), color, opa);
}
if(x_start[3] != LV_COORD_MIN) {
if(x_end[3] == LV_COORD_MIN) x_end[3] = xi - 1;
hor_line(center_x - x_end[3], center_y - yi, mask, LV_MATH_ABS(x_end[3] - x_start[3]), color, opa);
}
#if LV_ANTIALIAS
/*TODO*/
#endif
}
}
static uint16_t fast_atan2(int x, int y)
{
// Fast XY vector to integer degree algorithm - Jan 2011 www.RomanBlack.com
// Converts any XY values including 0 to a degree value that should be
// within +/- 1 degree of the accurate value without needing
// large slow trig functions like ArcTan() or ArcCos().
// NOTE! at least one of the X or Y values must be non-zero!
// This is the full version, for all 4 quadrants and will generate
// the angle in integer degrees from 0-360.
// Any values of X and Y are usable including negative values provided
// they are between -1456 and 1456 so the 16bit multiply does not overflow.
unsigned char negflag;
unsigned char tempdegree;
unsigned char comp;
unsigned int degree; // this will hold the result
//signed int x; // these hold the XY vector at the start
//signed int y; // (and they will be destroyed)
unsigned int ux;
unsigned int uy;
// Save the sign flags then remove signs and get XY as unsigned ints
negflag = 0;
if(x < 0) {
negflag += 0x01; // x flag bit
x = (0 - x); // is now +
}
ux = x; // copy to unsigned var before multiply
if(y < 0) {
negflag += 0x02; // y flag bit
y = (0 - y); // is now +
}
uy = y; // copy to unsigned var before multiply
// 1. Calc the scaled "degrees"
if(ux > uy) {
degree = (uy * 45) / ux; // degree result will be 0-45 range
negflag += 0x10; // octant flag bit
} else {
degree = (ux * 45) / uy; // degree result will be 0-45 range
}
// 2. Compensate for the 4 degree error curve
comp = 0;
tempdegree = degree; // use an unsigned char for speed!
if(tempdegree > 22) { // if top half of range
if(tempdegree <= 44) comp++;
if(tempdegree <= 41) comp++;
if(tempdegree <= 37) comp++;
if(tempdegree <= 32) comp++; // max is 4 degrees compensated
} else { // else is lower half of range
if(tempdegree >= 2) comp++;
if(tempdegree >= 6) comp++;
if(tempdegree >= 10) comp++;
if(tempdegree >= 15) comp++; // max is 4 degrees compensated
}
degree += comp; // degree is now accurate to +/- 1 degree!
// Invert degree if it was X>Y octant, makes 0-45 into 90-45
if(negflag & 0x10) degree = (90 - degree);
// 3. Degree is now 0-90 range for this quadrant,
// need to invert it for whichever quadrant it was in
if(negflag & 0x02) { // if -Y
if(negflag & 0x01) // if -Y -X
degree = (180 + degree);
else // else is -Y +X
degree = (180 - degree);
} else { // else is +Y
if(negflag & 0x01) // if +Y -X
degree = (360 - degree);
}
return degree;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void ver_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa)
{
lv_area_t area;
lv_area_set(&area, x, y, x, y + len);
fill_fp(&area, mask, color, opa);
}
static void hor_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa)
{
lv_area_t area;
lv_area_set(&area, x, y, x + len, y);
fill_fp(&area, mask, color, opa);
}
static bool deg_test_norm(uint16_t deg, uint16_t start, uint16_t end)
{
if(deg >= start && deg <= end) return true;
else return false;
}
static bool deg_test_inv(uint16_t deg, uint16_t start, uint16_t end)
{
if(deg >= start || deg <= end) {
return true;
} else return false;
}

View File

@ -0,0 +1,53 @@
/**
* @file lv_draw_arc.h
*
*/
#ifndef LV_DRAW_ARC_H
#define LV_DRAW_ARC_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_draw.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Draw an arc. (Can draw pie too with great thickness.)
* @param center_x the x coordinate of the center of the arc
* @param center_y the y coordinate of the center of the arc
* @param radius the radius of the arc
* @param mask the arc will be drawn only in this mask
* @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right)
* @param end_angle the end angle of the arc
* @param style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used)
* @param opa_scale scale down all opacities by the factor
*/
void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask,
uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_DRAW_ARC*/

View File

@ -0,0 +1,759 @@
/**
* @file lv_draw_img.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_img.h"
#include "../lv_misc/lv_fs.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask,
const void * src, const lv_style_t * style, lv_opa_t opa_scale);
static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style);
static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
static void lv_img_decoder_close(void);
static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
/**********************
* STATIC VARIABLES
**********************/
static bool decoder_custom;
static const void * decoder_src;
static lv_img_src_t decoder_src_type;
static lv_img_header_t decoder_header;
static const lv_style_t * decoder_style;
#if USE_LV_FILESYSTEM
static lv_fs_file_t decoder_file;
#endif
#if LV_IMG_CF_INDEXED
static lv_color_t decoder_index_map[256];
#endif
static lv_img_decoder_info_f_t lv_img_decoder_info_custom;
static lv_img_decoder_open_f_t lv_img_decoder_open_custom;
static lv_img_decoder_read_line_f_t lv_img_decoder_read_line_custom;
static lv_img_decoder_close_f_t lv_img_decoder_close_custom;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Draw an image
* @param coords the coordinates of the image
* @param mask the image will be drawn only in this area
* @param src pointer to a lv_color_t array which contains the pixels of the image
* @param style style of the image
* @param opa_scale scale down all opacities by the factor
*/
void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask,
const void * src, const lv_style_t * style, lv_opa_t opa_scale)
{
if(src == NULL) {
LV_LOG_WARN("Image draw: src is NULL");
lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER);
lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, "No\ndata", LV_TXT_FLAG_NONE, NULL);
return;
}
lv_res_t res;
res = lv_img_draw_core(coords, mask, src, style, opa_scale);
if(res == LV_RES_INV) {
LV_LOG_WARN("Image draw error");
lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER);
lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, "No\ndata", LV_TXT_FLAG_NONE, NULL);
return;
}
}
/**
*
* @param src
* @param header
* @param style
* @return
*/
lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header)
{
header->always_zero = 0;
/*Try to get info with the custom functions first*/
if(lv_img_decoder_info_custom) {
lv_res_t custom_res;
custom_res = lv_img_decoder_info_custom(src, header);
if(custom_res == LV_RES_OK) return LV_RES_OK; /*Custom info has supported this source*/
}
lv_img_src_t src_type = lv_img_src_get_type(src);
if(src_type == LV_IMG_SRC_VARIABLE) {
header->w = ((lv_img_dsc_t *)src)->header.w;
header->h = ((lv_img_dsc_t *)src)->header.h;
header->cf = ((lv_img_dsc_t *)src)->header.cf;
}
#if USE_LV_FILESYSTEM
else if(src_type == LV_IMG_SRC_FILE) {
lv_fs_file_t file;
lv_fs_res_t res;
uint32_t rn;
res = lv_fs_open(&file, src, LV_FS_MODE_RD);
if(res == LV_FS_RES_OK) {
res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn);
}
/*Create a dummy header on fs error*/
if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) {
header->w = LV_DPI;
header->h = LV_DPI;
header->cf = LV_IMG_CF_UNKOWN;
}
lv_fs_close(&file);
}
#endif
else if(src_type == LV_IMG_SRC_SYMBOL) {
/*The size depend on the font but it is unknown here. It should be handled outside of the function*/
header->w = 1;
header->h = 1;
/* Symbols always have transparent parts. Important because of cover check in the design function.
* The actual value doesn't matter because lv_draw_label will draw it*/
header->cf = LV_IMG_CF_ALPHA_1BIT;
} else {
LV_LOG_WARN("Image get info found unknown src type");
return false;
}
return true;
}
uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf)
{
uint8_t px_size = 0;
switch(cf) {
case LV_IMG_CF_UNKOWN:
case LV_IMG_CF_RAW:
px_size = 0;
break;
case LV_IMG_CF_TRUE_COLOR:
case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
px_size = LV_COLOR_SIZE;
break;
case LV_IMG_CF_TRUE_COLOR_ALPHA:
px_size = LV_IMG_PX_SIZE_ALPHA_BYTE << 3;
break;
case LV_IMG_CF_INDEXED_1BIT:
case LV_IMG_CF_ALPHA_1BIT:
px_size = 1;
break;
case LV_IMG_CF_INDEXED_2BIT:
case LV_IMG_CF_ALPHA_2BIT:
px_size = 2;
break;
case LV_IMG_CF_INDEXED_4BIT:
case LV_IMG_CF_ALPHA_4BIT:
px_size = 4;
break;
case LV_IMG_CF_INDEXED_8BIT:
case LV_IMG_CF_ALPHA_8BIT:
px_size = 8;
break;
default:
px_size = 0;
break;
}
return px_size;
}
bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf)
{
bool is_chroma_keyed = false;
switch(cf) {
case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
case LV_IMG_CF_RAW_CHROMA_KEYED:
case LV_IMG_CF_INDEXED_1BIT:
case LV_IMG_CF_INDEXED_2BIT:
case LV_IMG_CF_INDEXED_4BIT:
case LV_IMG_CF_INDEXED_8BIT:
is_chroma_keyed = true;
break;
default:
is_chroma_keyed = false;
break;
}
return is_chroma_keyed;
}
bool lv_img_color_format_has_alpha(lv_img_cf_t cf)
{
bool has_alpha = false;
switch(cf) {
case LV_IMG_CF_TRUE_COLOR_ALPHA:
case LV_IMG_CF_RAW_ALPHA:
case LV_IMG_CF_ALPHA_1BIT:
case LV_IMG_CF_ALPHA_2BIT:
case LV_IMG_CF_ALPHA_4BIT:
case LV_IMG_CF_ALPHA_8BIT:
has_alpha = true;
break;
default:
has_alpha = false;
break;
}
return has_alpha;
}
/**
* Get the type of an image source
* @param src pointer to an image source:
* - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code)
* - a path to a file (e.g. "S:/folder/image.bin")
* - or a symbol (e.g. SYMBOL_CLOSE)
* @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN
*/
lv_img_src_t lv_img_src_get_type(const void * src)
{
lv_img_src_t img_src_type = LV_IMG_SRC_UNKNOWN;
if(src == NULL) return img_src_type;
const uint8_t * u8_p = src;
/*The first byte shows the type of the image source*/
if(u8_p[0] >= 0x20 && u8_p[0] <= 0x7F) {
img_src_type = LV_IMG_SRC_FILE; /*If it's an ASCII character then it's file name*/
} else if(u8_p[0] >= 0x80) {
img_src_type = LV_IMG_SRC_SYMBOL; /*Symbols begins after 0x7F*/
} else {
img_src_type = LV_IMG_SRC_VARIABLE; /*`lv_img_dsc_t` is design to the first byte < 0x20*/
}
if (LV_IMG_SRC_UNKNOWN == img_src_type) {
LV_LOG_WARN("lv_img_src_get_type: unknown image type");
}
return img_src_type;
}
/**
* Set custom decoder functions. See the typdefs of the function typed above for more info about them
* @param info_fp info get function
* @param open_fp open function
* @param read_fp read line function
* @param close_fp clode function
*/
void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp,
lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp)
{
lv_img_decoder_info_custom = info_fp;
lv_img_decoder_open_custom = open_fp;
lv_img_decoder_read_line_custom = read_fp;
lv_img_decoder_close_custom = close_fp;
}
/**********************
* STATIC FUNCTIONS
**********************/
static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask,
const void * src, const lv_style_t * style, lv_opa_t opa_scale)
{
lv_area_t mask_com; /*Common area of mask and coords*/
bool union_ok;
union_ok = lv_area_intersect(&mask_com, mask, coords);
if(union_ok == false) {
return LV_RES_OK; /*Out of mask. There is nothing to draw so the image is drawn successfully.*/
}
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->image.opa : (uint16_t)((uint16_t) style->image.opa * opa_scale) >> 8;
lv_img_header_t header;
lv_res_t header_res;
header_res = lv_img_dsc_get_info(src, &header);
if(header_res != LV_RES_OK) {
LV_LOG_WARN("Image draw can't get image info");
lv_img_decoder_close();
return LV_RES_INV;
}
bool chroma_keyed = lv_img_color_format_is_chroma_keyed(header.cf);
bool alpha_byte = lv_img_color_format_has_alpha(header.cf);
const uint8_t * img_data = lv_img_decoder_open(src, style);
if(img_data == LV_IMG_DECODER_OPEN_FAIL) {
LV_LOG_WARN("Image draw cannot open the image resource");
lv_img_decoder_close();
return LV_RES_INV;
}
/* The decoder open could open the image and gave the entire uncompressed image.
* Just draw it!*/
if(img_data) {
map_fp(coords, mask, img_data, opa, chroma_keyed, alpha_byte, style->image.color, style->image.intense);
}
/* The whole uncompressed image is not available. Try to read it line-by-line*/
else {
lv_coord_t width = lv_area_get_width(&mask_com);
#if LV_COMPILER_VLA_SUPPORTED
uint8_t buf[(lv_area_get_width(&mask_com) * ((LV_COLOR_DEPTH >> 3) + 1))];
#else
uint8_t buf[LV_HOR_RES * ((LV_COLOR_DEPTH >> 3) + 1)]; /*+1 because of the possible alpha byte*/
#endif
lv_area_t line;
lv_area_copy(&line, &mask_com);
lv_area_set_height(&line, 1);
lv_coord_t x = mask_com.x1 - coords->x1;
lv_coord_t y = mask_com.y1 - coords->y1;
lv_coord_t row;
lv_res_t read_res;
for(row = mask_com.y1; row <= mask_com.y2; row++) {
read_res = lv_img_decoder_read_line(x, y, width, buf);
if(read_res != LV_RES_OK) {
lv_img_decoder_close();
LV_LOG_WARN("Image draw can't read the line");
return LV_RES_INV;
}
map_fp(&line, mask, buf, opa, chroma_keyed, alpha_byte, style->image.color, style->image.intense);
line.y1++;
line.y2++;
y++;
}
}
lv_img_decoder_close();
return LV_RES_OK;
}
static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style)
{
decoder_custom = false;
/*Try to open with the custom functions first*/
if(lv_img_decoder_open_custom) {
const uint8_t * custom_res;
custom_res = lv_img_decoder_open_custom(src, style);
if(custom_res != LV_IMG_DECODER_OPEN_FAIL) {
decoder_custom = true; /*Mark that custom decoder function should be used for this img source.*/
return custom_res; /*Custom open supported this source*/
}
}
decoder_src = src;
decoder_style = style;
decoder_src_type = lv_img_src_get_type(src);
lv_res_t header_res;
header_res = lv_img_dsc_get_info(src, &decoder_header);
if(header_res == LV_RES_INV) {
decoder_src = NULL;
decoder_src_type = LV_IMG_SRC_UNKNOWN;
LV_LOG_WARN("Built-in image decoder can't get the header info");
return LV_IMG_DECODER_OPEN_FAIL;
}
/*Open the file if it's a file*/
if(decoder_src_type == LV_IMG_SRC_FILE) {
#if USE_LV_FILESYSTEM
lv_fs_res_t res = lv_fs_open(&decoder_file, src, LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) {
LV_LOG_WARN("Built-in image decoder can't open the file");
return LV_IMG_DECODER_OPEN_FAIL;
}
#else
LV_LOG_WARN("Image built-in decoder can read file because USE_LV_FILESYSTEM = 0");
return LV_IMG_DECODER_OPEN_FAIL;
#endif
}
/*Process the different color formats*/
lv_img_cf_t cf = decoder_header.cf;
if(cf == LV_IMG_CF_TRUE_COLOR ||
cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
if(decoder_src_type == LV_IMG_SRC_VARIABLE) {
/*In case of uncompressed formats if the image stored in the ROM/RAM simply give it's pointer*/
return ((lv_img_dsc_t *)decoder_src)->data;
} else {
/*If it's file it need to be read line by line later*/
return NULL;
}
} else if(cf == LV_IMG_CF_INDEXED_1BIT ||
cf == LV_IMG_CF_INDEXED_2BIT ||
cf == LV_IMG_CF_INDEXED_4BIT ||
cf == LV_IMG_CF_INDEXED_8BIT) {
#if LV_IMG_CF_INDEXED
#if USE_LV_FILESYSTEM
lv_color32_t palette_file[256];
#endif
lv_color32_t * palette_p = NULL;
uint8_t px_size = lv_img_color_format_get_px_size(cf);
uint32_t palette_size = 1 << px_size;
if(decoder_src_type == LV_IMG_SRC_FILE) {
/*Read the palette from file*/
#if USE_LV_FILESYSTEM
lv_fs_seek(&decoder_file, 4); /*Skip the header*/
lv_fs_read(&decoder_file, palette_file, palette_size * sizeof(lv_color32_t), NULL);
palette_p = palette_file;
#else
LV_LOG_WARN("Image built-in decoder can read the palette because USE_LV_FILESYSTEM = 0");
return LV_IMG_DECODER_OPEN_FAIL;
#endif
} else {
/*The palette begins in the beginning of the image data. Just point to it.*/
palette_p = (lv_color32_t *)((lv_img_dsc_t *)decoder_src)->data;
}
uint32_t i;
for(i = 0; i < palette_size; i++) {
decoder_index_map[i] = LV_COLOR_MAKE(palette_p[i].red, palette_p[i].green, palette_p[i].blue);
}
return NULL;
#else
LV_LOG_WARN("Indexed (palette) images are not enabled in lv_conf.h. See LV_IMG_CF_INDEXED");
return LV_IMG_DECODER_OPEN_FAIL;
#endif
} else if(cf == LV_IMG_CF_ALPHA_1BIT ||
cf == LV_IMG_CF_ALPHA_2BIT ||
cf == LV_IMG_CF_ALPHA_4BIT ||
cf == LV_IMG_CF_ALPHA_8BIT) {
#if LV_IMG_CF_ALPHA
return NULL; /*Nothing to process*/
#else
LV_LOG_WARN("Alpha indexed images are not enabled in lv_conf.h. See LV_IMG_CF_ALPHA");
return LV_IMG_DECODER_OPEN_FAIL;
#endif
} else {
LV_LOG_WARN("Image decoder open: unknown color format")
return LV_IMG_DECODER_OPEN_FAIL;
}
}
static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
{
/*Try to read the line with the custom functions*/
if(decoder_custom) {
if(lv_img_decoder_read_line_custom) {
lv_res_t custom_res;
custom_res = lv_img_decoder_read_line_custom(x, y, len, buf);
return custom_res;
} else {
LV_LOG_WARN("Image open with custom decoder but read not supported")
}
return LV_RES_INV; /*It"s an error if not returned earlier*/
}
if(decoder_src_type == LV_IMG_SRC_FILE) {
#if USE_LV_FILESYSTEM
uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf);
lv_fs_res_t res;
if(decoder_header.cf == LV_IMG_CF_TRUE_COLOR ||
decoder_header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
decoder_header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
uint32_t pos = ((y * decoder_header.w + x) * px_size) >> 3;
pos += 4; /*Skip the header*/
res = lv_fs_seek(&decoder_file, pos);
if(res != LV_FS_RES_OK) {
LV_LOG_WARN("Built-in image decoder seek failed");
return false;
}
uint32_t btr = len * (px_size >> 3);
uint32_t br = 0;
lv_fs_read(&decoder_file, buf, btr, &br);
if(res != LV_FS_RES_OK || btr != br) {
LV_LOG_WARN("Built-in image decoder read failed");
return false;
}
} else if(decoder_header.cf == LV_IMG_CF_ALPHA_1BIT ||
decoder_header.cf == LV_IMG_CF_ALPHA_2BIT ||
decoder_header.cf == LV_IMG_CF_ALPHA_4BIT ||
decoder_header.cf == LV_IMG_CF_ALPHA_8BIT) {
lv_img_built_in_decoder_line_alpha(x, y, len, buf);
} else if(decoder_header.cf == LV_IMG_CF_INDEXED_1BIT ||
decoder_header.cf == LV_IMG_CF_INDEXED_2BIT ||
decoder_header.cf == LV_IMG_CF_INDEXED_4BIT ||
decoder_header.cf == LV_IMG_CF_INDEXED_8BIT) {
lv_img_built_in_decoder_line_indexed(x, y, len, buf);
} else {
LV_LOG_WARN("Built-in image decoder read not supports the color format");
return false;
}
#else
LV_LOG_WARN("Image built-in decoder can't read file because USE_LV_FILESYSTEM = 0");
return false;
#endif
} else if(decoder_src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = decoder_src;
if(img_dsc->header.cf == LV_IMG_CF_ALPHA_1BIT ||
img_dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||
img_dsc->header.cf == LV_IMG_CF_ALPHA_4BIT ||
img_dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
lv_img_built_in_decoder_line_alpha(x, y, len, buf);
} else if(img_dsc->header.cf == LV_IMG_CF_INDEXED_1BIT ||
img_dsc->header.cf == LV_IMG_CF_INDEXED_2BIT ||
img_dsc->header.cf == LV_IMG_CF_INDEXED_4BIT ||
img_dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
lv_img_built_in_decoder_line_indexed(x, y, len, buf);
} else {
LV_LOG_WARN("Built-in image decoder not supports the color format");
return false;
}
}
return true;
}
static void lv_img_decoder_close(void)
{
/*Try to close with the custom functions*/
if(decoder_custom) {
if(lv_img_decoder_close_custom) lv_img_decoder_close_custom();
return;
}
/*It was opened with built-in decoder*/
if(decoder_src) {
#if USE_LV_FILESYSTEM
if(decoder_src_type == LV_IMG_SRC_FILE) {
lv_fs_close(&decoder_file);
}
#endif
decoder_src_type = LV_IMG_SRC_UNKNOWN;
decoder_src = NULL;
}
}
static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
{
#if LV_IMG_CF_ALPHA
const lv_opa_t alpha1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
68, 85, 102, 119,
136, 153, 170, 187,
204, 221, 238, 255
};
/*Simply fill the buffer with the color. Later only the alpha value will be modified.*/
lv_color_t bg_color = decoder_style->image.color;
lv_coord_t i;
for(i = 0; i < len; i++) {
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full;
#elif LV_COLOR_DEPTH == 16
/*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF;
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF;
#elif LV_COLOR_DEPTH == 32
*((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full;
#else
#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
#endif
}
const lv_opa_t * opa_table = NULL;
uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf);
uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
lv_coord_t w = 0;
uint32_t ofs = 0;
int8_t pos = 0;
switch(decoder_header.cf) {
case LV_IMG_CF_ALPHA_1BIT:
w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/
if(decoder_header.w & 0x7) w++;
ofs += w * y + (x >> 3); /*First pixel*/
pos = 7 - (x & 0x7);
opa_table = alpha1_opa_table;
break;
case LV_IMG_CF_ALPHA_2BIT:
w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
if(decoder_header.w & 0x3) w++;
ofs += w * y + (x >> 2); /*First pixel*/
pos = 6 - ((x & 0x3) * 2);
opa_table = alpha2_opa_table;
break;
case LV_IMG_CF_ALPHA_4BIT:
w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
if(decoder_header.w & 0x1) w++;
ofs += w * y + (x >> 1); /*First pixel*/
pos = 4 - ((x & 0x1) * 4);
opa_table = alpha4_opa_table;
break;
case LV_IMG_CF_ALPHA_8BIT:
w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
ofs += w * y + x; /*First pixel*/
pos = 0;
break;
}
#if USE_LV_FILESYSTEM
# if LV_COMPILER_VLA_SUPPORTED
uint8_t fs_buf[w];
# else
uint8_t fs_buf[LV_HOR_RES];
# endif
#endif
const uint8_t * data_tmp = NULL;
if(decoder_src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = decoder_src;
data_tmp = img_dsc->data + ofs;
} else {
#if USE_LV_FILESYSTEM
lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/
lv_fs_read(&decoder_file, fs_buf, w, NULL);
data_tmp = fs_buf;
#else
LV_LOG_WARN("Image built-in alpha line reader can't read file because USE_LV_FILESYSTEM = 0");
data_tmp = NULL; /*To avoid warnings*/
return LV_RES_INV;
#endif
}
uint8_t byte_act = 0;
uint8_t val_act;
for(i = 0; i < len; i ++) {
val_act = (data_tmp[byte_act] & (mask << pos)) >> pos;
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] =
decoder_header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act];
pos -= px_size;
if(pos < 0) {
pos = 8 - px_size;
data_tmp++;
}
}
return LV_RES_OK;
#else
LV_LOG_WARN("Image built-in alpha line reader failed because LV_IMG_CF_ALPHA is 0 in lv_conf.h");
return LV_RES_INV;
#endif
}
static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
{
#if LV_IMG_CF_INDEXED
uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf);
uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
lv_coord_t w = 0;
int8_t pos = 0;
uint32_t ofs = 0;
switch(decoder_header.cf) {
case LV_IMG_CF_INDEXED_1BIT:
w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/
if(decoder_header.w & 0x7) w++;
ofs += w * y + (x >> 3); /*First pixel*/
ofs += 8; /*Skip the palette*/
pos = 7 - (x & 0x7);
break;
case LV_IMG_CF_INDEXED_2BIT:
w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
if(decoder_header.w & 0x3) w++;
ofs += w * y + (x >> 2); /*First pixel*/
ofs += 16; /*Skip the palette*/
pos = 6 - ((x & 0x3) * 2);
break;
case LV_IMG_CF_INDEXED_4BIT:
w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
if(decoder_header.w & 0x1) w++;
ofs += w * y + (x >> 1); /*First pixel*/
ofs += 64; /*Skip the palette*/
pos = 4 - ((x & 0x1) * 4);
break;
case LV_IMG_CF_INDEXED_8BIT:
w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
ofs += w * y + x; /*First pixel*/
ofs += 1024; /*Skip the palette*/
pos = 0;
break;
}
#if USE_LV_FILESYSTEM
# if LV_COMPILER_VLA_SUPPORTED
uint8_t fs_buf[w];
# else
uint8_t fs_buf[LV_HOR_RES];
# endif
#endif
const uint8_t * data_tmp = NULL;
if(decoder_src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = decoder_src;
data_tmp = img_dsc->data + ofs;
} else {
#if USE_LV_FILESYSTEM
lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/
lv_fs_read(&decoder_file, fs_buf, w, NULL);
data_tmp = fs_buf;
#else
LV_LOG_WARN("Image built-in indexed line reader can't read file because USE_LV_FILESYSTEM = 0");
data_tmp = NULL; /*To avoid warnings*/
return LV_RES_INV;
#endif
}
uint8_t byte_act = 0;
uint8_t val_act;
lv_coord_t i;
lv_color_t * cbuf = (lv_color_t *) buf;
for(i = 0; i < len; i ++) {
val_act = (data_tmp[byte_act] & (mask << pos)) >> pos;
cbuf[i] = decoder_index_map[val_act];
pos -= px_size;
if(pos < 0) {
pos = 8 - px_size;
data_tmp++;
}
}
return LV_RES_OK;
#else
LV_LOG_WARN("Image built-in indexed line reader failed because LV_IMG_CF_INDEXED is 0 in lv_conf.h");
return LV_RES_INV;
#endif
}

View File

@ -0,0 +1,167 @@
/**
* @file lv_draw_img.h
*
*/
#ifndef LV_DRAW_IMG_H
#define LV_DRAW_IMG_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_draw.h"
#include "../lv_core/lv_obj.h"
/*********************
* DEFINES
*********************/
#define LV_IMG_DECODER_OPEN_FAIL ((void*)(-1))
/**********************
* TYPEDEFS
**********************/
struct _lv_img_t;
typedef struct {
/* The first 8 bit is very important to distinguish the different source types.
* For more info see `lv_img_get_src_type()` in lv_img.c */
uint32_t cf :5; /* Color format: See `lv_img_color_format_t`*/
uint32_t always_zero :3; /*It the upper bits of the first byte. Always zero to look like a non-printable character*/
uint32_t reserved :2; /*Reserved to be used later*/
uint32_t w:11; /*Width of the image map*/
uint32_t h:11; /*Height of the image map*/
} lv_img_header_t;
/*Image color format*/
enum {
LV_IMG_CF_UNKOWN = 0,
LV_IMG_CF_RAW, /*Contains the file as it is. Needs custom decoder function*/
LV_IMG_CF_RAW_ALPHA, /*Contains the file as it is. The image has alpha. Needs custom decoder function*/
LV_IMG_CF_RAW_CHROMA_KEYED, /*Contains the file as it is. The image is chroma keyed. Needs custom decoder function*/
LV_IMG_CF_TRUE_COLOR, /*Color format and depth should match with LV_COLOR settings*/
LV_IMG_CF_TRUE_COLOR_ALPHA, /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/
LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels will be transparent*/
LV_IMG_CF_INDEXED_1BIT, /*Can have 2 different colors in a palette (always chroma keyed)*/
LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/
LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/
LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always chroma keyed)*/
LV_IMG_CF_ALPHA_1BIT, /*Can have one color and it can be drawn or not*/
LV_IMG_CF_ALPHA_2BIT, /*Can have one color but 4 different alpha value*/
LV_IMG_CF_ALPHA_4BIT, /*Can have one color but 16 different alpha value*/
LV_IMG_CF_ALPHA_8BIT, /*Can have one color but 256 different alpha value*/
};
typedef uint8_t lv_img_cf_t;
/* Image header it is compatible with
* the result image converter utility*/
typedef struct
{
lv_img_header_t header;
uint32_t data_size;
const uint8_t * data;
} lv_img_dsc_t;
/* Decoder function definitions */
/**
* Get info from an image and store in the `header`
* @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type)
* @param header store the info here
* @return LV_RES_OK: info written correctly; LV_RES_INV: failed
*/
typedef lv_res_t (*lv_img_decoder_info_f_t)(const void * src, lv_img_header_t * header);
/**
* Open an image for decoding. Prepare it as it is required to read it later
* @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type)
* @param style the style of image (maybe it will be required to determine a color or something)
* @return there are 3 possible return values:
* 1) buffer with the decoded image
* 2) if can decode the whole image NULL. decoder_read_line will be called to read the image line-by-line
* 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an error occurred
*/
typedef const uint8_t * (*lv_img_decoder_open_f_t)(const void * src, const lv_style_t * style);
/**
* Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
* Required only if the "open" function can't return with the whole decoded pixel array.
* @param x start x coordinate
* @param y startt y coordinate
* @param len number of pixels to decode
* @param buf a buffer to store the decoded pixels
* @return LV_RES_OK: ok; LV_RES_INV: failed
*/
typedef lv_res_t (*lv_img_decoder_read_line_f_t)(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
/**
* Close the pending decoding. Free resources etc.
*/
typedef void (*lv_img_decoder_close_f_t)(void);
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Draw an image
* @param coords the coordinates of the image
* @param mask the image will be drawn only in this area
* @param src pointer to a lv_color_t array which contains the pixels of the image
* @param style style of the image
* @param opa_scale scale down all opacities by the factor
*/
void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask,
const void * src, const lv_style_t * style, lv_opa_t opa_scale);
/**
* Get the type of an image source
* @param src pointer to an image source:
* - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code)
* - a path to a file (e.g. "S:/folder/image.bin")
* - or a symbol (e.g. SYMBOL_CLOSE)
* @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN
*/
lv_img_src_t lv_img_src_get_type(const void * src);
/**
* Set custom decoder functions. See the typdefs of the function typed above for more info about them
* @param info_fp info get function
* @param open_fp open function
* @param read_fp read line function
* @param close_fp clode function
*/
void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp,
lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp);
lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header);
uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf);
bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf);
bool lv_img_color_format_has_alpha(lv_img_cf_t cf);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_TEMPL_H*/

View File

@ -0,0 +1,264 @@
/**
* @file lv_draw_label.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_label.h"
#include "lv_draw_rbasic.h"
#include "../lv_misc/lv_math.h"
/*********************
* DEFINES
*********************/
#define LABEL_RECOLOR_PAR_LENGTH 6
/**********************
* TYPEDEFS
**********************/
enum {
CMD_STATE_WAIT,
CMD_STATE_PAR,
CMD_STATE_IN,
};
typedef uint8_t cmd_state_t;
/**********************
* STATIC PROTOTYPES
**********************/
static uint8_t hex_char_to_num(char hex);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Write a text
* @param coords coordinates of the label
* @param mask the label will be drawn only in this area
* @param style pointer to a style
* @param opa_scale scale down all opacities by the factor
* @param txt 0 terminated text to write
* @param flag settings for the text from 'txt_flag_t' enum
* @param offset text offset in x and y direction (NULL if unused)
*
*/
void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale,
const char * txt, lv_txt_flag_t flag, lv_point_t * offset)
{
const lv_font_t * font = style->text.font;
lv_coord_t w;
if((flag & LV_TXT_FLAG_EXPAND) == 0) {
/*Normally use the label's width as width*/
w = lv_area_get_width(coords);
} else {
/*If EXAPND is enabled then not limit the text's width to the object's width*/
lv_point_t p;
lv_txt_get_size(&p, txt, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, flag);
w = p.x;
}
lv_coord_t line_height = lv_font_get_height(font) + style->text.line_space;
/*Init variables for the first line*/
lv_coord_t line_width = 0;
lv_point_t pos;
pos.x = coords->x1;
pos.y = coords->y1;
lv_coord_t x_ofs = 0;
lv_coord_t y_ofs = 0;
if(offset != NULL) {
x_ofs = offset->x;
y_ofs = offset->y;
pos.y += y_ofs;
}
uint32_t line_start = 0;
uint32_t line_end = lv_txt_get_next_line(txt, font, style->text.letter_space, w, flag);
/*Go the first visible line*/
while(pos.y + line_height < mask->y1) {
/*Go to next line*/
line_start = line_end;
line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag);
pos.y += line_height;
if(txt[line_start] == '\0') return;
}
/*Align to middle*/
if(flag & LV_TXT_FLAG_CENTER) {
line_width = lv_txt_get_width(&txt[line_start], line_end - line_start,
font, style->text.letter_space, flag);
pos.x += (lv_area_get_width(coords) - line_width) / 2;
}
/*Align to the right*/
else if(flag & LV_TXT_FLAG_RIGHT) {
line_width = lv_txt_get_width(&txt[line_start], line_end - line_start,
font, style->text.letter_space, flag);
pos.x += lv_area_get_width(coords) - line_width;
}
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->text.opa : (uint16_t)((uint16_t) style->text.opa * opa_scale) >> 8;
cmd_state_t cmd_state = CMD_STATE_WAIT;
uint32_t i;
uint16_t par_start = 0;
lv_color_t recolor;
lv_coord_t letter_w;
/*Real draw need a background color for higher bpp letter*/
#if LV_VDB_SIZE == 0
lv_rletter_set_background(style->body.main_color);
#endif
/*Write out all lines*/
while(txt[line_start] != '\0') {
if(offset != NULL) {
pos.x += x_ofs;
}
/*Write all letter of a line*/
cmd_state = CMD_STATE_WAIT;
i = line_start;
uint32_t letter;
while(i < line_end) {
letter = lv_txt_encoded_next(txt, &i);
/*Handle the re-color command*/
if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) {
if(cmd_state == CMD_STATE_WAIT) { /*Start char*/
par_start = i;
cmd_state = CMD_STATE_PAR;
continue;
} else if(cmd_state == CMD_STATE_PAR) { /*Other start char in parameter escaped cmd. char */
cmd_state = CMD_STATE_WAIT;
} else if(cmd_state == CMD_STATE_IN) { /*Command end */
cmd_state = CMD_STATE_WAIT;
continue;
}
}
/*Skip the color parameter and wait the space after it*/
if(cmd_state == CMD_STATE_PAR) {
if(letter == ' ') {
/*Get the parameter*/
if(i - par_start == LABEL_RECOLOR_PAR_LENGTH + 1) {
char buf[LABEL_RECOLOR_PAR_LENGTH + 1];
memcpy(buf, &txt[par_start], LABEL_RECOLOR_PAR_LENGTH);
buf[LABEL_RECOLOR_PAR_LENGTH] = '\0';
int r, g, b;
r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]);
g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]);
b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]);
recolor = LV_COLOR_MAKE(r, g, b);
} else {
recolor.full = style->text.color.full;
}
cmd_state = CMD_STATE_IN; /*After the parameter the text is in the command*/
}
continue;
}
}
lv_color_t color = style->text.color;
if(cmd_state == CMD_STATE_IN) color = recolor;
letter_fp(&pos, mask, font, letter, color, opa);
letter_w = lv_font_get_width(font, letter);
if(letter_w > 0){
pos.x += letter_w + style->text.letter_space;
}
}
/*Go to next line*/
line_start = line_end;
line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag);
pos.x = coords->x1;
/*Align to middle*/
if(flag & LV_TXT_FLAG_CENTER) {
line_width = lv_txt_get_width(&txt[line_start], line_end - line_start,
font, style->text.letter_space, flag);
pos.x += (lv_area_get_width(coords) - line_width) / 2;
}
/*Align to the right*/
else if(flag & LV_TXT_FLAG_RIGHT) {
line_width = lv_txt_get_width(&txt[line_start], line_end - line_start,
font, style->text.letter_space, flag);
pos.x += lv_area_get_width(coords) - line_width;
}
/*Go the next line position*/
pos.y += line_height;
if(pos.y > mask->y2) return;
}
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Convert a hexadecimal characters to a number (0..15)
* @param hex Pointer to a hexadecimal character (0..9, A..F)
* @return the numerical value of `hex` or 0 on error
*/
static uint8_t hex_char_to_num(char hex)
{
uint8_t result = 0;
if(hex >= '0' && hex <= '9') {
result = hex - '0';
}
else {
if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/
switch(hex) {
case 'A':
result = 10;
break;
case 'B':
result = 11;
break;
case 'C':
result = 12;
break;
case 'D':
result = 13;
break;
case 'E':
result = 14;
break;
case 'F':
result = 15;
break;
default:
result = 0;
break;
}
}
return result;
}

View File

@ -0,0 +1,53 @@
/**
* @file lv_draw_label.h
*
*/
#ifndef LV_DRAW_LABEL_H
#define LV_DRAW_LABEL_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_draw.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Write a text
* @param coords coordinates of the label
* @param mask the label will be drawn only in this area
* @param style pointer to a style
* @param opa_scale scale down all opacities by the factor
* @param txt 0 terminated text to write
* @param flag settings for the text from 'txt_flag_t' enum
* @param offset text offset in x and y direction (NULL if unused)
*
*/
void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale,
const char * txt, lv_txt_flag_t flag, lv_point_t * offset);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_DRAW_LABEL_H*/

View File

@ -0,0 +1,607 @@
/**
* @file lv_draw_line.c
*
*/
/*********************
* INCLUDES
*********************/
#include <stdio.h>
#include "lv_draw.h"
#include "../lv_misc/lv_math.h"
/*********************
* DEFINES
*********************/
#if LV_COMPILER_VLA_SUPPORTED == 0
#define LINE_MAX_WIDTH 64
#endif
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_point_t p1;
lv_point_t p2;
lv_point_t p_act;
lv_coord_t dx;
lv_coord_t sx; /*-1: x1 < x2; 1: x2 >= x1*/
lv_coord_t dy;
lv_coord_t sy; /*-1: y1 < y2; 1: y2 >= y1*/
lv_coord_t err;
lv_coord_t e2;
bool hor; /*Rather horizontal or vertical*/
} line_draw_t;
typedef struct {
lv_coord_t width;
lv_coord_t width_1;
lv_coord_t width_half;
} line_width_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2);
static bool line_next(line_draw_t * line);
static bool line_next_y(line_draw_t * line);
static bool line_next_x(line_draw_t * line);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Draw a line
* @param point1 first point of the line
* @param point2 second point of the line
* @param mask the line will be drawn only on this area
* @param style pointer to a line's style
* @param opa_scale scale down all opacities by the factor
*/
void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask,
const lv_style_t * style, lv_opa_t opa_scale)
{
if(style->line.width == 0) return;
if(point1->x == point2->x && point1->y == point2->y) return;
line_draw_t main_line;
lv_point_t p1;
lv_point_t p2;
/*If the line if rather vertical then be sure y1 < y2 else x1 < x2*/
if(LV_MATH_ABS(point1->x - point2->x) > LV_MATH_ABS(point1->y - point2->y)) {
/*Steps less in y then x -> rather horizontal*/
if(point1->x < point2->x) {
p1.x = point1->x;
p1.y = point1->y;
p2.x = point2->x;
p2.y = point2->y;
} else {
p1.x = point2->x;
p1.y = point2->y;
p2.x = point1->x;
p2.y = point1->y;
}
} else {
/*Steps less in x then y -> rather vertical*/
if(point1->y < point2->y) {
p1.x = point1->x;
p1.y = point1->y;
p2.x = point2->x;
p2.y = point2->y;
} else {
p1.x = point2->x;
p1.y = point2->y;
p2.x = point1->x;
p2.y = point1->y;
}
}
line_init(&main_line, &p1, &p2);
/*Special case draw a horizontal line*/
if(main_line.p1.y == main_line.p2.y) {
line_draw_hor(&main_line, mask, style, opa_scale);
}
/*Special case draw a vertical line*/
else if(main_line.p1.x == main_line.p2.x) {
line_draw_ver(&main_line, mask, style, opa_scale);
}
/*Arbitrary skew line*/
else {
bool dir_ori = false;
#if LV_ANTIALIAS
lv_point_t p_tmp;
if(main_line.hor) {
if(main_line.p1.y < main_line.p2.y) {
dir_ori = true;
p_tmp.x = main_line.p2.x;
p_tmp.y = main_line.p2.y - 1;
line_init(&main_line, &p1, &p_tmp);
main_line.sy = LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/
}
else if(main_line.p1.y > main_line.p2.y) {
dir_ori = false;
p_tmp.x = main_line.p2.x;
p_tmp.y = main_line.p2.y + 1;
line_init(&main_line, &p1, &p_tmp);
main_line.sy = -LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/
}
}
else {
if(main_line.p1.x < main_line.p2.x) {
dir_ori = true;
p_tmp.x = main_line.p2.x - 1;
p_tmp.y = main_line.p2.y;
line_init(&main_line, &p1, &p_tmp);
main_line.sx = LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/
}
else if(main_line.p1.x > main_line.p2.x) {
dir_ori = false;
p_tmp.x = main_line.p2.x + 1;
p_tmp.y = main_line.p2.y;
line_init(&main_line, &p1, &p_tmp);
main_line.sx = -LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/
}
}
#endif
line_draw_skew(&main_line, dir_ori, mask, style, opa_scale);
}
}
/**********************
* STATIC FUNCTIONS
**********************/
static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
{
lv_coord_t width = style->line.width - 1;
lv_coord_t width_half = width >> 1;
lv_coord_t width_1 = width & 0x1;
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8;
lv_area_t act_area;
act_area.x1 = main_line->p1.x;
act_area.x2 = main_line->p2.x;
act_area.y1 = main_line->p1.y - width_half - width_1;
act_area.y2 = main_line->p2.y + width_half ;
lv_area_t draw_area;
draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);
draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);
draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);
draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);
fill_fp(&draw_area, mask, style->line.color, opa);
}
static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
{
lv_coord_t width = style->line.width - 1;
lv_coord_t width_half = width >> 1;
lv_coord_t width_1 = width & 0x1;
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8;
lv_area_t act_area;
act_area.x1 = main_line->p1.x - width_half;
act_area.x2 = main_line->p2.x + width_half + width_1;
act_area.y1 = main_line->p1.y;
act_area.y2 = main_line->p2.y;
lv_area_t draw_area;
draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);
draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);
draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);
draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);
fill_fp(&draw_area, mask, style->line.color, opa);
}
static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
{
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8;
lv_point_t vect_main, vect_norm;
vect_main.x = main_line->p2.x - main_line->p1.x;
vect_main.y = main_line->p2.y - main_line->p1.y;
if(main_line->hor) {
if(main_line->p1.y < main_line->p2.y + dir_ori) {
vect_norm.x = - vect_main.y;
vect_norm.y = vect_main.x;
} else {
vect_norm.x = vect_main.y;
vect_norm.y = -vect_main.x;
}
} else {
if(main_line->p1.x < main_line->p2.x + dir_ori) {
vect_norm.x = vect_main.y;
vect_norm.y = - vect_main.x;
} else {
vect_norm.x = - vect_main.y;
vect_norm.y = vect_main.x;
}
}
/* In case of a short but tick line the perpendicular ending is longer then the real line.
* it would break the calculations so make the normal vector larger*/
vect_norm.x = vect_norm.x << 4;
vect_norm.y = vect_norm.y << 4;
lv_coord_t width;
width = style->line.width;
/* The pattern stores the points of the line ending. It has the good direction and length.
* The worth case is the 45° line where pattern can have 1.41 x `width` points*/
#if LV_COMPILER_VLA_SUPPORTED
lv_point_t pattern[width * 2];
#else
lv_point_t pattern[LINE_MAX_WIDTH];
#endif
lv_coord_t i = 0;
/*Create a perpendicular pattern (a small line)*/
if(width != 0) {
line_draw_t pattern_line;
lv_point_t p0 = {0, 0};
line_init(&pattern_line, &p0, &vect_norm);
uint32_t width_sqr = width * width;
/* Run for a lot of times. Meanwhile the real width will be determined as well */
for(i = 0; i < (lv_coord_t)sizeof(pattern); i ++) {
pattern[i].x = pattern_line.p_act.x;
pattern[i].y = pattern_line.p_act.y;
/*Finish the pattern line if it's length equal to the desired width (Use Pythagoras theorem)*/
uint32_t sqr = pattern_line.p_act.x * pattern_line.p_act.x + pattern_line.p_act.y * pattern_line.p_act.y;
if(sqr >= width_sqr) {
width = i;
#if LV_ANTIALIAS
width--;
#endif
break;
}
line_next(&pattern_line);
}
}
#if LV_ANTIALIAS
lv_coord_t width_safe = width;
if(width == 0) width_safe = 1;
lv_coord_t aa_last_corner;
aa_last_corner = 0;
#endif
lv_coord_t x_center_ofs = 0;
lv_coord_t y_center_ofs = 0;
if(width != 0) {
x_center_ofs = pattern[width - 1].x / 2;
y_center_ofs = pattern[width - 1].y / 2;
}
else {
if(main_line->hor && main_line->p1.y >= main_line->p2.y + dir_ori) pattern[0].y --;
if(!main_line->hor && main_line->p1.x >= main_line->p2.x + dir_ori) pattern[0].x --;
}
/* Make the coordinates relative to the center */
for(i = 0; i < width; i++) {
pattern[i].x -= x_center_ofs;
pattern[i].y -= y_center_ofs;
#if LV_ANTIALIAS
if(i != 0) {
if(main_line->hor) {
if(pattern[i - 1].x != pattern[i].x) {
lv_coord_t seg_w = pattern[i].y - pattern[aa_last_corner].y;
if(main_line->sy < 0) {
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y + seg_w + 1,
seg_w, mask, style->line.color, opa);
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y + seg_w + 1,
-seg_w, mask, style->line.color, opa);
} else {
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y,
seg_w, mask, style->line.color, opa);
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y,
-seg_w, mask, style->line.color, opa);
}
aa_last_corner = i;
}
} else {
if(pattern[i - 1].y != pattern[i].y) {
lv_coord_t seg_w = pattern[i].x - pattern[aa_last_corner].x;
if(main_line->sx < 0) {
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w + 1, main_line->p1.y + pattern[aa_last_corner].y - 1,
seg_w, mask, style->line.color, opa);
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w + 1, main_line->p2.y + pattern[aa_last_corner].y + 1,
-seg_w, mask, style->line.color, opa);
} else {
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x, main_line->p1.y + pattern[aa_last_corner].y - 1,
seg_w, mask, style->line.color, opa);
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x, main_line->p2.y + pattern[aa_last_corner].y + 1,
-seg_w, mask, style->line.color, opa);
}
aa_last_corner = i;
}
}
}
#endif
}
#if LV_ANTIALIAS
/*Add the last part of anti-aliasing for the perpendicular ending*/
if(width != 0) { /*Due to rounding error with very thin lines it looks ugly*/
if(main_line->hor) {
lv_coord_t seg_w = pattern[width_safe - 1].y - pattern[aa_last_corner].y;
if(main_line->sy < 0) {
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y + seg_w,
seg_w + main_line->sy, mask, style->line.color, opa);
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y + seg_w,
-(seg_w + main_line->sy), mask, style->line.color, opa);
} else {
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y,
seg_w + main_line->sy, mask, style->line.color, opa);
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y,
-(seg_w + main_line->sy), mask, style->line.color, opa);
}
} else {
lv_coord_t seg_w = pattern[width_safe - 1].x - pattern[aa_last_corner].x;
if(main_line->sx < 0) {
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w, main_line->p1.y + pattern[aa_last_corner].y - 1,
seg_w + main_line->sx, mask, style->line.color, opa);
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w, main_line->p2.y + pattern[aa_last_corner].y + 1,
-(seg_w + main_line->sx), mask, style->line.color, opa);
} else {
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x, main_line->p1.y + pattern[aa_last_corner].y - 1,
seg_w + main_line->sx, mask, style->line.color, opa);
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x, main_line->p2.y + pattern[aa_last_corner].y + 1,
-(seg_w + main_line->sx), mask, style->line.color, opa);
}
}
}
#endif
#if LV_ANTIALIAS
/*Shift the anti aliasing on the edges (-1, 1 or 0 (zero only in case width == 0))*/
lv_coord_t aa_shift1;
lv_coord_t aa_shift2;
if(main_line->hor == false) {
if(main_line->sx < 0) {
aa_shift1 = -1;
aa_shift2 = width == 0 ? 0 : aa_shift1;
} else {
aa_shift2 = 1;
aa_shift1 = width == 0 ? 0 : aa_shift2;
}
} else {
if(main_line->sy < 0) {
aa_shift1 = -1;
aa_shift2 = width == 0 ? 0 : aa_shift1;
} else {
aa_shift2 = 1;
aa_shift1 = width == 0 ? 0 : aa_shift2;
}
}
#endif
volatile lv_point_t prev_p;
prev_p.x = main_line->p1.x;
prev_p.y = main_line->p1.y;
lv_area_t draw_area;
bool first_run = true;
if(main_line->hor) {
while(line_next_y(main_line)) {
for(i = 0; i < width; i++) {
draw_area.x1 = prev_p.x + pattern[i].x;
draw_area.y1 = prev_p.y + pattern[i].y;
draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x - 1;
draw_area.y2 = draw_area.y1;
fill_fp(&draw_area, mask, style->line.color, opa);
/* Fill the gaps
* When stepping in y one pixel remains empty on every corner (don't do this on the first segment ) */
if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) {
px_fp(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa);
}
}
#if LV_ANTIALIAS
lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1,
-(main_line->p_act.x - prev_p.x), mask, style->line.color, opa);
lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2,
main_line->p_act.x - prev_p.x, mask, style->line.color, opa);
#endif
first_run = false;
prev_p.x = main_line->p_act.x;
prev_p.y = main_line->p_act.y;
}
for(i = 0; i < width; i++) {
draw_area.x1 = prev_p.x + pattern[i].x;
draw_area.y1 = prev_p.y + pattern[i].y;
draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x;
draw_area.y2 = draw_area.y1;
fill_fp(&draw_area, mask, style->line.color, opa);
/* Fill the gaps
* When stepping in y one pixel remains empty on every corner */
if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) {
px_fp(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa);
}
}
#if LV_ANTIALIAS
lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1,
-(main_line->p_act.x - prev_p.x + 1), mask, style->line.color, opa);
lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2,
main_line->p_act.x - prev_p.x + 1, mask, style->line.color, opa);
#endif
}
/*Rather a vertical line*/
else {
while(line_next_x(main_line)) {
for(i = 0; i < width; i++) {
draw_area.x1 = prev_p.x + pattern[i].x;
draw_area.y1 = prev_p.y + pattern[i].y;
draw_area.x2 = draw_area.x1;
draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y - 1;
fill_fp(&draw_area, mask, style->line.color, opa);
/* Fill the gaps
* When stepping in x one pixel remains empty on every corner (don't do this on the first segment ) */
if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) {
px_fp(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa);
}
}
#if LV_ANTIALIAS
lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y,
-(main_line->p_act.y - prev_p.y), mask, style->line.color, opa);
lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y,
main_line->p_act.y - prev_p.y, mask, style->line.color, opa);
#endif
first_run = false;
prev_p.x = main_line->p_act.x;
prev_p.y = main_line->p_act.y;
}
/*Draw the last part*/
for(i = 0; i < width; i++) {
draw_area.x1 = prev_p.x + pattern[i].x;
draw_area.y1 = prev_p.y + pattern[i].y;
draw_area.x2 = draw_area.x1;
draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y;
fill_fp(&draw_area, mask, style->line.color, opa);
/* Fill the gaps
* When stepping in x one pixel remains empty on every corner */
if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) {
px_fp(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa);
}
}
#if LV_ANTIALIAS
lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y,
-(main_line->p_act.y - prev_p.y + 1), mask, style->line.color, opa);
lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y,
main_line->p_act.y - prev_p.y + 1, mask, style->line.color, opa);
#endif
}
}
static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2)
{
line->p1.x = p1->x;
line->p1.y = p1->y;
line->p2.x = p2->x;
line->p2.y = p2->y;
line->dx = LV_MATH_ABS(line->p2.x - line->p1.x);
line->sx = line->p1.x < line->p2.x ? 1 : -1;
line->dy = LV_MATH_ABS(line->p2.y - line->p1.y);
line->sy = line->p1.y < line->p2.y ? 1 : -1;
line->err = (line->dx > line->dy ? line->dx : -line->dy) / 2;
line->e2 = 0;
line->hor = line->dx > line->dy ? true : false; /*Rather horizontal or vertical*/
line->p_act.x = line->p1.x;
line->p_act.y = line->p1.y;
}
static bool line_next(line_draw_t * line)
{
if(line->p_act.x == line->p2.x && line->p_act.y == line->p2.y) return false;
line->e2 = line->err;
if(line->e2 > -line->dx) {
line->err -= line->dy;
line->p_act.x += line->sx;
}
if(line->e2 < line->dy) {
line->err += line->dx;
line->p_act.y += line->sy;
}
return true;
}
/**
* Iterate until step one in y direction.
* @param line
* @return
*/
static bool line_next_y(line_draw_t * line)
{
lv_coord_t last_y = line->p_act.y;
do {
if(!line_next(line)) return false;
} while(last_y == line->p_act.y);
return true;
}
/**
* Iterate until step one in x direction.
* @param line
* @return
*/
static bool line_next_x(line_draw_t * line)
{
lv_coord_t last_x = line->p_act.x;
do {
if(!line_next(line)) return false;
} while(last_x == line->p_act.x);
return true;
}

View File

@ -0,0 +1,49 @@
/**
* @file lv_draw_line.h
*
*/
#ifndef LV_DRAW_LINE_H
#define LV_DRAW_LINE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Draw a line
* @param point1 first point of the line
* @param point2 second point of the line
* @param mask the line will be drawn only on this area
* @param style pointer to a line's style
* @param opa_scale scale down all opacities by the factor
*/
void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask,
const lv_style_t * style, lv_opa_t opa_scale);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_DRAW_LINE_H*/

View File

@ -0,0 +1,269 @@
/**
* @file lv_draw_rbasic.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_rbasic.h"
#if USE_LV_REAL_DRAW != 0
#include "../lv_hal/lv_hal_disp.h"
#include "../lv_misc/lv_font.h"
#include "lv_draw.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
static lv_color_t letter_bg_color;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Put a pixel to the display
* @param x x coordinate of the pixel
* @param y y coordinate of the pixel
* @param mask_p the pixel will be drawn on this area
* @param color color of the pixel
* @param opa opacity (ignored, only for compatibility with lv_vpx)
*/
void lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa)
{
(void)opa; /*Opa is used only for compatibility with lv_vpx*/
lv_area_t area;
area.x1 = x;
area.y1 = y;
area.x2 = x;
area.y2 = y;
lv_rfill(&area, mask_p, color, LV_OPA_COVER);
}
/**
* Fill an area on the display
* @param cords_p coordinates of the area to fill
* @param mask_p fill only o this mask
* @param color fill color
* @param opa opacity (ignored, only for compatibility with lv_vfill)
*/
void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
lv_color_t color, lv_opa_t opa)
{
(void)opa; /*Opa is used only for compatibility with lv_vfill*/
lv_area_t masked_area;
bool union_ok = true;
if(mask_p != NULL) {
union_ok = lv_area_intersect(&masked_area, cords_p, mask_p);
} else {
lv_area_t scr_area;
lv_area_set(&scr_area, 0, 0, LV_HOR_RES - 1, LV_VER_RES - 1);
union_ok = lv_area_intersect(&masked_area, cords_p, &scr_area);
}
if(union_ok != false) {
lv_disp_fill(masked_area.x1, masked_area.y1, masked_area.x2, masked_area.y2, color);
}
}
/**
* Draw a letter to the display
* @param pos_p left-top coordinate of the latter
* @param mask_p the letter will be drawn only on this area
* @param font_p pointer to font
* @param letter a letter to draw
* @param color color of letter
* @param opa opacity of letter (ignored, only for compatibility with lv_vletter)
*/
void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
const lv_font_t * font_p, uint32_t letter,
lv_color_t color, lv_opa_t opa)
{
(void)opa; /*Opa is used only for compatibility with lv_vletter*/
static uint8_t bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
static uint8_t bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
static uint8_t bpp4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
68, 85, 102, 119,
136, 153, 170, 187,
204, 221, 238, 255
};
if(font_p == NULL) return;
uint8_t letter_w = lv_font_get_width(font_p, letter);
uint8_t letter_h = lv_font_get_height(font_p);
uint8_t bpp = lv_font_get_bpp(font_p, letter); /*Bit per pixel (1,2, 4 or 8)*/
uint8_t * bpp_opa_table;
uint8_t mask_init;
uint8_t mask;
switch(bpp) {
case 1:
bpp_opa_table = bpp1_opa_table;
mask_init = 0x80;
break;
case 2:
bpp_opa_table = bpp2_opa_table;
mask_init = 0xC0;
break;
case 4:
bpp_opa_table = bpp4_opa_table;
mask_init = 0xF0;
break;
case 8:
bpp_opa_table = NULL;
mask_init = 0xFF;
break; /*No opa table, pixel value will be used directly*/
default:
return; /*Invalid bpp. Can't render the letter*/
}
const uint8_t * map_p = lv_font_get_bitmap(font_p, letter);
if(map_p == NULL) return;
/*If the letter is completely out of mask don't draw it */
if(pos_p->x + letter_w < mask_p->x1 || pos_p->x > mask_p->x2 ||
pos_p->y + letter_h < mask_p->y1 || pos_p->y > mask_p->y2) return;
lv_coord_t col, row;
uint8_t col_bit;
uint8_t col_byte_cnt;
uint8_t width_byte_scr = letter_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/
if(letter_w & 0x7) width_byte_scr++;
uint8_t width_byte_bpp = (letter_w * bpp) >> 3; /*Letter width in byte. Real width in the font*/
if((letter_w * bpp) & 0x7) width_byte_bpp++;
/* Calculate the col/row start/end on the map*/
lv_coord_t col_start = pos_p->x >= mask_p->x1 ? 0 : mask_p->x1 - pos_p->x;
lv_coord_t col_end = pos_p->x + letter_w <= mask_p->x2 ? letter_w : mask_p->x2 - pos_p->x + 1;
lv_coord_t row_start = pos_p->y >= mask_p->y1 ? 0 : mask_p->y1 - pos_p->y;
lv_coord_t row_end = pos_p->y + letter_h <= mask_p->y2 ? letter_h : mask_p->y2 - pos_p->y + 1;
/*Move on the map too*/
map_p += (row_start * width_byte_bpp) + ((col_start * bpp) >> 3);
uint8_t letter_px;
for(row = row_start; row < row_end; row ++) {
col_byte_cnt = 0;
col_bit = (col_start * bpp) % 8;
mask = mask_init >> col_bit;
for(col = col_start; col < col_end; col ++) {
letter_px = (*map_p & mask) >> (8 - col_bit - bpp);
if(letter_px != 0) {
lv_rpx(pos_p->x + col, pos_p->y + row, mask_p, lv_color_mix(color, letter_bg_color, bpp == 8 ? letter_px : bpp_opa_table[letter_px]), LV_OPA_COVER);
}
if(col_bit < 8 - bpp) {
col_bit += bpp;
mask = mask >> bpp;
} else {
col_bit = 0;
col_byte_cnt ++;
mask = mask_init;
map_p ++;
}
}
map_p += (width_byte_bpp) - col_byte_cnt;
}
}
/**
* When the letter is ant-aliased it needs to know the background color
* @param bg_color the background color of the currently drawn letter
*/
void lv_rletter_set_background(lv_color_t color)
{
letter_bg_color = color;
}
/**
* Draw a color map to the display (image)
* @param cords_p coordinates the color map
* @param mask_p the map will drawn only on this area
* @param map_p pointer to a lv_color_t array
* @param opa opacity of the map (ignored, only for compatibility with 'lv_vmap')
* @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels
* @param alpha_byte true: extra alpha byte is inserted for every pixel (not supported, only l'v_vmap' can draw it)
* @param recolor mix the pixels with this color
* @param recolor_opa the intense of recoloring
*/
void lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,
lv_color_t recolor, lv_opa_t recolor_opa)
{
if(alpha_byte) return; /*Pixel level opacity i not supported in real map drawing*/
(void)opa; /*opa is used only for compatibility with lv_vmap*/
lv_area_t masked_a;
bool union_ok;
union_ok = lv_area_intersect(&masked_a, cords_p, mask_p);
/*If there are common part of the mask and map then draw the map*/
if(union_ok == false) return;
/*Go to the first pixel*/
lv_coord_t map_width = lv_area_get_width(cords_p);
map_p += (masked_a.y1 - cords_p->y1) * map_width * sizeof(lv_color_t);
map_p += (masked_a.x1 - cords_p->x1) * sizeof(lv_color_t);
lv_coord_t row;
if(recolor_opa == LV_OPA_TRANSP && chroma_key == false) {
lv_coord_t mask_w = lv_area_get_width(&masked_a) - 1;
for(row = masked_a.y1; row <= masked_a.y2; row++) {
lv_disp_map(masked_a.x1, row, masked_a.x1 + mask_w, row, (lv_color_t *)map_p);
map_p += map_width * sizeof(lv_color_t); /*Next row on the map*/
}
} else {
lv_color_t chroma_key_color = LV_COLOR_TRANSP;
lv_coord_t col;
for(row = masked_a.y1; row <= masked_a.y2; row++) {
for(col = masked_a.x1; col <= masked_a.x2; col++) {
lv_color_t * px_color = (lv_color_t *) &map_p[(uint32_t)(col - masked_a.x1) * sizeof(lv_color_t)];
if(chroma_key && chroma_key_color.full == px_color->full) continue;
if(recolor_opa != LV_OPA_TRANSP) {
lv_color_t recolored_px = lv_color_mix(recolor, *px_color, recolor_opa);
lv_rpx(col, row, mask_p, recolored_px, LV_OPA_COVER);
} else {
lv_rpx(col, row, mask_p, *px_color, LV_OPA_COVER);
}
}
map_p += map_width * sizeof(lv_color_t); /*Next row on the map*/
}
}
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*USE_LV_REAL_DRAW*/

View File

@ -0,0 +1,96 @@
/**
* @file lv_draw_rbasic..h
*
*/
#ifndef LV_DRAW_RBASIC_H
#define LV_DRAW_RBASIC_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_conf.h"
#else
#include "../../lv_conf.h"
#endif
#if USE_LV_REAL_DRAW != 0
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_area.h"
#include "../lv_misc/lv_font.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa);
/**
* Fill an area on the display
* @param cords_p coordinates of the area to fill
* @param mask_p fill only o this mask
* @param color fill color
* @param opa opacity (ignored, only for compatibility with lv_vfill)
*/
void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
lv_color_t color, lv_opa_t opa);
/**
* Draw a letter to the display
* @param pos_p left-top coordinate of the latter
* @param mask_p the letter will be drawn only on this area
* @param font_p pointer to font
* @param letter a letter to draw
* @param color color of letter
* @param opa opacity of letter (ignored, only for compatibility with lv_vletter)
*/
void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
const lv_font_t * font_p, uint32_t letter,
lv_color_t color, lv_opa_t opa);
/**
* When the letter is ant-aliased it needs to know the background color
* @param bg_color the background color of the currently drawn letter
*/
void lv_rletter_set_background(lv_color_t color);
/**
* Draw a color map to the display (image)
* @param cords_p coordinates the color map
* @param mask_p the map will drawn only on this area
* @param map_p pointer to a lv_color_t array
* @param opa opacity of the map (ignored, only for compatibility with 'lv_vmap')
* @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels
* @param alpha_byte true: extra alpha byte is inserted for every pixel (not supported, only l'v_vmap' can draw it)
* @param recolor mix the pixels with this color
* @param recolor_opa the intense of recoloring
*/
void lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,
lv_color_t recolor, lv_opa_t recolor_opa);
/**********************
* MACROS
**********************/
#endif /*USE_LV_REAL_DRAW*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_DRAW_RBASIC_H*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
/**
* @file lv_draw_rect.h
*
*/
#ifndef LV_DRAW_RECT_H
#define LV_DRAW_RECT_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_draw.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Draw a rectangle
* @param coords the coordinates of the rectangle
* @param mask the rectangle will be drawn only in this mask
* @param style pointer to a style
* @param opa_scale scale down all opacities by the factor
*/
void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_DRAW_RECT_H*/

View File

@ -0,0 +1,168 @@
/**
* @file lv_draw_triangle.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_triangle.h"
#include "../lv_misc/lv_math.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
static void point_swap(lv_point_t * p1, lv_point_t * p2);
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
#if USE_LV_TRIANGLE != 0
/**
*
* @param points pointer to an array with 3 points
* @param mask the triangle will be drawn only in this mask
* @param color color of the triangle
*/
void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color)
{
lv_point_t tri[3];
memcpy(tri, points, sizeof(tri));
/*Sort the vertices according to their y coordinate (0: y max, 1: y mid, 2:y min)*/
if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]);
if(tri[2].y < tri[1].y) point_swap(&tri[2], &tri[1]);
if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]);
/*Return is the triangle is degenerated*/
if(tri[0].x == tri[1].x && tri[0].y == tri[1].y) return;
if(tri[1].x == tri[2].x && tri[1].y == tri[2].y) return;
if(tri[0].x == tri[2].x && tri[0].y == tri[2].y) return;
if(tri[0].x == tri[1].x && tri[1].x == tri[2].x) return;
if(tri[0].y == tri[1].y && tri[1].y == tri[2].y) return;
/*Draw the triangle*/
lv_point_t edge1;
lv_coord_t dx1 = LV_MATH_ABS(tri[0].x - tri[1].x);
lv_coord_t sx1 = tri[0].x < tri[1].x ? 1 : -1;
lv_coord_t dy1 = LV_MATH_ABS(tri[0].y - tri[1].y);
lv_coord_t sy1 = tri[0].y < tri[1].y ? 1 : -1;
lv_coord_t err1 = (dx1 > dy1 ? dx1 : -dy1) / 2;
lv_coord_t err_tmp1;
lv_point_t edge2;
lv_coord_t dx2 = LV_MATH_ABS(tri[0].x - tri[2].x);
lv_coord_t sx2 = tri[0].x < tri[2].x ? 1 : -1;
lv_coord_t dy2 = LV_MATH_ABS(tri[0].y - tri[2].y);
lv_coord_t sy2 = tri[0].y < tri[2].y ? 1 : -1;
lv_coord_t err2 = (dx1 > dy2 ? dx2 : -dy2) / 2;
lv_coord_t err_tmp2;
lv_coord_t y1_tmp;
lv_coord_t y2_tmp;
edge1.x = tri[0].x;
edge1.y = tri[0].y;
edge2.x = tri[0].x;
edge2.y = tri[0].y;
lv_area_t act_area;
lv_area_t draw_area;
while(1) {
act_area.x1 = edge1.x;
act_area.x2 = edge2.x ;
act_area.y1 = edge1.y;
act_area.y2 = edge2.y ;
draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);
draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);
draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);
draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);
draw_area.x2--; /*Do not draw most right pixel because it will be drawn by the adjacent triangle*/
fill_fp(&draw_area, mask, color, LV_OPA_50);
/*Calc. the next point of edge1*/
y1_tmp = edge1.y;
do {
if(edge1.x == tri[1].x && edge1.y == tri[1].y) {
dx1 = LV_MATH_ABS(tri[1].x - tri[2].x);
sx1 = tri[1].x < tri[2].x ? 1 : -1;
dy1 = LV_MATH_ABS(tri[1].y - tri[2].y);
sy1 = tri[1].y < tri[2].y ? 1 : -1;
err1 = (dx1 > dy1 ? dx1 : -dy1) / 2;
} else if(edge1.x == tri[2].x && edge1.y == tri[2].y) return;
err_tmp1 = err1;
if(err_tmp1 > -dx1) {
err1 -= dy1;
edge1.x += sx1;
}
if(err_tmp1 < dy1) {
err1 += dx1;
edge1.y += sy1;
}
} while(edge1.y == y1_tmp);
/*Calc. the next point of edge2*/
y2_tmp = edge2.y;
do {
if(edge2.x == tri[2].x && edge2.y == tri[2].y) return;
err_tmp2 = err2;
if(err_tmp2 > -dx2) {
err2 -= dy2;
edge2.x += sx2;
}
if(err_tmp2 < dy2) {
err2 += dx2;
edge2.y += sy2;
}
} while(edge2.y == y2_tmp);
}
}
#endif
/**********************
* STATIC FUNCTIONS
**********************/
#if USE_LV_TRIANGLE != 0
/**
* Swap two points
* p1 pointer to the first point
* p2 pointer to the second point
*/
static void point_swap(lv_point_t * p1, lv_point_t * p2)
{
lv_point_t tmp;
tmp.x = p1->x;
tmp.y = p1->y;
p1->x = p2->x;
p1->y = p2->y;
p2->x = tmp.x;
p2->y = tmp.y;
}
#endif

View File

@ -0,0 +1,51 @@
/**
* @file lv_draw_triangle.h
*
*/
#ifndef LV_DRAW_TRIANGLE_H
#define LV_DRAW_TRIANGLE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_draw.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/*Experimental use for 3D modeling*/
#define USE_LV_TRIANGLE 1
#if USE_LV_TRIANGLE != 0
/**
*
* @param points pointer to an array with 3 points
* @param mask the triangle will be drawn only in this mask
* @param color color of the triangle
*/
void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color);
#endif
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_DRAW_TRIANGLE_H*/

View File

@ -0,0 +1,691 @@
/**
* @file lv_vdraw.c
*
*/
#include "lv_draw_vbasic.h"
#include <stdint.h>
#include <string.h>
#include "../lv_hal/lv_hal_disp.h"
#include "../lv_misc/lv_area.h"
#include "../lv_misc/lv_font.h"
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_log.h"
#if LV_VDB_SIZE != 0
#include <stddef.h>
#include "../lv_core/lv_vdb.h"
#include "lv_draw.h"
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
#define VFILL_HW_ACC_SIZE_LIMIT 50 /*Always fill < 50 px with 'sw_color_fill' because of the hw. init overhead*/
#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);
static void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa);
#if LV_COLOR_SCREEN_TRANSP
static inline lv_color_t color_mix_2_alpha(lv_color_t bg_color, lv_opa_t bg_opa, lv_color_t fg_color, lv_opa_t fg_opa);
#endif
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Put a pixel in the Virtual Display Buffer
* @param x pixel x coordinate
* @param y pixel y coordinate
* @param mask_p fill only on this mask (truncated to VDB area)
* @param color pixel color
* @param opa opacity of the area (0..255)
*/
void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa)
{
if(opa < LV_OPA_MIN) return;
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
lv_vdb_t * vdb_p = lv_vdb_get();
if(!vdb_p) {
LV_LOG_WARN("Invalid VDB pointer");
return;
}
/*Pixel out of the mask*/
if(x < mask_p->x1 || x > mask_p->x2 ||
y < mask_p->y1 || y > mask_p->y2) {
return;
}
uint32_t vdb_width = lv_area_get_width(&vdb_p->area);
/*Make the coordinates relative to VDB*/
x -= vdb_p->area.x1;
y -= vdb_p->area.y1;
lv_disp_t * disp = lv_disp_get_active();
if(disp->driver.vdb_wr) {
disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, x, y, color, opa);
} else {
lv_color_t * vdb_px_p = vdb_p->buf + y * vdb_width + x;
#if LV_COLOR_SCREEN_TRANSP == 0
if(opa == LV_OPA_COVER) {
*vdb_px_p = color;
} else {
*vdb_px_p = lv_color_mix(color, *vdb_px_p, opa);
}
#else
*vdb_px_p = color_mix_2_alpha(*vdb_px_p, (*vdb_px_p).alpha, color, opa);
#endif
}
}
/**
* Fill an area in the Virtual Display Buffer
* @param cords_p coordinates of the area to fill
* @param mask_p fill only o this mask (truncated to VDB area)
* @param color fill color
* @param opa opacity of the area (0..255)
*/
void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
lv_color_t color, lv_opa_t opa)
{
if(opa < LV_OPA_MIN) return;
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
lv_area_t res_a;
bool union_ok;
lv_vdb_t * vdb_p = lv_vdb_get();
if(!vdb_p) {
LV_LOG_WARN("Invalid VDB pointer");
return;
}
/*Get the union of cord and mask*/
/* The mask is already truncated to the vdb size
* in 'lv_refr_area_with_vdb' function */
union_ok = lv_area_intersect(&res_a, cords_p, mask_p);
/*If there are common part of the three area then draw to the vdb*/
if(union_ok == false) return;
lv_area_t vdb_rel_a; /*Stores relative coordinates on vdb*/
vdb_rel_a.x1 = res_a.x1 - vdb_p->area.x1;
vdb_rel_a.y1 = res_a.y1 - vdb_p->area.y1;
vdb_rel_a.x2 = res_a.x2 - vdb_p->area.x1;
vdb_rel_a.y2 = res_a.y2 - vdb_p->area.y1;
lv_color_t * vdb_buf_tmp = vdb_p->buf;
uint32_t vdb_width = lv_area_get_width(&vdb_p->area);
/*Move the vdb_tmp to the first row*/
vdb_buf_tmp += vdb_width * vdb_rel_a.y1;
#if USE_LV_GPU
static LV_ATTRIBUTE_MEM_ALIGN lv_color_t color_array_tmp[LV_HOR_RES]; /*Used by 'lv_disp_mem_blend'*/
static lv_coord_t last_width = -1;
lv_coord_t w = lv_area_get_width(&vdb_rel_a);
/*Don't use hw. acc. for every small fill (because of the init overhead)*/
if(w < VFILL_HW_ACC_SIZE_LIMIT) {
sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);
}
/*Not opaque fill*/
else if(opa == LV_OPA_COVER) {
/*Use hw fill if present*/
if(lv_disp_is_mem_fill_supported()) {
lv_coord_t row;
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
lv_disp_mem_fill(&vdb_buf_tmp[vdb_rel_a.x1], w, color);
vdb_buf_tmp += vdb_width;
}
}
/*Use hw blend if present and the area is not too small*/
else if(lv_area_get_height(&vdb_rel_a) > VFILL_HW_ACC_SIZE_LIMIT &&
lv_disp_is_mem_blend_supported()) {
/*Fill a one line sized buffer with a color and blend this later*/
if(color_array_tmp[0].full != color.full || last_width != w) {
uint16_t i;
for(i = 0; i < w; i++) {
color_array_tmp[i].full = color.full;
}
last_width = w;
}
/*Blend the filled line to every line VDB line-by-line*/
lv_coord_t row;
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
lv_disp_mem_blend(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa);
vdb_buf_tmp += vdb_width;
}
}
/*Else use sw fill if no better option*/
else {
sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);
}
}
/*Fill with opacity*/
else {
/*Use hw blend if present*/
if(lv_disp_is_mem_blend_supported()) {
if(color_array_tmp[0].full != color.full || last_width != w) {
uint16_t i;
for(i = 0; i < w; i++) {
color_array_tmp[i].full = color.full;
}
last_width = w;
}
lv_coord_t row;
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
lv_disp_mem_blend(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa);
vdb_buf_tmp += vdb_width;
}
}
/*Use sw fill with opa if no better option*/
else {
sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);
}
}
#else
sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);
#endif
}
/**
* Draw a letter in the Virtual Display Buffer
* @param pos_p left-top coordinate of the latter
* @param mask_p the letter will be drawn only on this area (truncated to VDB area)
* @param font_p pointer to font
* @param letter a letter to draw
* @param color color of letter
* @param opa opacity of letter (0..255)
*/
void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
const lv_font_t * font_p, uint32_t letter,
lv_color_t color, lv_opa_t opa)
{
const uint8_t bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
const uint8_t bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
const uint8_t bpp4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
68, 85, 102, 119,
136, 153, 170, 187,
204, 221, 238, 255
};
if(opa < LV_OPA_MIN) return;
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
if(font_p == NULL) {
LV_LOG_WARN("Font: character's bitmap not found");
return;
}
lv_coord_t pos_x = pos_p->x;
lv_coord_t pos_y = pos_p->y;
uint8_t letter_w = lv_font_get_real_width(font_p, letter);
uint8_t letter_h = lv_font_get_height(font_p);
uint8_t bpp = lv_font_get_bpp(font_p, letter); /*Bit per pixel (1,2, 4 or 8)*/
const uint8_t * bpp_opa_table;
uint8_t mask_init;
uint8_t mask;
if(lv_font_is_monospace(font_p, letter)) {
pos_x += (lv_font_get_width(font_p, letter) - letter_w) / 2;
}
switch(bpp) {
case 1:
bpp_opa_table = bpp1_opa_table;
mask_init = 0x80;
break;
case 2:
bpp_opa_table = bpp2_opa_table;
mask_init = 0xC0;
break;
case 4:
bpp_opa_table = bpp4_opa_table;
mask_init = 0xF0;
break;
case 8:
bpp_opa_table = NULL;
mask_init = 0xFF;
break; /*No opa table, pixel value will be used directly*/
default:
return; /*Invalid bpp. Can't render the letter*/
}
const uint8_t * map_p = lv_font_get_bitmap(font_p, letter);
if(map_p == NULL) return;
/*If the letter is completely out of mask don't draw it */
if(pos_x + letter_w < mask_p->x1 || pos_x > mask_p->x2 ||
pos_y + letter_h < mask_p->y1 || pos_y > mask_p->y2) return;
lv_vdb_t * vdb_p = lv_vdb_get();
if(!vdb_p) {
LV_LOG_WARN("Invalid VDB pointer");
return;
}
lv_coord_t vdb_width = lv_area_get_width(&vdb_p->area);
lv_color_t * vdb_buf_tmp = vdb_p->buf;
lv_coord_t col, row;
uint8_t col_bit;
uint8_t col_byte_cnt;
uint8_t width_byte_scr = letter_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/
if(letter_w & 0x7) width_byte_scr++;
uint8_t width_byte_bpp = (letter_w * bpp) >> 3; /*Letter width in byte. Real width in the font*/
if((letter_w * bpp) & 0x7) width_byte_bpp++;
/* Calculate the col/row start/end on the map*/
lv_coord_t col_start = pos_x >= mask_p->x1 ? 0 : mask_p->x1 - pos_x;
lv_coord_t col_end = pos_x + letter_w <= mask_p->x2 ? letter_w : mask_p->x2 - pos_x + 1;
lv_coord_t row_start = pos_y >= mask_p->y1 ? 0 : mask_p->y1 - pos_y;
lv_coord_t row_end = pos_y + letter_h <= mask_p->y2 ? letter_h : mask_p->y2 - pos_y + 1;
/*Set a pointer on VDB to the first pixel of the letter*/
vdb_buf_tmp += ((pos_y - vdb_p->area.y1) * vdb_width)
+ pos_x - vdb_p->area.x1;
/*If the letter is partially out of mask the move there on VDB*/
vdb_buf_tmp += (row_start * vdb_width) + col_start;
/*Move on the map too*/
map_p += (row_start * width_byte_bpp) + ((col_start * bpp) >> 3);
lv_disp_t * disp = lv_disp_get_active();
uint8_t letter_px;
lv_opa_t px_opa;
for(row = row_start; row < row_end; row ++) {
col_byte_cnt = 0;
col_bit = (col_start * bpp) % 8;
mask = mask_init >> col_bit;
for(col = col_start; col < col_end; col ++) {
letter_px = (*map_p & mask) >> (8 - col_bit - bpp);
if(letter_px != 0) {
if(opa == LV_OPA_COVER) {
px_opa = bpp == 8 ? letter_px : bpp_opa_table[letter_px];
} else {
px_opa = bpp == 8 ?
(uint16_t)((uint16_t)letter_px * opa) >> 8 :
(uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8;
}
if(disp->driver.vdb_wr) {
disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width,
(col + pos_x) - vdb_p->area.x1, (row + pos_y) - vdb_p->area.y1,
color, px_opa);
} else {
#if LV_COLOR_SCREEN_TRANSP == 0
*vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, px_opa);
#else
*vdb_buf_tmp = color_mix_2_alpha(*vdb_buf_tmp, (*vdb_buf_tmp).alpha, color, px_opa);
#endif
}
}
vdb_buf_tmp++;
if(col_bit < 8 - bpp) {
col_bit += bpp;
mask = mask >> bpp;
} else {
col_bit = 0;
col_byte_cnt ++;
mask = mask_init;
map_p ++;
}
}
map_p += (width_byte_bpp) - col_byte_cnt;
vdb_buf_tmp += vdb_width - (col_end - col_start); /*Next row in VDB*/
}
}
/**
* Draw a color map to the display (image)
* @param cords_p coordinates the color map
* @param mask_p the map will drawn only on this area (truncated to VDB area)
* @param map_p pointer to a lv_color_t array
* @param opa opacity of the map
* @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels
* @param alpha_byte true: extra alpha byte is inserted for every pixel
* @param recolor mix the pixels with this color
* @param recolor_opa the intense of recoloring
*/
void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,
lv_color_t recolor, lv_opa_t recolor_opa)
{
if(opa < LV_OPA_MIN) return;
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
lv_area_t masked_a;
bool union_ok;
lv_vdb_t * vdb_p = lv_vdb_get();
if(!vdb_p) {
LV_LOG_WARN("Invalid VDB pointer");
return;
}
/*Get the union of map size and mask*/
/* The mask is already truncated to the vdb size
* in 'lv_refr_area_with_vdb' function */
union_ok = lv_area_intersect(&masked_a, cords_p, mask_p);
/*If there are common part of the three area then draw to the vdb*/
if(union_ok == false) return;
/*The pixel size in byte is different if an alpha byte is added too*/
uint8_t px_size_byte = alpha_byte ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t);
/*If the map starts OUT of the masked area then calc. the first pixel*/
lv_coord_t map_width = lv_area_get_width(cords_p);
if(cords_p->y1 < masked_a.y1) {
map_p += (uint32_t) map_width * ((masked_a.y1 - cords_p->y1)) * px_size_byte;
}
if(cords_p->x1 < masked_a.x1) {
map_p += (masked_a.x1 - cords_p->x1) * px_size_byte;
}
/*Stores coordinates relative to the current VDB*/
masked_a.x1 = masked_a.x1 - vdb_p->area.x1;
masked_a.y1 = masked_a.y1 - vdb_p->area.y1;
masked_a.x2 = masked_a.x2 - vdb_p->area.x1;
masked_a.y2 = masked_a.y2 - vdb_p->area.y1;
lv_coord_t vdb_width = lv_area_get_width(&vdb_p->area);
lv_color_t * vdb_buf_tmp = vdb_p->buf;
vdb_buf_tmp += (uint32_t) vdb_width * masked_a.y1; /*Move to the first row*/
vdb_buf_tmp += (uint32_t) masked_a.x1; /*Move to the first col*/
lv_coord_t row;
lv_coord_t map_useful_w = lv_area_get_width(&masked_a);
lv_disp_t * disp = lv_disp_get_active();
/*The simplest case just copy the pixels into the VDB*/
if(chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && recolor_opa == LV_OPA_TRANSP) {
/*Use the custom VDB write function is exists*/
if(disp->driver.vdb_wr) {
lv_coord_t col;
for(row = masked_a.y1; row <= masked_a.y2; row++) {
for(col = 0; col < map_useful_w; col++) {
lv_color_t px_color = *((lv_color_t *)&map_p[(uint32_t)col * px_size_byte]);
disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, col + masked_a.x1, row, px_color, opa);
}
map_p += map_width * px_size_byte; /*Next row on the map*/
}
}
/*Normal native VDB*/
else {
for(row = masked_a.y1; row <= masked_a.y2; row++) {
#if USE_LV_GPU
if(lv_disp_is_mem_blend_supported() == false) {
sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
} else {
lv_disp_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
}
#else
sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
#endif
map_p += map_width * px_size_byte; /*Next row on the map*/
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
}
}
}
/*In the other cases every pixel need to be checked one-by-one*/
else {
lv_color_t chroma_key_color = LV_COLOR_TRANSP;
lv_coord_t col;
lv_color_t last_img_px = LV_COLOR_BLACK;
lv_color_t recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa);
for(row = masked_a.y1; row <= masked_a.y2; row++) {
for(col = 0; col < map_useful_w; col++) {
lv_opa_t opa_result = opa;
uint8_t * px_color_p = (uint8_t *) &map_p[(uint32_t)col * px_size_byte];
lv_color_t px_color;
/*Calculate with the pixel level alpha*/
if(alpha_byte) {
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
px_color.full = px_color_p[0];
#elif LV_COLOR_DEPTH == 16
/*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
px_color.full = px_color_p[0] + (px_color_p[1] << 8);
#elif LV_COLOR_DEPTH == 32
px_color = *((lv_color_t *)px_color_p);
#endif
lv_opa_t px_opa = *(px_color_p + LV_IMG_PX_SIZE_ALPHA_BYTE - 1);
if(px_opa == LV_OPA_TRANSP) continue;
else if(px_opa != LV_OPA_COVER) opa_result = (uint32_t)((uint32_t)px_opa * opa_result) >> 8;
} else {
px_color = *((lv_color_t *)px_color_p);
}
/*Handle chroma key*/
if(chroma_key && px_color.full == chroma_key_color.full) continue;
/*Re-color the pixel if required*/
if(recolor_opa != LV_OPA_TRANSP) {
if(last_img_px.full != px_color.full) { /*Minor acceleration: calculate only for new colors (save the last)*/
last_img_px = px_color;
recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa);
}
/*Handle custom VDB write is present*/
if(disp->driver.vdb_wr) {
disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, col + masked_a.x1, row, recolored_px, opa_result);
}
/*Normal native VDB write*/
else {
if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col].full = recolored_px.full;
else vdb_buf_tmp[col] = lv_color_mix(recolored_px, vdb_buf_tmp[col], opa_result);
}
} else {
/*Handle custom VDB write is present*/
if(disp->driver.vdb_wr) {
disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, col + masked_a.x1, row, px_color, opa_result);
}
/*Normal native VDB write*/
else {
if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col] = px_color;
else {
#if LV_COLOR_SCREEN_TRANSP == 0
vdb_buf_tmp[col] = lv_color_mix(px_color, vdb_buf_tmp[col], opa_result);
#else
vdb_buf_tmp[col] = color_mix_2_alpha(vdb_buf_tmp[col], vdb_buf_tmp[col].alpha, px_color, opa_result);
#endif
}
}
}
}
map_p += map_width * px_size_byte; /*Next row on the map*/
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
}
}
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Blend pixels to destination memory using opacity
* @param dest a memory address. Copy 'src' here.
* @param src pointer to pixel map. Copy it to 'dest'.
* @param length number of pixels in 'src'
* @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover)
*/
static void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa)
{
if(opa == LV_OPA_COVER) {
memcpy(dest, src, length * sizeof(lv_color_t));
} else {
uint32_t col;
for(col = 0; col < length; col++) {
dest[col] = lv_color_mix(src[col], dest[col], opa);
}
}
}
/**
*
* @param mem_area coordinates of 'mem' memory area
* @param mem a memory address. Considered to a rectangular window according to 'mem_area'
* @param fill_area coordinates of an area to fill. Relative to 'mem_area'.
* @param color fill color
* @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover)
*/
static void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa)
{
/*Set all row in vdb to the given color*/
lv_coord_t row;
lv_coord_t col;
lv_coord_t mem_width = lv_area_get_width(mem_area);
lv_disp_t * disp = lv_disp_get_active();
if(disp->driver.vdb_wr) {
for(col = fill_area->x1; col <= fill_area->x2; col++) {
for(row = fill_area->y1; row <= fill_area->y2; row++) {
disp->driver.vdb_wr((uint8_t *)mem, mem_width, col, row, color, opa);
}
}
} else {
mem += fill_area->y1 * mem_width; /*Go to the first row*/
/*Run simpler function without opacity*/
if(opa == LV_OPA_COVER) {
/*Fill the first row with 'color'*/
for(col = fill_area->x1; col <= fill_area->x2; col++) {
mem[col] = color;
}
/*Copy the first row to all other rows*/
lv_color_t * mem_first = &mem[fill_area->x1];
lv_coord_t copy_size = (fill_area->x2 - fill_area->x1 + 1) * sizeof(lv_color_t);
mem += mem_width;
for(row = fill_area->y1 + 1; row <= fill_area->y2; row++) {
memcpy(&mem[fill_area->x1], mem_first, copy_size);
mem += mem_width;
}
}
/*Calculate with alpha too*/
else {
#if LV_COLOR_SCREEN_TRANSP == 0
lv_color_t bg_tmp = LV_COLOR_BLACK;
lv_color_t opa_tmp = lv_color_mix(color, bg_tmp, opa);
#endif
for(row = fill_area->y1; row <= fill_area->y2; row++) {
for(col = fill_area->x1; col <= fill_area->x2; col++) {
#if LV_COLOR_SCREEN_TRANSP == 0
/*If the bg color changed recalculate the result color*/
if(mem[col].full != bg_tmp.full) {
bg_tmp = mem[col];
opa_tmp = lv_color_mix(color, bg_tmp, opa);
}
mem[col] = opa_tmp;
#else
mem[col] = color_mix_2_alpha(mem[col], mem[col].alpha, color, opa);
#endif
}
mem += mem_width;
}
}
}
}
#if LV_COLOR_SCREEN_TRANSP
/**
* Mix two colors. Both color can have alpha value. It requires ARGB888 colors.
* @param bg_color background color
* @param bg_opa alpha of the background color
* @param fg_color foreground color
* @param fg_opa alpha of the foreground color
* @return the mixed color. the alpha channel (color.alpha) contains the result alpha
*/
static inline lv_color_t color_mix_2_alpha(lv_color_t bg_color, lv_opa_t bg_opa, lv_color_t fg_color, lv_opa_t fg_opa)
{
/* Pick the foreground if it's fully opaque or the Background is fully transparent*/
if(fg_opa == LV_OPA_COVER && bg_opa <= LV_OPA_MIN) {
fg_color.alpha = fg_opa;
return fg_color;
}
/*Transparent foreground: use the Background*/
else if(fg_opa <= LV_OPA_MIN) {
return bg_color;
}
/*Opaque background: use simple mix*/
else if(bg_opa >= LV_OPA_MAX) {
return lv_color_mix(fg_color, bg_color, fg_opa);
}
/*Both colors have alpha. Expensive calculation need to be applied*/
else {
/*Save the parameters and the result. If they will be asked again don't compute again*/
static lv_opa_t fg_opa_save = 0;
static lv_opa_t bg_opa_save = 0;
static lv_color_t c = {{0}};
if(fg_opa != fg_opa_save || bg_opa != bg_opa_save) {
fg_opa_save = fg_opa;
bg_opa_save = bg_opa;
/*Info: https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator*/
lv_opa_t alpha_res = 255 - ((uint16_t)((uint16_t)(255 - fg_opa) * (255 - bg_opa)) >> 8);
if(alpha_res == 0) {
while(1);
}
lv_opa_t ratio = (uint16_t)((uint16_t) fg_opa * 255) / alpha_res;
c = lv_color_mix(fg_color, bg_color, ratio);
c.alpha = alpha_res;
}
return c;
}
}
#endif /*LV_COLOR_SCREEN_TRANSP*/
#endif

View File

@ -0,0 +1,89 @@
/**
* @file lv_draw_vbasic.h
*
*/
#ifndef LV_DRAW_VBASIC_H
#define LV_DRAW_VBASIC_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_conf.h"
#else
#include "../../lv_conf.h"
#endif
#if LV_VDB_SIZE != 0
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_area.h"
#include "../lv_misc/lv_font.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa);
/**
* Fill an area in the Virtual Display Buffer
* @param cords_p coordinates of the area to fill
* @param mask_p fill only o this mask
* @param color fill color
* @param opa opacity of the area (0..255)
*/
void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
lv_color_t color, lv_opa_t opa);
/**
* Draw a letter in the Virtual Display Buffer
* @param pos_p left-top coordinate of the latter
* @param mask_p the letter will be drawn only on this area
* @param font_p pointer to font
* @param letter a letter to draw
* @param color color of letter
* @param opa opacity of letter (0..255)
*/
void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
const lv_font_t * font_p, uint32_t letter,
lv_color_t color, lv_opa_t opa);
/**
* Draw a color map to the display (image)
* @param cords_p coordinates the color map
* @param mask_p the map will drawn only on this area (truncated to VDB area)
* @param map_p pointer to a lv_color_t array
* @param opa opacity of the map
* @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels
* @param alpha_byte true: extra alpha byte is inserted for every pixel
* @param recolor mix the pixels with this color
* @param recolor_opa the intense of recoloring
*/
void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,
lv_color_t recolor, lv_opa_t recolor_opa);
/**********************
* MACROS
**********************/
#endif /*LV_VDB_SIZE != 0*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_DRAW_RBASIC_H*/

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../lv_misc/lv_font.h"
#if USE_HEKATE_SYMBOL_120 != 0 /*Can be enabled in lv_conf.h*/
/***********************************************************************************
* hekate-symbols-huge.ttf 120 px Font in U+f002 () .. U+f007 () range with all bpp
* Sparse font with only these characters:
***********************************************************************************/
/*Store the glyph descriptions*/
static const lv_font_glyph_dsc_t hekate_symbol_120_glyph_dsc[] =
{
#if USE_HEKATE_SYMBOL_120 == 8
{.w_px = 103, .glyph_index = 0}, /*Unicode: U+f002 ()*/
{.w_px = 103, .glyph_index = 12360}, /*Unicode: U+f003 ()*/
{.w_px = 103, .glyph_index = 24720}, /*Unicode: U+f005 ()*/
{.w_px = 103, .glyph_index = 37080}, /*Unicode: U+f007 ()*/
#endif
};
lv_font_t hekate_symbol_120 =
{
.unicode_first = LV_SYMBOL_GLYPH_FIRST, /*First Unicode letter in this font*/
.unicode_last = LV_SYMBOL_GLYPH_LAST, /*Last Unicode letter in this font*/
.h_px = 120, /*Font height in pixels*/
.glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x36E00), /*Bitmap of glyphs*/
.glyph_dsc = hekate_symbol_120_glyph_dsc, /*Description of glyphs*/
.glyph_cnt = 4, /*Number of glyphs in the font*/
.unicode_list = NULL, /*List of unicode characters*/
.get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/
.get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/
#if USE_HEKATE_SYMBOL_120 == 8
.bpp = 8, /*Bit per pixel*/
#endif
.monospace = 0, /*Fix width (0: if not used)*/
.next_page = NULL, /*Pointer to a font extension*/
};
#endif /*USE_HEKATE_SYMBOL_100*/

View File

@ -0,0 +1,157 @@
/*
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../lv_misc/lv_font.h"
#if USE_HEKATE_SYMBOL_20 != 0 /*Can be enabled in lv_conf.h*/
/***********************************************************************************
* hekate-symbols.ttf 20 px Font in U+f000 () .. U+f2ee () range with all bpp
* Sparse font with only these characters:
***********************************************************************************/
/*Store the glyph descriptions*/
static const lv_font_glyph_dsc_t hekate_symbol_20_glyph_dsc[] =
{
#if USE_HEKATE_SYMBOL_20 == 4
{.w_px = 5, .glyph_index = 0}, /*Unicode: U+f001 ()*/
{.w_px = 16, .glyph_index = 60}, /*Unicode: U+f008 ()*/
{.w_px = 20, .glyph_index = 220}, /*Unicode: U+f00b ()*/
{.w_px = 22, .glyph_index = 420}, /*Unicode: U+f00c ()*/
{.w_px = 16, .glyph_index = 640}, /*Unicode: U+f00d ()*/
{.w_px = 18, .glyph_index = 800}, /*Unicode: U+f011 ()*/
{.w_px = 18, .glyph_index = 980}, /*Unicode: U+f013 ()*/
{.w_px = 16, .glyph_index = 1160}, /*Unicode: U+f014 ()*/
{.w_px = 23, .glyph_index = 1320}, /*Unicode: U+f015 ()*/
{.w_px = 18, .glyph_index = 1560}, /*Unicode: U+f019 ()*/
{.w_px = 23, .glyph_index = 1740}, /*Unicode: U+f01c ()*/
{.w_px = 18, .glyph_index = 1980}, /*Unicode: U+f021 ()*/
{.w_px = 18, .glyph_index = 2160}, /*Unicode: U+f026 ()*/
{.w_px = 18, .glyph_index = 2340}, /*Unicode: U+f027 ()*/
{.w_px = 13, .glyph_index = 2520}, /*Unicode: U+f028 ()*/
{.w_px = 13, .glyph_index = 2660}, /*Unicode: U+f03e ()*/
{.w_px = 16, .glyph_index = 2800}, /*Unicode: U+f040 ()*/
{.w_px = 13, .glyph_index = 2960}, /*Unicode: U+f048 ()*/
{.w_px = 13, .glyph_index = 3100}, /*Unicode: U+f04b ()*/
{.w_px = 13, .glyph_index = 3240}, /*Unicode: U+f04c ()*/
{.w_px = 9, .glyph_index = 3380}, /*Unicode: U+f04d ()*/
{.w_px = 23, .glyph_index = 3480}, /*Unicode: U+f051 ()*/
{.w_px = 21, .glyph_index = 3720}, /*Unicode: U+f052 ()*/
{.w_px = 11, .glyph_index = 3940}, /*Unicode: U+f053 ()*/
{.w_px = 11, .glyph_index = 4060}, /*Unicode: U+f054 ()*/
{.w_px = 18, .glyph_index = 4180}, /*Unicode: U+f067 ()*/
{.w_px = 18, .glyph_index = 4360}, /*Unicode: U+f068 ()*/
{.w_px = 20, .glyph_index = 4540}, /*Unicode: U+f071 ()*/
{.w_px = 20, .glyph_index = 4740}, /*Unicode: U+f074 ()*/
{.w_px = 18, .glyph_index = 4940}, /*Unicode: U+f077 ()*/
{.w_px = 18, .glyph_index = 5120}, /*Unicode: U+f078 ()*/
{.w_px = 18, .glyph_index = 5300}, /*Unicode: U+f079 ()*/
{.w_px = 20, .glyph_index = 5480}, /*Unicode: U+f07b ()*/
{.w_px = 18, .glyph_index = 5680}, /*Unicode: U+f093 ()*/
{.w_px = 25, .glyph_index = 5860}, /*Unicode: U+f095 ()*/
{.w_px = 18, .glyph_index = 6120}, /*Unicode: U+f0c4 ()*/
{.w_px = 16, .glyph_index = 6300}, /*Unicode: U+f0c5 ()*/
{.w_px = 17, .glyph_index = 6460}, /*Unicode: U+f0c7 ()*/
{.w_px = 8, .glyph_index = 6640}, /*Unicode: U+f0e7 ()*/
{.w_px = 12, .glyph_index = 6720}, /*Unicode: U+f0f3 ()*/
{.w_px = 23, .glyph_index = 6840}, /*Unicode: U+f11c ()*/
{.w_px = 18, .glyph_index = 7080}, /*Unicode: U+f124 ()*/
{.w_px = 13, .glyph_index = 7260}, /*Unicode: U+f15b ()*/
{.w_px = 20, .glyph_index = 7400}, /*Unicode: U+f1eb ()*/
{.w_px = 26, .glyph_index = 7600}, /*Unicode: U+f240 ()*/
{.w_px = 26, .glyph_index = 7860}, /*Unicode: U+f241 ()*/
{.w_px = 26, .glyph_index = 8120}, /*Unicode: U+f242 ()*/
{.w_px = 26, .glyph_index = 8380}, /*Unicode: U+f243 ()*/
{.w_px = 26, .glyph_index = 8640}, /*Unicode: U+f244 ()*/
{.w_px = 20, .glyph_index = 8900}, /*Unicode: U+f293 ()*/
#elif USE_HEKATE_SYMBOL_20 == 8
{.w_px = 5, .glyph_index = 0}, /*Unicode: U+f001 ()*/
{.w_px = 16, .glyph_index = 100}, /*Unicode: U+f008 ()*/
{.w_px = 20, .glyph_index = 420}, /*Unicode: U+f00b ()*/
{.w_px = 22, .glyph_index = 820}, /*Unicode: U+f00c ()*/
{.w_px = 16, .glyph_index = 1260}, /*Unicode: U+f00d ()*/
{.w_px = 18, .glyph_index = 1580}, /*Unicode: U+f011 ()*/
{.w_px = 18, .glyph_index = 1940}, /*Unicode: U+f013 ()*/
{.w_px = 16, .glyph_index = 2300}, /*Unicode: U+f014 ()*/
{.w_px = 23, .glyph_index = 2620}, /*Unicode: U+f015 ()*/
{.w_px = 18, .glyph_index = 3080}, /*Unicode: U+f019 ()*/
{.w_px = 23, .glyph_index = 3440}, /*Unicode: U+f01c ()*/
{.w_px = 18, .glyph_index = 3900}, /*Unicode: U+f021 ()*/
{.w_px = 18, .glyph_index = 4260}, /*Unicode: U+f026 ()*/
{.w_px = 18, .glyph_index = 4620}, /*Unicode: U+f027 ()*/
{.w_px = 13, .glyph_index = 4980}, /*Unicode: U+f028 ()*/
{.w_px = 13, .glyph_index = 5240}, /*Unicode: U+f03e ()*/
{.w_px = 16, .glyph_index = 5500}, /*Unicode: U+f040 ()*/
{.w_px = 13, .glyph_index = 5820}, /*Unicode: U+f048 ()*/
{.w_px = 13, .glyph_index = 6080}, /*Unicode: U+f04b ()*/
{.w_px = 13, .glyph_index = 6340}, /*Unicode: U+f04c ()*/
{.w_px = 9, .glyph_index = 6600}, /*Unicode: U+f04d ()*/
{.w_px = 23, .glyph_index = 6780}, /*Unicode: U+f051 ()*/
{.w_px = 21, .glyph_index = 7240}, /*Unicode: U+f052 ()*/
{.w_px = 11, .glyph_index = 7660}, /*Unicode: U+f053 ()*/
{.w_px = 11, .glyph_index = 7880}, /*Unicode: U+f054 ()*/
{.w_px = 18, .glyph_index = 8100}, /*Unicode: U+f067 ()*/
{.w_px = 18, .glyph_index = 8460}, /*Unicode: U+f068 ()*/
{.w_px = 20, .glyph_index = 8820}, /*Unicode: U+f071 ()*/
{.w_px = 20, .glyph_index = 9220}, /*Unicode: U+f074 ()*/
{.w_px = 18, .glyph_index = 9620}, /*Unicode: U+f077 ()*/
{.w_px = 18, .glyph_index = 9980}, /*Unicode: U+f078 ()*/
{.w_px = 18, .glyph_index = 10340}, /*Unicode: U+f079 ()*/
{.w_px = 20, .glyph_index = 10700}, /*Unicode: U+f07b ()*/
{.w_px = 18, .glyph_index = 11100}, /*Unicode: U+f093 ()*/
{.w_px = 25, .glyph_index = 11460}, /*Unicode: U+f095 ()*/
{.w_px = 18, .glyph_index = 11960}, /*Unicode: U+f0c4 ()*/
{.w_px = 16, .glyph_index = 12320}, /*Unicode: U+f0c5 ()*/
{.w_px = 17, .glyph_index = 12640}, /*Unicode: U+f0c7 ()*/
{.w_px = 8, .glyph_index = 12980}, /*Unicode: U+f0e7 ()*/
{.w_px = 12, .glyph_index = 13140}, /*Unicode: U+f0f3 ()*/
{.w_px = 23, .glyph_index = 13380}, /*Unicode: U+f11c ()*/
{.w_px = 18, .glyph_index = 13840}, /*Unicode: U+f124 ()*/
{.w_px = 13, .glyph_index = 14200}, /*Unicode: U+f15b ()*/
{.w_px = 20, .glyph_index = 14460}, /*Unicode: U+f1eb ()*/
{.w_px = 26, .glyph_index = 14860}, /*Unicode: U+f240 ()*/
{.w_px = 26, .glyph_index = 15380}, /*Unicode: U+f241 ()*/
{.w_px = 26, .glyph_index = 15900}, /*Unicode: U+f242 ()*/
{.w_px = 26, .glyph_index = 16420}, /*Unicode: U+f243 ()*/
{.w_px = 26, .glyph_index = 16940}, /*Unicode: U+f244 ()*/
{.w_px = 20, .glyph_index = 17460}, /*Unicode: U+f293 ()*/
#endif
};
lv_font_t hekate_symbol_20 =
{
.unicode_first = LV_SYMBOL_GLYPH_FIRST, /*First Unicode letter in this font*/
.unicode_last = LV_SYMBOL_GLYPH_LAST, /*Last Unicode letter in this font*/
.h_px = 20, /*Font height in pixels*/
//.glyph_bitmap = hekate_symbol_20_glyph_bitmap, /*Bitmap of glyphs*/
.glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0xFC00),
.glyph_dsc = hekate_symbol_20_glyph_dsc, /*Description of glyphs*/
.glyph_cnt = 50, /*Number of glyphs in the font*/
.unicode_list = NULL, /*List of unicode characters*/
.get_bitmap = lv_font_get_bitmap_continuous, /*Function pointer to get glyph's bitmap*/
.get_width = lv_font_get_width_continuous, /*Function pointer to get glyph's width*/
#if USE_HEKATE_SYMBOL_20 == 4
.bpp = 4, /*Bit per pixel*/
#elif USE_HEKATE_SYMBOL_20 == 8
.bpp = 8, /*Bit per pixel*/
#endif
.monospace = 0, /*Fix width (0: if not used)*/
.next_page = NULL, /*Pointer to a font extension*/
};
#endif /*USE_HEKATE_SYMBOL_20*/

Some files were not shown because too many files have changed in this diff Show More