mirror of
https://github.com/RfidResearchGroup/mayhem-firmware.git
synced 2026-05-12 11:27:21 -07:00
Standalone app api v3 (#2772)
Added file io, and updated some ui elements. Also added Digital Rain standalone app for an example.
This commit is contained in:
@@ -640,6 +640,7 @@ BLERxView::BLERxView(NavigationView& nav)
|
||||
};
|
||||
|
||||
options_filter.on_change = [this](size_t index, int32_t v) {
|
||||
(void)v;
|
||||
filter_index = (uint8_t)index;
|
||||
recent.clear();
|
||||
recent_entries_view.set_dirty();
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
|
||||
#include "ui_font_fixed_5x8.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
#include "portapack.hpp"
|
||||
|
||||
#include "file.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
@@ -93,8 +96,90 @@ bool i2c_read(uint8_t* cmd, size_t cmd_len, uint8_t* data, size_t data_len) {
|
||||
return dev->i2c_read(cmd, cmd_len, data, data_len);
|
||||
}
|
||||
|
||||
// v3
|
||||
// Version 3
|
||||
FRESULT ext_f_open(FIL* fp, const TCHAR* path, BYTE mode) {
|
||||
return f_open(fp, path, mode);
|
||||
}
|
||||
FRESULT ext_f_close(FIL* fp) {
|
||||
return f_close(fp);
|
||||
}
|
||||
FRESULT ext_f_read(FIL* fp, void* buff, UINT btr, UINT* br) {
|
||||
return f_read(fp, buff, btr, br);
|
||||
}
|
||||
FRESULT ext_f_write(FIL* fp, const void* buff, UINT btw, UINT* bw) {
|
||||
return f_write(fp, buff, btw, bw);
|
||||
}
|
||||
FRESULT ext_f_lseek(FIL* fp, FSIZE_t ofs) {
|
||||
return f_lseek(fp, ofs);
|
||||
}
|
||||
FRESULT ext_f_truncate(FIL* fp) {
|
||||
return f_truncate(fp);
|
||||
}
|
||||
FRESULT ext_f_sync(FIL* fp) {
|
||||
return f_sync(fp);
|
||||
}
|
||||
FRESULT ext_f_opendir(DIR* dp, const TCHAR* path) {
|
||||
return f_opendir(dp, path);
|
||||
}
|
||||
FRESULT ext_f_closedir(DIR* dp) {
|
||||
return f_closedir(dp);
|
||||
}
|
||||
FRESULT ext_f_readdir(DIR* dp, FILINFO* fno) {
|
||||
return f_readdir(dp, fno);
|
||||
}
|
||||
FRESULT ext_f_findfirst(DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern) {
|
||||
return f_findfirst(dp, fno, path, pattern);
|
||||
}
|
||||
FRESULT ext_f_findnext(DIR* dp, FILINFO* fno) {
|
||||
return f_findnext(dp, fno);
|
||||
}
|
||||
FRESULT ext_f_mkdir(const TCHAR* path) {
|
||||
return f_mkdir(path);
|
||||
}
|
||||
FRESULT ext_f_unlink(const TCHAR* path) {
|
||||
return f_unlink(path);
|
||||
}
|
||||
FRESULT ext_f_rename(const TCHAR* path_old, const TCHAR* path_new) {
|
||||
return f_rename(path_old, path_new);
|
||||
}
|
||||
FRESULT ext_f_stat(const TCHAR* path, FILINFO* fno) {
|
||||
return f_stat(path, fno);
|
||||
}
|
||||
FRESULT ext_f_utime(const TCHAR* path, const FILINFO* fno) {
|
||||
return f_utime(path, fno);
|
||||
}
|
||||
FRESULT ext_f_getfree(const TCHAR* path, DWORD* nclst, FATFS** fatfs) {
|
||||
return f_getfree(path, nclst, fatfs);
|
||||
}
|
||||
FRESULT ext_f_mount(FATFS* fs, const TCHAR* path, BYTE opt) {
|
||||
return f_mount(fs, path, opt);
|
||||
}
|
||||
int ext_f_putc(TCHAR c, FIL* fp) {
|
||||
return f_putc(c, fp);
|
||||
}
|
||||
int ext_f_puts(const TCHAR* str, FIL* cp) {
|
||||
return f_puts(str, cp);
|
||||
}
|
||||
int ext_f_printf(FIL* fp, const TCHAR* str, ...) {
|
||||
return f_printf(fp, str);
|
||||
}
|
||||
TCHAR* ext_f_gets(TCHAR* buff, int len, FIL* fp) {
|
||||
return f_gets(buff, len, fp);
|
||||
}
|
||||
void ext_draw_pixels(const ui::Rect r, const ui::Color* const colors, const size_t count) {
|
||||
portapack::display.draw_pixels(r, colors, count);
|
||||
}
|
||||
void ext_draw_pixel(const ui::Point p, const ui::Color color) {
|
||||
portapack::display.draw_pixel(p, color);
|
||||
}
|
||||
|
||||
StandaloneView* standaloneView = nullptr;
|
||||
|
||||
void exit_app() {
|
||||
if (standaloneView) standaloneView->exit();
|
||||
}
|
||||
|
||||
void set_dirty() {
|
||||
if (standaloneView != nullptr)
|
||||
standaloneView->set_dirty();
|
||||
@@ -121,6 +206,33 @@ standalone_application_api_t api = {
|
||||
/* .i2c_read = */ &i2c_read,
|
||||
/* .panic = */ &chDbgPanic,
|
||||
/* .set_dirty = */ &set_dirty,
|
||||
// Version 3
|
||||
.f_open = &ext_f_open,
|
||||
.f_close = &ext_f_close,
|
||||
.f_read = &ext_f_read,
|
||||
.f_write = &ext_f_write,
|
||||
.f_lseek = &ext_f_lseek,
|
||||
.f_truncate = &ext_f_truncate,
|
||||
.f_sync = &ext_f_sync,
|
||||
.f_opendir = &ext_f_opendir,
|
||||
.f_closedir = &ext_f_closedir,
|
||||
.f_readdir = &ext_f_readdir,
|
||||
.f_findfirst = &ext_f_findfirst,
|
||||
.f_findnext = &ext_f_findnext,
|
||||
.f_mkdir = &ext_f_mkdir,
|
||||
.f_unlink = &ext_f_unlink,
|
||||
.f_rename = &ext_f_rename,
|
||||
.f_stat = &ext_f_stat,
|
||||
.f_utime = &ext_f_utime,
|
||||
.f_getfree = &ext_f_getfree,
|
||||
.f_mount = &ext_f_mount,
|
||||
.f_putc = &ext_f_putc,
|
||||
.f_puts = &ext_f_puts,
|
||||
.f_printf = &ext_f_printf,
|
||||
.f_gets = &ext_f_gets,
|
||||
.draw_pixels = &ext_draw_pixels,
|
||||
.draw_pixel = &ext_draw_pixel,
|
||||
.exit_app = &exit_app,
|
||||
};
|
||||
|
||||
StandaloneView::StandaloneView(NavigationView& nav, uint8_t* app_image)
|
||||
@@ -158,22 +270,21 @@ bool StandaloneView::on_key(const KeyEvent key) {
|
||||
if (get_application_information()->header_version > 1) {
|
||||
return get_application_information()->OnKeyEvent((uint8_t)key);
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StandaloneView::on_encoder(const EncoderEvent event) {
|
||||
if (get_application_information()->header_version > 1) {
|
||||
return get_application_information()->OnEncoder((int32_t)event);
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StandaloneView::on_touch(const TouchEvent event) {
|
||||
if (get_application_information()->header_version > 1) {
|
||||
get_application_information()->OnTouchEvent(event.point.x(), event.point.y(), (uint32_t)event.type);
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StandaloneView::on_keyboard(const KeyboardEvent event) {
|
||||
@@ -202,4 +313,8 @@ void StandaloneView::on_before_detach() {
|
||||
context().focus_manager().clearMirror();
|
||||
}
|
||||
|
||||
void StandaloneView::exit() {
|
||||
nav_.pop();
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
||||
@@ -51,6 +51,8 @@ class StandaloneView : public View {
|
||||
|
||||
void frame_sync();
|
||||
|
||||
void exit();
|
||||
|
||||
private:
|
||||
bool initialized = false;
|
||||
NavigationView& nav_;
|
||||
|
||||
@@ -4,6 +4,12 @@ namespace ui {
|
||||
|
||||
ThemeTemplate* Theme::current = nullptr;
|
||||
|
||||
void Theme::destroy() {
|
||||
if (current != nullptr)
|
||||
delete current;
|
||||
current = nullptr;
|
||||
}
|
||||
|
||||
ThemeTemplate* Theme::getInstance() {
|
||||
if (current == nullptr) SetTheme(DefaultGrey);
|
||||
return Theme::current;
|
||||
|
||||
@@ -113,7 +113,7 @@ class Theme {
|
||||
|
||||
static void SetTheme(ThemeId theme);
|
||||
static ThemeTemplate* current;
|
||||
|
||||
static void destroy(); // used from standalone app, to prevent memleak
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
@@ -256,7 +256,7 @@ void GeoMap::map_read_line_bin(ui::Color* buffer, uint16_t pixels) {
|
||||
for (int i = 0; i < geomap_rect_width; i++) {
|
||||
buffer[i] = zoom_out_buffer[i * (-map_zoom)];
|
||||
}
|
||||
delete zoom_out_buffer;
|
||||
delete[] zoom_out_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,7 +660,7 @@ bool GeoMap::init() {
|
||||
map_height = 32768;
|
||||
}
|
||||
|
||||
map_visible = map_opened;
|
||||
map_visible = map_opened || has_osm;
|
||||
map_center_x = map_width >> 1;
|
||||
map_center_y = map_height >> 1;
|
||||
|
||||
@@ -670,7 +670,7 @@ bool GeoMap::init() {
|
||||
map_bottom = sin(-85.05 * pi / 180); // Map bitmap only goes from about -85 to 85 lat
|
||||
map_world_lon = map_width / (2 * pi);
|
||||
map_offset = (map_world_lon / 2 * log((1 + map_bottom) / (1 - map_bottom)));
|
||||
return map_opened || has_osm;
|
||||
return map_opened;
|
||||
}
|
||||
|
||||
void GeoMap::set_mode(GeoMapMode mode) {
|
||||
|
||||
@@ -347,7 +347,7 @@ namespace ui {
|
||||
return false;
|
||||
|
||||
// TODO: move this to m4 memory space
|
||||
auto app_image = reinterpret_cast<uint8_t*>(portapack::memory::map::m4_code.end() - app.size());
|
||||
auto app_image = reinterpret_cast<uint8_t*>(portapack::memory::map::local_sram_0.base());
|
||||
|
||||
// read file in 512 byte chunks
|
||||
for (size_t file_read_index = 0; file_read_index < app.size(); file_read_index += std::filesystem::max_file_block_size) {
|
||||
|
||||
@@ -27,8 +27,9 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "file.hpp"
|
||||
|
||||
#define CURRENT_STANDALONE_APPLICATION_API_VERSION 2
|
||||
#define CURRENT_STANDALONE_APPLICATION_API_VERSION 3
|
||||
|
||||
struct standalone_application_api_t {
|
||||
// Version 1
|
||||
@@ -58,7 +59,52 @@ struct standalone_application_api_t {
|
||||
void (*panic)(const char* msg);
|
||||
void (*set_dirty)();
|
||||
|
||||
// TODO: add filesystem access functions
|
||||
// Version 3
|
||||
FRESULT(*f_open)
|
||||
(FIL* fp, const TCHAR* path, BYTE mode);
|
||||
FRESULT(*f_close)
|
||||
(FIL* fp);
|
||||
FRESULT(*f_read)
|
||||
(FIL* fp, void* buff, UINT btr, UINT* br);
|
||||
FRESULT(*f_write)
|
||||
(FIL* fp, const void* buff, UINT btw, UINT* bw);
|
||||
FRESULT(*f_lseek)
|
||||
(FIL* fp, FSIZE_t ofs);
|
||||
FRESULT(*f_truncate)
|
||||
(FIL* fp);
|
||||
FRESULT(*f_sync)
|
||||
(FIL* fp);
|
||||
FRESULT(*f_opendir)
|
||||
(DIR* dp, const TCHAR* path);
|
||||
FRESULT(*f_closedir)
|
||||
(DIR* dp);
|
||||
FRESULT(*f_readdir)
|
||||
(DIR* dp, FILINFO* fno);
|
||||
FRESULT(*f_findfirst)
|
||||
(DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern);
|
||||
FRESULT(*f_findnext)
|
||||
(DIR* dp, FILINFO* fno);
|
||||
FRESULT(*f_mkdir)
|
||||
(const TCHAR* path);
|
||||
FRESULT(*f_unlink)
|
||||
(const TCHAR* path);
|
||||
FRESULT(*f_rename)
|
||||
(const TCHAR* path_old, const TCHAR* path_new);
|
||||
FRESULT(*f_stat)
|
||||
(const TCHAR* path, FILINFO* fno);
|
||||
FRESULT(*f_utime)
|
||||
(const TCHAR* path, const FILINFO* fno);
|
||||
FRESULT(*f_getfree)
|
||||
(const TCHAR* path, DWORD* nclst, FATFS** fatfs);
|
||||
FRESULT(*f_mount)
|
||||
(FATFS* fs, const TCHAR* path, BYTE opt);
|
||||
int (*f_putc)(TCHAR c, FIL* fp);
|
||||
int (*f_puts)(const TCHAR* str, FIL* cp);
|
||||
int (*f_printf)(FIL* fp, const TCHAR* str, ...);
|
||||
TCHAR* (*f_gets)(TCHAR* buff, int len, FIL* fp);
|
||||
void (*draw_pixels)(const ui::Rect r, const ui::Color* const colors, const size_t count);
|
||||
void (*draw_pixel)(const ui::Point p, const ui::Color color);
|
||||
void (*exit_app)();
|
||||
// TODO: add baseband access functions
|
||||
|
||||
// HOW TO extend this interface:
|
||||
|
||||
@@ -3,9 +3,10 @@ cmake_minimum_required(VERSION 3.16)
|
||||
project(standalone_apps)
|
||||
|
||||
add_subdirectory(pacman)
|
||||
add_subdirectory(digitalrain)
|
||||
|
||||
add_custom_target(
|
||||
standalone_apps
|
||||
DEPENDS pacman_app
|
||||
DEPENDS pacman_app digitalrain_app
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
#
|
||||
# Copyright (C) 2024 Bernd Herzog
|
||||
#
|
||||
# This file is part of PortaPack.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that 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; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
# Build global options
|
||||
# NOTE: Can be overridden externally.
|
||||
#
|
||||
|
||||
enable_language(C CXX ASM)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
project(digitalrain_app)
|
||||
|
||||
# Compiler options here.
|
||||
set(USE_OPT "-Os -g --specs=nano.specs --specs=nosys.specs")
|
||||
|
||||
# C specific options here (added to USE_OPT).
|
||||
set(USE_COPT "-std=gnu99")
|
||||
|
||||
# C++ specific options here (added to USE_OPT).
|
||||
check_cxx_compiler_flag("-std=c++20" cpp20_supported)
|
||||
if(cpp20_supported)
|
||||
set(USE_CPPOPT "-std=c++20")
|
||||
else()
|
||||
set(USE_CPPOPT "-std=c++17")
|
||||
endif()
|
||||
set(USE_CPPOPT "${USE_CPPOPT} -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized -fno-use-cxa-atexit")
|
||||
|
||||
# Enable this if you want the linker to remove unused code and data
|
||||
set(USE_LINK_GC yes)
|
||||
|
||||
# Linker extra options here.
|
||||
set(USE_LDOPT)
|
||||
|
||||
# Enable this if you want link time optimizations (LTO) - this flag affects chibios only
|
||||
set(USE_LTO no)
|
||||
|
||||
# If enabled, this option allows to compile the application in THUMB mode.
|
||||
set(USE_THUMB yes)
|
||||
|
||||
# Enable this if you want to see the full log while compiling.
|
||||
set(USE_VERBOSE_COMPILE no)
|
||||
|
||||
#
|
||||
# Build global options
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Architecture or project specific options
|
||||
#
|
||||
|
||||
# Enables the use of FPU on Cortex-M4 (no, softfp, hard).
|
||||
set(USE_FPU no)
|
||||
|
||||
#
|
||||
# Architecture or project specific options
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Project, sources and paths
|
||||
#
|
||||
|
||||
# Define linker script file here
|
||||
set(LDSCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/external.ld)
|
||||
|
||||
|
||||
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
# setting.
|
||||
FILE(GLOB_RECURSE Sources_C ${CMAKE_CURRENT_LIST_DIR}/*.c)
|
||||
set(CSRC
|
||||
${Sources_C}
|
||||
)
|
||||
|
||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
# setting.
|
||||
FILE(GLOB_RECURSE Sources_CPP ${CMAKE_CURRENT_LIST_DIR}/*.cpp)
|
||||
set(CPPSRC
|
||||
${Sources_CPP}
|
||||
)
|
||||
|
||||
# C sources to be compiled in ARM mode regardless of the global setting.
|
||||
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||
# option that results in lower performance and larger code size.
|
||||
set(ACSRC)
|
||||
|
||||
# C++ sources to be compiled in ARM mode regardless of the global setting.
|
||||
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||
# option that results in lower performance and larger code size.
|
||||
set(ACPPSRC)
|
||||
|
||||
# C sources to be compiled in THUMB mode regardless of the global setting.
|
||||
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||
# option that results in lower performance and larger code size.
|
||||
set(TCSRC)
|
||||
|
||||
# C sources to be compiled in THUMB mode regardless of the global setting.
|
||||
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||
# option that results in lower performance and larger code size.
|
||||
set(TCPPSRC)
|
||||
|
||||
# List ASM source files here
|
||||
set(ASMSRC)
|
||||
|
||||
set(INCDIR
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${COMMON}
|
||||
${COMMON}/../application
|
||||
${COMMON}/../application/hw
|
||||
)
|
||||
|
||||
#
|
||||
# Project, sources and paths
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Compiler settings
|
||||
#
|
||||
|
||||
# TODO: Entertain using MCU=cortex-m0.small-multiply for LPC43xx M0 core.
|
||||
# However, on GCC-ARM-Embedded 4.9 2015q2, it seems to produce non-functional
|
||||
# binaries.
|
||||
set(MCU cortex-m0)
|
||||
|
||||
# ARM-specific options here
|
||||
set(AOPT)
|
||||
|
||||
# THUMB-specific options here
|
||||
set(TOPT "-mthumb -DTHUMB")
|
||||
|
||||
# Define C warning options here
|
||||
set(CWARN "-Wall -Wextra -Wstrict-prototypes")
|
||||
|
||||
# Define C++ warning options here
|
||||
set(CPPWARN "-Wall -Wextra -Wno-psabi")
|
||||
|
||||
#
|
||||
# Compiler settings
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Start of default section
|
||||
#
|
||||
|
||||
# List all default C defines here, like -D_DEBUG=1
|
||||
# TODO: Switch -DCRT0_INIT_DATA depending on load from RAM or SPIFI?
|
||||
# NOTE: _RANDOM_TCC to kill a GCC 4.9.3 error with std::max argument types
|
||||
set(DDEFS "-DLPC43XX -DLPC43XX_M0 -D__NEWLIB__ -DHACKRF_ONE -DTOOLCHAIN_GCC -DTOOLCHAIN_GCC_ARM -D_RANDOM_TCC=0")
|
||||
|
||||
# List all default ASM defines here, like -D_DEBUG=1
|
||||
set(DADEFS)
|
||||
|
||||
# List all default directories to look for include files here
|
||||
set(DINCDIR)
|
||||
|
||||
# List the default directory to look for the libraries here
|
||||
set(DLIBDIR)
|
||||
|
||||
# List all default libraries here
|
||||
set(DLIBS)
|
||||
|
||||
#
|
||||
# End of default section
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Start of user section
|
||||
#
|
||||
|
||||
# List all user C define here, like -D_DEBUG=1
|
||||
set(UDEFS)
|
||||
|
||||
# Define ASM defines here
|
||||
set(UADEFS)
|
||||
|
||||
# List all user directories here
|
||||
set(UINCDIR)
|
||||
|
||||
# List the user directory to look for the libraries here
|
||||
set(ULIBDIR)
|
||||
|
||||
# List all user libraries here
|
||||
set(ULIBS)
|
||||
|
||||
#
|
||||
# End of user defines
|
||||
##############################################################################
|
||||
|
||||
set(RULESPATH ${CHIBIOS}/os/ports/GCC/ARMCMx)
|
||||
include(${RULESPATH}/rules.cmake)
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
add_executable(${PROJECT_NAME}.elf ${CSRC} ${CPPSRC} ${ASMSRC})
|
||||
set_target_properties(${PROJECT_NAME}.elf PROPERTIES LINK_DEPENDS ${LDSCRIPT})
|
||||
add_definitions(${DEFS})
|
||||
include_directories(. ${INCDIR})
|
||||
link_directories(${LLIBDIR})
|
||||
target_link_libraries(${PROJECT_NAME}.elf -Wl,-Map=${PROJECT_NAME}.map)
|
||||
|
||||
# redirect std lib memory allocations
|
||||
target_link_libraries(${PROJECT_NAME}.elf "-Wl,-wrap,_malloc_r")
|
||||
target_link_libraries(${PROJECT_NAME}.elf "-Wl,-wrap,_free_r")
|
||||
target_link_libraries(${PROJECT_NAME}.elf "-Wl,--print-memory-usage")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_NAME}.ppmp
|
||||
COMMAND ${CMAKE_OBJCOPY} -v -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.ppmp
|
||||
DEPENDS ${PROJECT_NAME}.elf
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
${PROJECT_NAME}
|
||||
DEPENDS ${PROJECT_NAME}.ppmp
|
||||
)
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Bernd Herzog
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that 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; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "digitalrain.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
StandaloneViewMirror* standaloneViewMirror = nullptr;
|
||||
ui::Context* context = nullptr;
|
||||
|
||||
void initialize(const standalone_application_api_t& api) {
|
||||
_api = &api;
|
||||
|
||||
context = new ui::Context();
|
||||
standaloneViewMirror = new StandaloneViewMirror(*context, {0, 16, 240, 304});
|
||||
}
|
||||
|
||||
// event 1 == frame sync. called each 1/60th of second, so 6 = 100ms
|
||||
|
||||
void on_event(const uint32_t& events) {
|
||||
if ((events & 1) == 1) standaloneViewMirror->need_refresh();
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
delete standaloneViewMirror;
|
||||
delete context;
|
||||
}
|
||||
|
||||
void PaintViewMirror() {
|
||||
ui::Painter painter;
|
||||
if (standaloneViewMirror)
|
||||
painter.paint_widget_tree(standaloneViewMirror);
|
||||
}
|
||||
|
||||
ui::Widget* touch_widget(ui::Widget* const w, ui::TouchEvent event) {
|
||||
if (!w->hidden()) {
|
||||
// To achieve reverse depth ordering (last object drawn is
|
||||
// considered "top"), descend first.
|
||||
for (const auto child : w->children()) {
|
||||
const auto touched_widget = touch_widget(child, event);
|
||||
if (touched_widget) {
|
||||
return touched_widget;
|
||||
}
|
||||
}
|
||||
|
||||
const auto r = w->screen_rect();
|
||||
if (r.contains(event.point)) {
|
||||
if (w->on_touch(event)) {
|
||||
// This widget responded. Return it up the call stack.
|
||||
return w;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ui::Widget* captured_widget{nullptr};
|
||||
|
||||
void OnTouchEvent(int, int, uint32_t) {
|
||||
if (standaloneViewMirror) {
|
||||
_api->exit_app();
|
||||
/*
|
||||
ui::TouchEvent event{{x, y}, static_cast<ui::TouchEvent::Type>(type)};
|
||||
|
||||
if (event.type == ui::TouchEvent::Type::Start) {
|
||||
captured_widget = touch_widget(standaloneViewMirror, event);
|
||||
|
||||
if (captured_widget) {
|
||||
captured_widget->focus();
|
||||
captured_widget->set_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
if (captured_widget)
|
||||
captured_widget->on_touch(event);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void OnFocus() {
|
||||
if (standaloneViewMirror)
|
||||
standaloneViewMirror->focus();
|
||||
}
|
||||
|
||||
bool OnKeyEvent(uint8_t) {
|
||||
// ui::KeyEvent key = (ui::KeyEvent)key_val;
|
||||
if (context) {
|
||||
_api->exit_app();
|
||||
/* auto focus_widget = context->focus_manager().focus_widget();
|
||||
|
||||
if (focus_widget) {
|
||||
if (focus_widget->on_key(key))
|
||||
return true;
|
||||
|
||||
context->focus_manager().update(standaloneViewMirror, key);
|
||||
|
||||
if (focus_widget != context->focus_manager().focus_widget())
|
||||
return true;
|
||||
else {
|
||||
if (key == ui::KeyEvent::Up || key == ui::KeyEvent::Back || key == ui::KeyEvent::Left) {
|
||||
focus_widget->blur();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OnEncoder(int32_t) {
|
||||
if (context) {
|
||||
_api->exit_app();
|
||||
/*
|
||||
auto focus_widget = context->focus_manager().focus_widget();
|
||||
|
||||
if (focus_widget) return focus_widget->on_encoder((ui::EncoderEvent)delta);
|
||||
*/
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OnKeyboad(uint8_t) {
|
||||
if (context) {
|
||||
_api->exit_app();
|
||||
/*
|
||||
auto focus_widget = context->focus_manager().focus_widget();
|
||||
|
||||
if (focus_widget)
|
||||
return focus_widget->on_keyboard((ui::KeyboardEvent)key);
|
||||
*/
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Bernd Herzog
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that 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; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "standalone_app.hpp"
|
||||
|
||||
#include "ui/ui_widget.hpp"
|
||||
#include "ui/theme.hpp"
|
||||
#include "ui/string_format.hpp"
|
||||
#include <string.h>
|
||||
#include "ui/ui_font_fixed_5x8.hpp"
|
||||
#include "ui/ui_painter.hpp"
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <cstdlib> // for std::rand() and std::srand()
|
||||
#include <ctime> // for std::time()
|
||||
|
||||
void initialize(const standalone_application_api_t& api);
|
||||
void on_event(const uint32_t& events);
|
||||
void shutdown();
|
||||
void OnFocus();
|
||||
bool OnKeyEvent(uint8_t);
|
||||
bool OnEncoder(int32_t);
|
||||
void OnTouchEvent(int, int, uint32_t);
|
||||
bool OnKeyboad(uint8_t);
|
||||
void PaintViewMirror();
|
||||
|
||||
extern const standalone_application_api_t* _api;
|
||||
|
||||
class DigitalRain {
|
||||
private:
|
||||
ui::Painter painter{};
|
||||
static const int WIDTH = 240;
|
||||
static const int HEIGHT = 325;
|
||||
static const int MARGIN_TOP = 20;
|
||||
static const int CHAR_WIDTH = 5;
|
||||
static const int CHAR_HEIGHT = 8;
|
||||
static const int COLS = WIDTH / CHAR_WIDTH;
|
||||
static const int ROWS = (HEIGHT - MARGIN_TOP) / CHAR_HEIGHT;
|
||||
static const int MAX_DROPS = 36;
|
||||
|
||||
const ui::Font& font = ui::font::fixed_5x8();
|
||||
|
||||
struct Drop {
|
||||
uint8_t x;
|
||||
int16_t y;
|
||||
uint8_t length;
|
||||
uint8_t speed;
|
||||
uint8_t morph_counter[16];
|
||||
char chars[16];
|
||||
int16_t old_y; // Track previous position for clearing
|
||||
bool active;
|
||||
};
|
||||
|
||||
Drop drops[MAX_DROPS];
|
||||
const char char_set[16] = {
|
||||
'@', '#', '$', '0', '1', '2', '>', '<',
|
||||
'/', '\\', '[', ']', '{', '}', '.', ' '};
|
||||
|
||||
inline int random(int min, int max) {
|
||||
return min + (std::rand() % (max - min + 1));
|
||||
}
|
||||
|
||||
void init_drop(uint8_t index, bool force_top = false) {
|
||||
drops[index].x = random(0, COLS - 1);
|
||||
drops[index].y = force_top ? -random(0, 5) : -5;
|
||||
drops[index].old_y = drops[index].y; // Initialize old position
|
||||
drops[index].length = random(5, 15);
|
||||
drops[index].speed = random(1, 3);
|
||||
drops[index].active = true;
|
||||
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
drops[index].chars[i] = char_set[random(0, 15)];
|
||||
drops[index].morph_counter[i] = random(2, 6);
|
||||
}
|
||||
}
|
||||
|
||||
void clear_drop_trail(const Drop& drop) {
|
||||
// Convert to int16_t for consistent type comparison
|
||||
int16_t start_y = std::max<int16_t>(0, drop.old_y - drop.length + 1);
|
||||
int16_t end_y = std::min<int16_t>(ROWS - 1, drop.old_y);
|
||||
|
||||
if (start_y <= end_y) {
|
||||
int16_t pixel_y = start_y * CHAR_HEIGHT + MARGIN_TOP;
|
||||
uint16_t height = (end_y - start_y + 1) * CHAR_HEIGHT;
|
||||
|
||||
painter.fill_rectangle_unrolled8(
|
||||
{static_cast<int16_t>(drop.x * CHAR_WIDTH),
|
||||
pixel_y,
|
||||
CHAR_WIDTH,
|
||||
height},
|
||||
ui::Color::black());
|
||||
}
|
||||
}
|
||||
|
||||
void morph_characters(Drop& drop) {
|
||||
for (uint8_t i = 0; i < drop.length; i++) {
|
||||
if (--drop.morph_counter[i] == 0) {
|
||||
drop.chars[i] = char_set[random(0, 15)];
|
||||
drop.morph_counter[i] = random(2, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DigitalRain() {
|
||||
std::srand(0);
|
||||
|
||||
for (uint8_t i = 0; i < MAX_DROPS; ++i) {
|
||||
init_drop(i, true);
|
||||
}
|
||||
}
|
||||
|
||||
void update() {
|
||||
for (uint8_t i = 0; i < MAX_DROPS; ++i) {
|
||||
if (!drops[i].active) continue;
|
||||
|
||||
// Store old position before updating
|
||||
drops[i].old_y = drops[i].y;
|
||||
|
||||
// Update position
|
||||
drops[i].y += drops[i].speed;
|
||||
morph_characters(drops[i]);
|
||||
|
||||
// Reset drop if off screen
|
||||
if (drops[i].y - drops[i].length > ROWS) {
|
||||
clear_drop_trail(drops[i]); // Clear final position
|
||||
init_drop(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void render() {
|
||||
for (uint8_t i = 0; i < MAX_DROPS; ++i) {
|
||||
if (!drops[i].active) continue;
|
||||
|
||||
// Clear previous position
|
||||
clear_drop_trail(drops[i]);
|
||||
|
||||
// Draw new position
|
||||
for (uint8_t j = 0; j < drops[i].length; ++j) {
|
||||
int y = drops[i].y - j;
|
||||
if (y >= 0 && y < ROWS) {
|
||||
ui::Point p{
|
||||
static_cast<int16_t>(drops[i].x * CHAR_WIDTH),
|
||||
static_cast<int16_t>(y * CHAR_HEIGHT + MARGIN_TOP)};
|
||||
|
||||
ui::Color fg;
|
||||
if (j == 0) {
|
||||
fg = ui::Color::white();
|
||||
} else if (j < 3) {
|
||||
fg = ui::Color(0, 255, 0);
|
||||
} else {
|
||||
uint8_t intensity = std::max(40, 180 - (j * 15));
|
||||
fg = ui::Color(0, intensity, 0);
|
||||
}
|
||||
|
||||
std::string ch(1, drops[i].chars[j]);
|
||||
painter.draw_string(
|
||||
p,
|
||||
font,
|
||||
fg,
|
||||
ui::Color::black(),
|
||||
ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class StandaloneViewMirror : public ui::View {
|
||||
public:
|
||||
StandaloneViewMirror(ui::Context& context, const ui::Rect parent_rect)
|
||||
: View{parent_rect}, context_(context) {
|
||||
set_style(ui::Theme::getInstance()->bg_darkest);
|
||||
}
|
||||
~StandaloneViewMirror() {
|
||||
ui::Theme::destroy();
|
||||
}
|
||||
ui::Context& context() const override {
|
||||
return context_;
|
||||
}
|
||||
|
||||
void focus() override {
|
||||
}
|
||||
|
||||
bool need_refresh() {
|
||||
update++;
|
||||
if (update % 2 == 0) {
|
||||
return false;
|
||||
}
|
||||
digitalRain.update();
|
||||
digitalRain.render();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
ui::Context& context_;
|
||||
ui::Console console{{0, 0, 240, 320}};
|
||||
DigitalRain digitalRain{};
|
||||
uint8_t update = 0;
|
||||
};
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Copyright (C) 2024 Bernd Herzog
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram : org = 0xADB10000, len = 64k /* DO NOT CHANGE the address. We make the image relocateable on load. It needs to be 0xADB10000 */
|
||||
}
|
||||
|
||||
__ram_start__ = ORIGIN(ram);
|
||||
__ram_size__ = LENGTH(ram);
|
||||
__ram_end__ = __ram_start__ + __ram_size__;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
_text = .;
|
||||
startup : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
KEEP(*(.standalone_application_information));
|
||||
} > ram
|
||||
|
||||
constructors : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
PROVIDE(__init_array_start = .);
|
||||
KEEP(*(SORT(.init_array.*)))
|
||||
KEEP(*(.init_array))
|
||||
PROVIDE(__init_array_end = .);
|
||||
} > ram
|
||||
|
||||
destructors : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
PROVIDE(__fini_array_start = .);
|
||||
KEEP(*(.fini_array))
|
||||
KEEP(*(SORT(.fini_array.*)))
|
||||
PROVIDE(__fini_array_end = .);
|
||||
} > ram
|
||||
|
||||
.text : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
*(.text.startup.*)
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.glue_7t)
|
||||
*(.glue_7)
|
||||
*(.gcc*)
|
||||
} > ram
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} > ram
|
||||
|
||||
.ARM.exidx : {
|
||||
PROVIDE(__exidx_start = .);
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
PROVIDE(__exidx_end = .);
|
||||
} > ram
|
||||
|
||||
.eh_frame_hdr :
|
||||
{
|
||||
*(.eh_frame_hdr)
|
||||
} > ram
|
||||
|
||||
.eh_frame : ONLY_IF_RO
|
||||
{
|
||||
*(.eh_frame)
|
||||
} > ram
|
||||
|
||||
.textalign : ONLY_IF_RO
|
||||
{
|
||||
. = ALIGN(8);
|
||||
} > ram
|
||||
|
||||
.bss ALIGN(4) : ALIGN(4)
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_bss_start = .);
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_bss_end = .);
|
||||
} > ram
|
||||
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
_textdata = _etext;
|
||||
|
||||
.data ALIGN(4) : AT (_textdata)
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_data = .);
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
*(.ramtext)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_edata = .);
|
||||
} > ram
|
||||
}
|
||||
|
||||
PROVIDE(end = .);
|
||||
_end = .;
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT file system module R0.12c /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2017, 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 _FATFS
|
||||
#define _FATFS 68300 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "integer.h" /* Basic integer types */
|
||||
#include "ffconf.h" /* FatFs configuration options */
|
||||
|
||||
#if _FATFS != _FFCONF
|
||||
#error Wrong configuration file (ffconf.h).
|
||||
#endif
|
||||
|
||||
/* Definitions of volume management */
|
||||
|
||||
#if _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
|
||||
|
||||
/* Type of path name strings on FatFs API */
|
||||
|
||||
#if _LFN_UNICODE /* Unicode (UTF-16) string */
|
||||
#if _USE_LFN == 0
|
||||
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
||||
#endif
|
||||
#ifndef _INC_TCHAR
|
||||
typedef WCHAR TCHAR;
|
||||
#define _T(x) L##x
|
||||
#define _TEXT(x) L##x
|
||||
#endif
|
||||
#else /* ANSI/OEM string */
|
||||
#ifndef _INC_TCHAR
|
||||
typedef char TCHAR;
|
||||
#define _T(x) x
|
||||
#define _TEXT(x) x
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Type of file size variables */
|
||||
|
||||
#if _FS_EXFAT
|
||||
#if _USE_LFN == 0
|
||||
#error LFN must be enabled when enable exFAT
|
||||
#endif
|
||||
typedef QWORD FSIZE_t;
|
||||
#else
|
||||
typedef DWORD FSIZE_t;
|
||||
#endif
|
||||
|
||||
/* File system object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* File system type (0:N/A) */
|
||||
BYTE drv; /* Physical drive number */
|
||||
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; /* File system mount ID */
|
||||
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||
WORD csize; /* Cluster size [sectors] */
|
||||
#if _MAX_SS != _MIN_SS
|
||||
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
||||
#endif
|
||||
#if _USE_LFN != 0
|
||||
WCHAR* lfnbuf; /* LFN working buffer */
|
||||
#endif
|
||||
#if _FS_EXFAT
|
||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer */
|
||||
#endif
|
||||
#if _FS_REENTRANT
|
||||
_SYNC_t sobj; /* Identifier of sync object */
|
||||
#endif
|
||||
#if !_FS_READONLY
|
||||
DWORD last_clst; /* Last allocated cluster */
|
||||
DWORD free_clst; /* Number of free clusters */
|
||||
#endif
|
||||
#if _FS_RPATH != 0
|
||||
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||
#if _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 */
|
||||
DWORD winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
/* Object ID and allocation information (_FDID) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the owner file system object */
|
||||
WORD id; /* Owner file system mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:flagmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if _FS_EXFAT
|
||||
DWORD n_cont; /* Size of first fragment, clusters - 1 (valid when stat == 3) */
|
||||
DWORD n_frag; /* Size of last fragment needs to be written (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 sclust != 0 and non-directory object) */
|
||||
#endif
|
||||
#if _FS_LOCK != 0
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
#endif
|
||||
} _FDID;
|
||||
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
_FDID 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 !_FS_READONLY
|
||||
DWORD dir_sect; /* Sector number containing the directory entry */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
|
||||
#endif
|
||||
#if _USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
#if !_FS_TINY
|
||||
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
/* Directory object structure (DIR) */
|
||||
|
||||
typedef struct {
|
||||
_FDID 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 _USE_LFN != 0
|
||||
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
||||
#endif
|
||||
#if _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 _USE_LFN != 0
|
||||
TCHAR altname[13]; /* Altenative file name */
|
||||
TCHAR fname[_MAX_LFN + 1]; /* Primary file name */
|
||||
#else
|
||||
TCHAR fname[13]; /* 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 > _FS_LOCK */
|
||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||
} FRESULT;
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* FatFs module application interface */
|
||||
|
||||
/*
|
||||
//MOVED TO API
|
||||
|
||||
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 *
|
||||
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 diectory *
|
||||
FRESULT f_unlink(const TCHAR* path); / Delete an existing fileor 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 *
|
||||
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 *
|
||||
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)
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
#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
|
||||
|
||||
#include "fileext.hpp"
|
||||
|
||||
#endif /* _FATFS */
|
||||
@@ -0,0 +1,242 @@
|
||||
/* CHIBIOS FIX */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module configuration file
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FFCONF 68300 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _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 _FS_MINIMIZE 0
|
||||
/* This option defines minimization level to remove some basic API functions.
|
||||
/
|
||||
/ 0: All basic functions are 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 _USE_STRFUNC 1
|
||||
/* 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 _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 _USE_MKFS 0
|
||||
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
||||
|
||||
#define _USE_FASTSEEK 1
|
||||
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
||||
|
||||
#define _USE_EXPAND 0
|
||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||
|
||||
#define _USE_CHMOD 1
|
||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||
/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */
|
||||
|
||||
#define _USE_LABEL 0
|
||||
/* This option switches volume label functions, f_getlabel() and f_setlabel().
|
||||
/ (0:Disable or 1:Enable) */
|
||||
|
||||
#define _USE_FORWARD 0
|
||||
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Locale and Namespace Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _CODE_PAGE 437
|
||||
/* This option specifies the OEM code page to be used on the target system.
|
||||
/ Incorrect setting of the code page can cause a file open failure.
|
||||
/
|
||||
/ 1 - ASCII (No support of extended character. Non-LFN cfg. only)
|
||||
/ 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)
|
||||
*/
|
||||
|
||||
#define _USE_LFN 3
|
||||
#define _MAX_LFN 255
|
||||
/* The _USE_LFN switches the support of long file name (LFN).
|
||||
/
|
||||
/ 0: Disable support of LFN. _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, Unicode handling functions (option/unicode.c) must be added
|
||||
/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and
|
||||
/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255.
|
||||
/ It should be set 255 to support full featured LFN operations.
|
||||
/ 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(), must be added to the project. */
|
||||
|
||||
#define _LFN_UNICODE 1
|
||||
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)
|
||||
/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
|
||||
/ This option also affects behavior of string I/O functions. */
|
||||
|
||||
#define _STRF_ENCODE 3
|
||||
/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to
|
||||
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
||||
/
|
||||
/ 0: ANSI/OEM
|
||||
/ 1: UTF-16LE
|
||||
/ 2: UTF-16BE
|
||||
/ 3: UTF-8
|
||||
/
|
||||
/ This option has no effect when _LFN_UNICODE == 0. */
|
||||
|
||||
#define _FS_RPATH 0
|
||||
/* This option configures support of 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 _VOLUMES 1
|
||||
/* Number of volumes (logical drives) to be used. (1-10) */
|
||||
|
||||
#define _STR_VOLUME_ID 0
|
||||
#define _VOLUME_STRS "RAM", "NAND", "CF", "SD", "SD2", "USB", "USB2", "USB3"
|
||||
/* _STR_VOLUME_ID switches string support of volume ID.
|
||||
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
||||
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
||||
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
|
||||
/ the drive ID strings are: A-Z and 0-9. */
|
||||
|
||||
#define _MULTI_PARTITION 0
|
||||
/* This option switches support of multi-partition on a 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 multi-partition 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 _MIN_SS 512
|
||||
#define _MAX_SS 512
|
||||
/* These options configure 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 _MAX_SS is larger than _MIN_SS, FatFs is configured
|
||||
/ to variable sector size and GET_SECTOR_SIZE command needs to be implemented to
|
||||
/ the disk_ioctl() function. */
|
||||
|
||||
#define _USE_TRIM 0
|
||||
/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable)
|
||||
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
|
||||
#define _FS_NOFSINFO 0
|
||||
/* 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 _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 _MAX_SS bytes.
|
||||
/ Instead of private sector buffer eliminated from the file object, common sector
|
||||
/ buffer in the file system object (FATFS) is used for the file data transfer. */
|
||||
|
||||
#define _FS_EXFAT 1
|
||||
/* This option switches support of exFAT file system. (0:Disable or 1:Enable)
|
||||
/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
#define _FS_NORTC 0
|
||||
#define _NORTC_MON 1
|
||||
#define _NORTC_MDAY 1
|
||||
#define _NORTC_YEAR 2016
|
||||
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable
|
||||
/ the timestamp function. All objects modified by FatFs will have a fixed timestamp
|
||||
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time.
|
||||
/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be
|
||||
/ added to the project to get current time form real-time clock. _NORTC_MON,
|
||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||
/ These options have no effect at read-only configuration (_FS_READONLY = 1). */
|
||||
|
||||
#define _FS_LOCK 0
|
||||
/* The option _FS_LOCK switches file lock function to control duplicated file open
|
||||
/ and illegal operation to open objects. This option must be 0 when _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. */
|
||||
|
||||
#define _FS_REENTRANT 1
|
||||
#define _FS_TIMEOUT 1000
|
||||
#define _SYNC_t void*
|
||||
/* The option _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. _FS_TIMEOUT and _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 _FS_TIMEOUT defines timeout period in unit of time tick.
|
||||
/ The _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. */
|
||||
|
||||
/* #include <windows.h> // O/S definitions */
|
||||
|
||||
/*--- End of configuration options ---*/
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
extern "C" FRESULT f_open(FIL* fp, const TCHAR* path, BYTE mode);
|
||||
extern "C" FRESULT f_close(FIL* fp);
|
||||
extern "C" FRESULT f_read(FIL* fp, void* buff, UINT btr, UINT* br);
|
||||
extern "C" FRESULT f_write(FIL* fp, const void* buff, UINT btw, UINT* bw);
|
||||
extern "C" FRESULT f_lseek(FIL* fp, FSIZE_t ofs);
|
||||
extern "C" FRESULT f_truncate(FIL* fp);
|
||||
|
||||
extern "C" FRESULT f_sync(FIL* fp);
|
||||
extern "C" FRESULT f_opendir(DIR* dp, const TCHAR* path);
|
||||
extern "C" FRESULT f_closedir(DIR* dp);
|
||||
extern "C" FRESULT f_readdir(DIR* dp, FILINFO* fno);
|
||||
|
||||
extern "C" FRESULT f_findfirst(DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern);
|
||||
extern "C" FRESULT f_findnext(DIR* dp, FILINFO* fno);
|
||||
|
||||
extern "C" FRESULT f_mkdir(const TCHAR* path);
|
||||
extern "C" FRESULT f_unlink(const TCHAR* path);
|
||||
extern "C" FRESULT f_rename(const TCHAR* path_old, const TCHAR* path_new);
|
||||
extern "C" FRESULT f_stat(const TCHAR* path, FILINFO* fno);
|
||||
|
||||
extern "C" FRESULT f_chmod(const TCHAR* path, BYTE attr, BYTE mask);
|
||||
extern "C" FRESULT f_utime(const TCHAR* path, const FILINFO* fno);
|
||||
extern "C" FRESULT f_chdir(const TCHAR* path);
|
||||
extern "C" FRESULT f_chdrive(const TCHAR* path);
|
||||
|
||||
extern "C" FRESULT f_getcwd(TCHAR* buff, UINT len);
|
||||
extern "C" FRESULT f_getfree(const TCHAR* path, DWORD* nclst, FATFS** fatfs);
|
||||
extern "C" FRESULT f_getlabel(const TCHAR* path, TCHAR* label, DWORD* vsn);
|
||||
extern "C" FRESULT f_setlabel(const TCHAR* label);
|
||||
extern "C" FRESULT f_forward(FIL* fp, UINT (*func)(const BYTE*, UINT), UINT btf, UINT* bf);
|
||||
extern "C" FRESULT f_expand(FIL* fp, FSIZE_t szf, BYTE opt);
|
||||
|
||||
extern "C" FRESULT f_mount(FATFS* fs, const TCHAR* path, BYTE opt);
|
||||
extern "C" FRESULT f_mkfs(const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len);
|
||||
|
||||
extern "C" FRESULT f_fdisk(BYTE pdrv, const DWORD* szt, void* work);
|
||||
extern "C" int f_putc(TCHAR c, FIL* fp);
|
||||
|
||||
extern "C" int f_puts(const TCHAR* str, FIL* cp);
|
||||
extern "C" int f_printf(FIL* fp, const TCHAR* str, ...);
|
||||
extern "C" TCHAR* f_gets(TCHAR* buff, int len, FIL* fp);
|
||||
@@ -0,0 +1,38 @@
|
||||
/*-------------------------------------------*/
|
||||
/* Integer type definitions for FatFs module */
|
||||
/*-------------------------------------------*/
|
||||
|
||||
#ifndef _FF_INTEGER
|
||||
#define _FF_INTEGER
|
||||
|
||||
#ifdef _WIN32 /* FatFs development platform */
|
||||
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
typedef unsigned __int64 QWORD;
|
||||
|
||||
|
||||
#else /* Embedded platform */
|
||||
|
||||
/* These types MUST be 16-bit or 32-bit */
|
||||
typedef int INT;
|
||||
typedef unsigned int UINT;
|
||||
|
||||
/* This type MUST be 8-bit */
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
/* These types MUST be 16-bit */
|
||||
typedef short SHORT;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned short WCHAR;
|
||||
|
||||
/* These types MUST be 32-bit */
|
||||
typedef long LONG;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */
|
||||
typedef unsigned long long QWORD;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Bernd Herzog
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that 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; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "standalone_app.hpp"
|
||||
#include "digitalrain.hpp"
|
||||
#include <memory>
|
||||
|
||||
const standalone_application_api_t* _api;
|
||||
|
||||
extern "C" {
|
||||
__attribute__((section(".standalone_application_information"), used)) standalone_application_information_t _standalone_application_information = {
|
||||
/*.header_version = */ 2,
|
||||
|
||||
/*.app_name = */ "DigitalRain",
|
||||
/*.bitmap_data = */ {
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0xFC,
|
||||
0x3F,
|
||||
0xFE,
|
||||
0x7F,
|
||||
0x02,
|
||||
0x40,
|
||||
0xBA,
|
||||
0x45,
|
||||
0x02,
|
||||
0x40,
|
||||
0xFE,
|
||||
0x7F,
|
||||
0xFE,
|
||||
0x7F,
|
||||
0x92,
|
||||
0x7C,
|
||||
0x92,
|
||||
0x7C,
|
||||
0xFC,
|
||||
0x3F,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
},
|
||||
/*.icon_color = 16 bit: 5R 6G 5B*/ 0x0000FFE0,
|
||||
/*.menu_location = */ app_location_t::GAMES,
|
||||
|
||||
/*.initialize_app = */ initialize,
|
||||
/*.on_event = */ on_event,
|
||||
/*.shutdown = */ shutdown,
|
||||
/*PaintViewMirror */ PaintViewMirror,
|
||||
/*OnTouchEvent */ OnTouchEvent,
|
||||
/*OnFocus */ OnFocus,
|
||||
/*OnKeyEvent */ OnKeyEvent,
|
||||
/*OnEncoder */ OnEncoder,
|
||||
/*OnKeyboard */ OnKeyboad};
|
||||
}
|
||||
|
||||
/* Implementing abort() eliminates requirement for _getpid(), _kill(), _exit(). */
|
||||
extern "C" void abort() {
|
||||
while (true);
|
||||
}
|
||||
|
||||
// replace memory allocations to use heap from chibios
|
||||
extern "C" void* malloc(size_t size) {
|
||||
return _api->malloc(size);
|
||||
}
|
||||
extern "C" void* calloc(size_t num, size_t size) {
|
||||
return _api->calloc(num, size);
|
||||
}
|
||||
extern "C" void* realloc(void* p, size_t size) {
|
||||
return _api->realloc(p, size);
|
||||
}
|
||||
extern "C" void free(void* p) {
|
||||
_api->free(p);
|
||||
}
|
||||
|
||||
// redirect std lib memory allocations (sprintf, etc.)
|
||||
extern "C" void* __wrap__malloc_r(size_t size) {
|
||||
return _api->malloc(size);
|
||||
}
|
||||
extern "C" void __wrap__free_r(void* p) {
|
||||
_api->free(p);
|
||||
}
|
||||
|
||||
// redirect file I/O
|
||||
|
||||
extern "C" FRESULT f_open(FIL* fp, const TCHAR* path, BYTE mode) {
|
||||
return _api->f_open(fp, path, mode);
|
||||
}
|
||||
extern "C" FRESULT f_close(FIL* fp) {
|
||||
return _api->f_close(fp);
|
||||
}
|
||||
extern "C" FRESULT f_read(FIL* fp, void* buff, UINT btr, UINT* br) {
|
||||
return _api->f_read(fp, buff, btr, br);
|
||||
}
|
||||
extern "C" FRESULT f_write(FIL* fp, const void* buff, UINT btw, UINT* bw) {
|
||||
return _api->f_write(fp, buff, btw, bw);
|
||||
}
|
||||
extern "C" FRESULT f_lseek(FIL* fp, FSIZE_t ofs) {
|
||||
return _api->f_lseek(fp, ofs);
|
||||
}
|
||||
extern "C" FRESULT f_truncate(FIL* fp) {
|
||||
return _api->f_truncate(fp);
|
||||
}
|
||||
extern "C" FRESULT f_sync(FIL* fp) {
|
||||
return _api->f_sync(fp);
|
||||
}
|
||||
extern "C" FRESULT f_opendir(DIR* dp, const TCHAR* path) {
|
||||
return _api->f_opendir(dp, path);
|
||||
}
|
||||
extern "C" FRESULT f_closedir(DIR* dp) {
|
||||
return _api->f_closedir(dp);
|
||||
}
|
||||
extern "C" FRESULT f_readdir(DIR* dp, FILINFO* fno) {
|
||||
return _api->f_readdir(dp, fno);
|
||||
}
|
||||
extern "C" FRESULT f_findfirst(DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern) {
|
||||
return _api->f_findfirst(dp, fno, path, pattern);
|
||||
}
|
||||
extern "C" FRESULT f_findnext(DIR* dp, FILINFO* fno) {
|
||||
return _api->f_findnext(dp, fno);
|
||||
}
|
||||
extern "C" FRESULT f_mkdir(const TCHAR* path) {
|
||||
return _api->f_mkdir(path);
|
||||
}
|
||||
extern "C" FRESULT f_unlink(const TCHAR* path) {
|
||||
return _api->f_unlink(path);
|
||||
}
|
||||
extern "C" FRESULT f_rename(const TCHAR* path_old, const TCHAR* path_new) {
|
||||
return _api->f_rename(path_old, path_new);
|
||||
}
|
||||
extern "C" FRESULT f_stat(const TCHAR* path, FILINFO* fno) {
|
||||
return _api->f_stat(path, fno);
|
||||
}
|
||||
extern "C" FRESULT f_utime(const TCHAR* path, const FILINFO* fno) {
|
||||
return _api->f_utime(path, fno);
|
||||
}
|
||||
extern "C" FRESULT f_getfree(const TCHAR* path, DWORD* nclst, FATFS** fatfs) {
|
||||
return _api->f_getfree(path, nclst, fatfs);
|
||||
}
|
||||
extern "C" FRESULT f_mount(FATFS* fs, const TCHAR* path, BYTE opt) {
|
||||
return _api->f_mount(fs, path, opt);
|
||||
}
|
||||
extern "C" int f_putc(TCHAR c, FIL* fp) {
|
||||
return _api->f_putc(c, fp);
|
||||
}
|
||||
extern "C" int f_puts(const TCHAR* str, FIL* cp) {
|
||||
return _api->f_puts(str, cp);
|
||||
}
|
||||
extern "C" int f_printf(FIL* fp, const TCHAR* str, ...) {
|
||||
return _api->f_printf(fp, str);
|
||||
}
|
||||
extern "C" TCHAR* f_gets(TCHAR* buff, int len, FIL* fp) {
|
||||
return _api->f_gets(buff, len, fp);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that 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; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct bmp_header_t {
|
||||
uint16_t signature;
|
||||
uint32_t size;
|
||||
uint16_t reserved_1;
|
||||
uint16_t reserved_2;
|
||||
uint32_t image_data;
|
||||
uint32_t BIH_size;
|
||||
uint32_t width;
|
||||
int32_t height; // can be negative, to signal the bottom-up or reserve status
|
||||
uint16_t planes;
|
||||
uint16_t bpp;
|
||||
uint32_t compression;
|
||||
uint32_t data_size;
|
||||
uint32_t h_res;
|
||||
uint32_t v_res;
|
||||
uint32_t colors_count;
|
||||
uint32_t icolors_count;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct bmp_palette_t {
|
||||
struct color_t {
|
||||
uint8_t B;
|
||||
uint8_t G;
|
||||
uint8_t R;
|
||||
uint8_t A;
|
||||
} color[16];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that 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; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "bmpfile.hpp"
|
||||
|
||||
bool BMPFile::is_loaded() {
|
||||
return is_opened;
|
||||
}
|
||||
|
||||
// fix height info
|
||||
uint32_t BMPFile::get_real_height() {
|
||||
if (!is_opened) return 0;
|
||||
return bmp_header.height >= 0 ? (uint32_t)bmp_header.height : (uint32_t)(-1 * bmp_header.height);
|
||||
}
|
||||
|
||||
// get bmp width
|
||||
uint32_t BMPFile::get_width() {
|
||||
if (!is_opened) return 0;
|
||||
return bmp_header.width;
|
||||
}
|
||||
|
||||
// get if the rows are bottom up (for most bmp), or up to bottom (negative height, we use it for write)
|
||||
bool BMPFile::is_bottomup() {
|
||||
return (bmp_header.height >= 0);
|
||||
}
|
||||
|
||||
BMPFile::~BMPFile() {
|
||||
close();
|
||||
}
|
||||
|
||||
// closes file
|
||||
void BMPFile::close() {
|
||||
is_opened = false;
|
||||
bmpimage.close();
|
||||
}
|
||||
|
||||
// creates a new bmp file. hardcoded to 3 byte (24-bit) colour depth
|
||||
bool BMPFile::create(const std::filesystem::path& file, uint32_t x, uint32_t y) {
|
||||
is_opened = false;
|
||||
is_read_only = true;
|
||||
bmpimage.close(); // if already open, close before open a new
|
||||
if (file_exists(file)) {
|
||||
delete_file(file); // overwrite
|
||||
}
|
||||
auto result = bmpimage.open(file, false, true);
|
||||
if (!result.value().ok()) return false;
|
||||
file_pos = 0;
|
||||
byte_per_row = (x * 3 % 4 == 0) ? x * 3 : (x * 3 + (4 - ((x * 3) % 4))); // with padding
|
||||
bmpimage.seek(file_pos);
|
||||
bmp_header.signature = 0x4D42;
|
||||
bmp_header.planes = 1;
|
||||
bmp_header.compression = 0;
|
||||
bmp_header.bpp = 24; // 3 byte depth
|
||||
bmp_header.width = x;
|
||||
bmp_header.height = 0; // for now, will expand
|
||||
bmp_header.image_data = 0x36;
|
||||
bmp_header.BIH_size = 0x28;
|
||||
bmp_header.h_res = 100;
|
||||
bmp_header.v_res = 100;
|
||||
byte_per_px = 3;
|
||||
type = 1;
|
||||
bmp_header.size = sizeof(bmp_header) + get_real_height() * byte_per_row; // with padding! --will update later with expand
|
||||
bmp_header.data_size = bmp_header.size - sizeof(bmp_header_t);
|
||||
bmp_header.colors_count = 0;
|
||||
bmp_header.icolors_count = 0;
|
||||
|
||||
bmpimage.write(&bmp_header, sizeof(bmp_header_t));
|
||||
file_pos = bmp_header.image_data;
|
||||
is_opened = true;
|
||||
is_read_only = false;
|
||||
if (!expand_y(y)) return false; // will fill with 0, and update header data
|
||||
seek(0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// opens the file and parses header data. return true on success
|
||||
bool BMPFile::open(const std::filesystem::path& file, bool readonly) {
|
||||
is_opened = false;
|
||||
is_read_only = true;
|
||||
bmpimage.close();
|
||||
|
||||
auto result = bmpimage.open(file, readonly, false);
|
||||
if (!result.value().ok()) return false;
|
||||
file_pos = 0;
|
||||
bmpimage.seek(file_pos);
|
||||
bmpimage.read(&bmp_header, sizeof(bmp_header_t));
|
||||
if (!((bmp_header.signature == 0x4D42) &&
|
||||
(bmp_header.planes == 1) &&
|
||||
(bmp_header.compression == 0 || bmp_header.compression == 3))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (bmp_header.bpp) {
|
||||
case 8:
|
||||
type = 4;
|
||||
byte_per_px = 1;
|
||||
// bmpimage.seek(sizeof(bmp_header_t));
|
||||
// bmpimage.read(color_palette, 1024);
|
||||
return false; // niy
|
||||
break;
|
||||
|
||||
case 16:
|
||||
byte_per_px = 2;
|
||||
type = 5;
|
||||
if (bmp_header.compression == 3) {
|
||||
return false;
|
||||
} // niy
|
||||
|
||||
break;
|
||||
case 24:
|
||||
type = 1;
|
||||
byte_per_px = 3;
|
||||
break;
|
||||
case 32:
|
||||
type = 2;
|
||||
byte_per_px = 4;
|
||||
break;
|
||||
default:
|
||||
// not supported
|
||||
return false;
|
||||
}
|
||||
byte_per_row = (bmp_header.width * byte_per_px + 3) & ~3;
|
||||
file_pos = bmp_header.image_data;
|
||||
is_opened = true;
|
||||
is_read_only = readonly;
|
||||
currx = 0;
|
||||
curry = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// jumps to next pixel. false on the end
|
||||
bool BMPFile::advance_curr_px(uint32_t num = 1) {
|
||||
if (curry >= get_real_height()) return false;
|
||||
uint32_t rowsToAdvance = (currx + num) / bmp_header.width;
|
||||
uint32_t nx = (currx + num) % bmp_header.width;
|
||||
uint32_t ny = curry + rowsToAdvance;
|
||||
if (ny >= get_real_height()) {
|
||||
return false;
|
||||
}
|
||||
seek(nx, ny);
|
||||
return true;
|
||||
}
|
||||
|
||||
// reads next px, then advance the pos (and seek). return false on error
|
||||
bool BMPFile::read_next_px(ui::Color& px, bool seek = true) {
|
||||
if (!is_opened) return false;
|
||||
uint8_t buffer[4];
|
||||
auto res = bmpimage.read(buffer, byte_per_px);
|
||||
if (res.is_error()) return false;
|
||||
switch (type) {
|
||||
case 5: {
|
||||
// ARGB1555
|
||||
uint16_t val = buffer[0] | (buffer[1] << 8);
|
||||
// Extract components
|
||||
//*a = (val >> 15) & 0x01; // 1-bit alpha
|
||||
uint8_t r = (val >> 10) & 0x1F; // 5-bit red
|
||||
uint8_t g = (val >> 5) & 0x1F; // 5-bit green
|
||||
uint8_t b = (val)&0x1F; // 5-bit blue
|
||||
// expand
|
||||
r = (r << 3) | (r >> 2);
|
||||
g = (g << 3) | (g >> 2);
|
||||
b = (b << 3) | (b >> 2);
|
||||
px = ui::Color(r, g, b);
|
||||
break;
|
||||
}
|
||||
case 2: // 32
|
||||
px = ui::Color(buffer[2], buffer[1], buffer[0]);
|
||||
break;
|
||||
|
||||
case 4: { // 8-bit
|
||||
// uint8_t index = buffer[0];
|
||||
// px = ui::Color(color_palette[index][2], color_palette[index][1], color_palette[index][0]); // Palette is BGR
|
||||
// px = ui::Color(buffer[0]); // niy, since needs a lot of ram for the palette
|
||||
break;
|
||||
}
|
||||
case 1: // 24
|
||||
default:
|
||||
px = ui::Color(buffer[2], buffer[1], buffer[0]);
|
||||
break;
|
||||
}
|
||||
if (seek) advance_curr_px();
|
||||
return true;
|
||||
}
|
||||
|
||||
// if you set this, then the expanded part (or the newly created) will be filled with this color. but the expansion or the creation will be slower.
|
||||
void BMPFile::set_bg_color(ui::Color background) {
|
||||
bg = background;
|
||||
use_bg = true;
|
||||
}
|
||||
|
||||
// delete bg color. default. creation or expansion will be fast, but the file will contain random garbage. no problem if you write all pixels later.
|
||||
void BMPFile::delete_bg_color() {
|
||||
use_bg = false;
|
||||
}
|
||||
|
||||
// writes a color data to the current position, and advances 1 px. true on success, false on error
|
||||
bool BMPFile::write_next_px(ui::Color& px) {
|
||||
if (!is_opened || is_read_only) return false;
|
||||
uint8_t buffer[4];
|
||||
switch (type) {
|
||||
case 5:
|
||||
case 0: // R5G6B5
|
||||
case 3: // A1R5G5B5
|
||||
if (!type) {
|
||||
buffer[0] = (px.r() << 3) | (px.g() >> 3);
|
||||
buffer[1] = (px.g() << 5) | px.b();
|
||||
} else {
|
||||
buffer[0] = (1 << 7) | (px.r() << 2) | (px.g() >> 3);
|
||||
buffer[1] = (px.g() << 5) | px.b();
|
||||
}
|
||||
break;
|
||||
case 1: // 24
|
||||
default:
|
||||
buffer[2] = px.r();
|
||||
buffer[1] = px.g();
|
||||
buffer[0] = px.b();
|
||||
break;
|
||||
case 2: // 32
|
||||
buffer[2] = px.r();
|
||||
buffer[1] = px.g();
|
||||
buffer[0] = px.b();
|
||||
buffer[3] = 255;
|
||||
break;
|
||||
case 4: // 8-bit
|
||||
return false;
|
||||
}
|
||||
auto res = bmpimage.write(buffer, byte_per_px);
|
||||
if (res.is_error()) return false;
|
||||
advance_curr_px();
|
||||
return true;
|
||||
}
|
||||
|
||||
// positions in the file to the given pixel. 0 based indexing
|
||||
bool BMPFile::seek(uint32_t x, uint32_t y) {
|
||||
if (!is_opened) return false;
|
||||
if (x >= bmp_header.width) return false;
|
||||
if (y >= get_real_height()) return false;
|
||||
if (!BMPFile::is_bottomup()) {
|
||||
file_pos = bmp_header.image_data; // nav to start pos.
|
||||
file_pos += y * byte_per_row;
|
||||
file_pos += x * byte_per_px;
|
||||
bmpimage.seek(file_pos);
|
||||
currx = x;
|
||||
curry = y;
|
||||
} else {
|
||||
file_pos = bmp_header.image_data; // nav to start pos.
|
||||
file_pos += (get_real_height() - y - 1) * byte_per_row;
|
||||
file_pos += x * byte_per_px;
|
||||
bmpimage.seek(file_pos);
|
||||
currx = x;
|
||||
curry = y;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// expands the image with a delta (y). also seek's t it's begining. in bottumup format, it should be used carefully!
|
||||
bool BMPFile::expand_y_delta(uint32_t delta_y) {
|
||||
return expand_y(get_real_height() + delta_y);
|
||||
}
|
||||
|
||||
// expands the image to a new y size. also seek's t it's begining. in bottumup format, it should be used carefully!
|
||||
bool BMPFile::expand_y(uint32_t new_y) {
|
||||
if (!is_opened) return false; // not yet opened
|
||||
uint32_t old_height = get_real_height();
|
||||
if (new_y < old_height) return true; // already bigger
|
||||
if (is_read_only) return false; // can't expand
|
||||
uint32_t delta = (new_y - old_height) * byte_per_row;
|
||||
bmp_header.size += delta;
|
||||
bmp_header.data_size += delta;
|
||||
bmp_header.height = -1 * new_y; //-1*, so no bottom-up structure needed. easier to expand.
|
||||
bmpimage.seek(0);
|
||||
bmpimage.write(&bmp_header, sizeof(bmp_header)); // overwrite header
|
||||
bmpimage.seek(bmp_header.size); // seek to new end to expand
|
||||
// fill with bg color if needed
|
||||
if (use_bg) {
|
||||
seek(0, old_height); // to the new begin
|
||||
size_t newpxcount = ((new_y - old_height) * bmp_header.width);
|
||||
for (size_t i = 0; i < newpxcount; ++i)
|
||||
write_next_px(bg);
|
||||
}
|
||||
|
||||
if (is_bottomup()) {
|
||||
seek(0, new_y - old_height); // seek to the new chunk begin
|
||||
} else {
|
||||
seek(0, curry + 1); // seek to the begin of the new chunk
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user