From 7993f4b88fa3b8bc98769046d43b97ef5fa7448d Mon Sep 17 00:00:00 2001 From: Yann MAGNIN Date: Sat, 25 Sep 2021 16:02:50 +0200 Subject: [PATCH] vxBoot (0.0.1) - First commit @add <> terminal device <> builtin - ls (file listing), help (some information message)) <> smemfs - SMEM file system abstraction <> small CLI to interact with the core --- .gitignore | 14 +++ CMakeLists.txt | 46 +++++++ assets-cg/icon-sel.png | Bin 0 -> 8388 bytes assets-cg/icon-uns.png | Bin 0 -> 4629 bytes assets-fx/icon.png | Bin 0 -> 7429 bytes include/vxBoot/builtin.h | 11 ++ include/vxBoot/cli.h | 10 ++ include/vxBoot/fs/smemfs.h | 52 ++++++++ include/vxBoot/terminal.h | 79 ++++++++++++ src/builtin/help.c | 21 ++++ src/builtin/ls.c | 78 ++++++++++++ src/cli/parser.c | 140 +++++++++++++++++++++ src/fs/smemfs/mount.c | 117 ++++++++++++++++++ src/fs/smemfs/pread.c | 77 ++++++++++++ src/main.c | 81 ++++++++++++ src/terminal/close.c | 18 +++ src/terminal/open.c | 47 +++++++ src/terminal/read.c | 245 +++++++++++++++++++++++++++++++++++++ src/terminal/util.c | 168 +++++++++++++++++++++++++ src/terminal/write.c | 29 +++++ 20 files changed, 1233 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 assets-cg/icon-sel.png create mode 100644 assets-cg/icon-uns.png create mode 100644 assets-fx/icon.png create mode 100644 include/vxBoot/builtin.h create mode 100644 include/vxBoot/cli.h create mode 100644 include/vxBoot/fs/smemfs.h create mode 100644 include/vxBoot/terminal.h create mode 100644 src/builtin/help.c create mode 100644 src/builtin/ls.c create mode 100644 src/cli/parser.c create mode 100644 src/fs/smemfs/mount.c create mode 100644 src/fs/smemfs/pread.c create mode 100644 src/main.c create mode 100644 src/terminal/close.c create mode 100644 src/terminal/open.c create mode 100644 src/terminal/read.c create mode 100644 src/terminal/util.c create mode 100644 src/terminal/write.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d33e55 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Build files +/build-fx +/build-cg +/*.g1a +/*.g3a + +# Python bytecode + __pycache__/ + +# Common IDE files +*.sublime-project +*.sublime-workspace +.vscode +commit.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e27990d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.15) +project(vxBoot) + +include(GenerateG1A) +include(GenerateG3A) +include(Fxconv) +find_package(Gint 2.1 REQUIRED) + +set(SOURCES + src/main.c + src/cli/parser.c + src/fs/smemfs/mount.c + src/fs/smemfs/pread.c + src/terminal/close.c + src/terminal/open.c + src/terminal/read.c + src/terminal/util.c + src/terminal/write.c + src/builtin/ls.c + src/builtin/help.c +) +# Shared assets, fx-9860G-only assets and fx-CG-50-only assets +set(ASSETS + # ... +) +set(ASSETS_fx + # ... +) +set(ASSETS_cg + # ... +) + +fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA) + +add_executable(vxBoot ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}}) +target_compile_options(vxBoot PRIVATE -Wall -Wextra -Os) +target_include_directories(vxBoot PRIVATE include/) +target_link_libraries(vxBoot Gint::Gint) + +if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G) + generate_g1a(TARGET vxBoot OUTPUT "vxBoot.g1a" + NAME "vxBoot" ICON assets-fx/icon.png) +elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50) + generate_g3a(TARGET vxBoot OUTPUT "vxBoot.g3a" + NAME "vxBoot" ICONS assets-cg/icon-uns.png assets-cg/icon-sel.png) +endif() diff --git a/assets-cg/icon-sel.png b/assets-cg/icon-sel.png new file mode 100644 index 0000000000000000000000000000000000000000..7137b504cfd44f62f3105ce7a203b9100a557d0f GIT binary patch literal 8388 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 ag#Q8hHNm}t`+-sb0000 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 LNkvXXu0mjfMjhGA literal 0 HcmV?d00001 diff --git a/assets-fx/icon.png b/assets-fx/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c92f12afab0af9f7b3d8e2bec76a1dc5cc9c08a1 GIT binary patch literal 7429 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 +#include + +extern int ls_main(int argc, char **argv); +extern int os_main(int argc, char **argv); +extern int help_main(int argc, char **argv); + +#endif /*__VXBOOT_BUILTIN_H__*/ diff --git a/include/vxBoot/cli.h b/include/vxBoot/cli.h new file mode 100644 index 0000000..1d48b27 --- /dev/null +++ b/include/vxBoot/cli.h @@ -0,0 +1,10 @@ +#ifndef __VXBOOT_PARSER_H__ +# define __VXBOOT_PARSER_H__ + +#include +#include + +extern int cli_parser_strtotab(int *argc, char ***argv, char const *str); +extern void cli_parser_strtotab_quit(int *argc, char ***argv); + +#endif /*__VXBOOT_PARSER_H__*/ diff --git a/include/vxBoot/fs/smemfs.h b/include/vxBoot/fs/smemfs.h new file mode 100644 index 0000000..a71340e --- /dev/null +++ b/include/vxBoot/fs/smemfs.h @@ -0,0 +1,52 @@ +#ifndef __VXBOOT_FS_SMEMFS_H__ +# define __VXBOOT_FS_SMEMFS_H__ + +#include +#include + +#include + +//---- +// Internal structure used to provide Casio's syscall abstraction +//--- + +/* Internal superblock use for the Casio's syscall abstraction */ +struct smemfs_superblock { + struct smemfs_inode *root_inode; + struct smemfs_inode *fake_root_inode; +}; + +/* Internal struct used to store SMEM dump */ +struct smemfs_inode { + /* File name */ + char name[32]; + + /* Internal file's information */ + int type; + size_t fsize; + size_t dsize; + + /* Internal abstraction information */ + struct smemfs_inode *child; + struct smemfs_inode *sibling; + struct smemfs_inode *parent; +}; + +//--- +// Dev symbols +//--- +#define SMEMFS_FAKE_ROOT_INODE ((void*)0xdeadbeef) +extern struct smemfs_superblock smemfs_superblock; + + +//--- +// Primitives +//--- +extern struct smemfs_inode *smemfs_mount(void); + +extern ssize_t smemfs_pread(struct smemfs_inode *inode, + void *buf, size_t count, off_t pos); + +extern struct smemfs_inode *smemfs_alloc_inode(void); + +#endif /*__VXBOOT_FS_SMEMFS_H__*/ diff --git a/include/vxBoot/terminal.h b/include/vxBoot/terminal.h new file mode 100644 index 0000000..3465646 --- /dev/null +++ b/include/vxBoot/terminal.h @@ -0,0 +1,79 @@ +#ifndef __VXBOOT_TERMINAL_H__ +# define __VXBOOT_TERMINAL_H__ + +#include +#include +#include + +/* internal terminal hardcoded information */ +#define TERM_PRIVATE_WATERMARK (0xdeadbeef) +#define TERM_RDBUFFER_NBLINE (32) + +/* hardcoded font size (TODO: dynamic !) */ +#ifdef FXCG50 +#define FWIDTH 8 +#define FHEIGHT 9 +#endif +#ifdef FX9860G +#define FWIDTH 5 +#define FHEIGHT 7 +#endif + +/* define terminal structure */ +struct terminal { + /* windows information */ + struct { + unsigned short ws_col; + unsigned short ws_row; + unsigned short ws_xpixel; + unsigned short ws_ypixel; + unsigned short ft_xpixel; + unsigned short ft_ypixel; + } winsize; + + /* cursor information */ + struct { + unsigned short x; + unsigned short y; + } cursor; + + /* buffer information */ + struct { + uint8_t *data; + off_t cursor; + size_t size; + } buffer; + + /* private information */ + struct { + struct { + int id; + } timer; + uint32_t watermark; + struct { + int fg; + int bg; + } color; + } private; +}; + +/* define the terminal */ +extern struct terminal terminal; + +//--- +// User interface +//--- +extern int terminal_open(void); +extern int terminal_write(const char *format, ...); +extern int terminal_read(void *buffer, size_t nb); +extern int terminal_close(void); + +//--- +// Internal interface +//--- +extern void terminal_clear(void); +extern int terminal_cursor_handler(void); +extern void terminal_buffer_display(void); +extern void terminal_buffer_insert(char *buffer, size_t nb); + +#endif /*__FXBOOT_TERMINAL_H__*/ diff --git a/src/builtin/help.c b/src/builtin/help.c new file mode 100644 index 0000000..0500d77 --- /dev/null +++ b/src/builtin/help.c @@ -0,0 +1,21 @@ +#include "vxBoot/builtin.h" +#include "vxBoot/terminal.h" + +int help_main(int argc, char **argv) +{ + //TODO : use arguments ? + (void)argc; + (void)argv; + + terminal_write( +"VxBoot was created by Yatis for the sole purpose of being able to load Vhex -" +" an experimental operating system touching many sensitive things on the " +"machine.\n" +"\n" +"The available commands are:\n" +" help - display this help message\n" +" ls - list files in storage memory\n" +" os - allows you to interact with the bootstraper\n" + ); + return (0); +} diff --git a/src/builtin/ls.c b/src/builtin/ls.c new file mode 100644 index 0000000..903b9c3 --- /dev/null +++ b/src/builtin/ls.c @@ -0,0 +1,78 @@ +#include "vxBoot/builtin.h" +#include "vxBoot/terminal.h" +#include "vxBoot/fs/smemfs.h" + +#include + +#include + +/* ls_help() : Display the hep message */ +static void ls_help(void) +{ + terminal_write( +"NAME\n" +" ls - list directory contents\n" +"\n" +"SYNOPSIS\n" +" ls [-h|--help]\n" +"\n" +"DESCRIPTION\n" +" List file information about FILEs (from the root directory only). The" +" display is inspired from the utilitary `tree` in UNIX environment.\n" +"\n" +" -h,--help\n" +" Display this help message\n" + ); +} + +/* inode_walk() : walk onto the filesystem and display files */ +static void inode_walk(struct smemfs_inode *inode, int level, uint32_t bitmap) +{ + const char *records; + + if (inode == NULL) + return; + + /* handle indentation */ + for (int i = 0; i < level; ++i) { + records = "\t"; + if ((bitmap & (1 << i)) != 0) + records = "|\t"; + terminal_write(records); + } + + /* handle file name and sibling dependencies */ + records = "|-- (%x) %s"; + bitmap |= 1 << level; + if (inode->sibling == NULL) { + records = "`-- (%x) %s"; + bitmap &= ~(1 << level); + } + terminal_write(records, inode->type, inode->name); + + /* handle file type */ + if (inode->type == BFile_Type_Directory) { + terminal_write(":\n"); + inode_walk(inode->child, level + 1, bitmap); + inode_walk(inode->sibling, level, bitmap); + return; + } + terminal_write("\n"); + inode_walk(inode->sibling, level, bitmap); +} + +/* ls_main() : entry of the "ls" builtin */ +int ls_main(int argc, char **argv) +{ + if (smemfs_superblock.fake_root_inode != SMEMFS_FAKE_ROOT_INODE) { + terminal_write("smemfs not mounted !\n"); + return (84); + } + if (argc > 1 && strcmp(argv[1], "-help") == 0) { + ls_help(); + return (0); + } + terminal_write("/:\n"); + inode_walk(smemfs_superblock.root_inode, 0, 0x00000000); + return (0); +} diff --git a/src/cli/parser.c b/src/cli/parser.c new file mode 100644 index 0000000..a535a45 --- /dev/null +++ b/src/cli/parser.c @@ -0,0 +1,140 @@ +#include "vxBoot/cli.h" + +#include +#include + +/* define external symbols */ +extern int cli_parser_strtotab(int *argc, char ***argv, char const *str); +extern void cli_parser_strtotab_quit(int *argc, char ***argv); + +/* parser_get_word(): Get the word at the current cursor location. */ +static int parser_get_word(char ***tab, size_t *tab_pos, + char const *str, int *counter) +{ + int i; + + /* skip until separator */ + i = -1; + while (str[++i] != '\0' + && str[i] != '\n' + && str[i] != ' ' + && str[i] != '\t'); + + /* dump the word of needed */ + if (*tab != NULL) { + (*tab)[*tab_pos] = (char*)calloc(1, i + 1); + if ((*tab)[*tab_pos] == NULL) + return (-1); + memset((*tab)[*tab_pos], 0, i + 1); + strncpy((*tab)[(*tab_pos)++], str, i); + } + + /* update the internal counter */ + (*counter)++; + return (i); +} + +/* parser_get_inibitor() + + This function will get the content of an inhibitor (and check if the + inhibitor characteres are alone or not). */ +static int parser_get_inibitor(char ***tab, size_t *tab_pos, + char const *str, int *counter) +{ + int i; + + /* get the inibitor end */ + i = 0; + while (str[++i] != '\0' && str[i] != '\"'); + if (str[i] != '\"') + return (0); + + /* dump the word if needed */ + if (*tab != NULL) { + (*tab)[*tab_pos] = (char*)calloc(1, i + 1); + if ((*tab)[*tab_pos] == NULL) + return (-1); + memset((*tab)[*tab_pos], 0, i + 1); + strncpy((*tab)[(*tab_pos)++], str + 1, i - 1); + } + + /* update the internal counter */ + (*counter)++; + return (i + 1); +} + +/* parser_setup_arg() + + This function removes useless spaces, tabs and handle '\"' inhibitor. + Return the number of word(s) stored in "str". */ +static int parser_entry(char ***tab, char const *str) +{ + size_t tab_pos; + int counter; + int sz; + + str--; + sz = 0; + counter = 0; + tab_pos = 0; + while (*(++str) != '\0' && *str != '\n' && sz >= 0) { + if (*str == '\"') { + sz = parser_get_inibitor(tab, &tab_pos, str, &counter); + if (sz > 0) { + str = &str[sz]; + continue; + } + } + if (*str != ' ' && *str != '\t') { + sz = parser_get_word(tab, &tab_pos, str, &counter) - 1; + if (sz > 0) + str = &str[sz]; + } + } + return (counter); +} + +/* cli_parser_strtotab() + Generate word table and indicated the number of word find in the string. */ +int cli_parser_strtotab(int *argc, char ***argv, char const *str) +{ + if (argc == NULL || argv == NULL || str == NULL) + return (-1); + + /* Get the number of word. */ + *argv = NULL; + *argc = parser_entry(argv, str); + if (*argc <= 0) + return (-2); + + *argv = (char **)calloc(1, sizeof(char *) * (*argc + 1)); + if (*argv == NULL) + return (-3); + + /* Dump all word. */ + if (parser_entry(argv, str) != *argc) { + cli_parser_strtotab_quit(argc, argv); + return (-4); + } + (*argv)[*argc] = NULL; + return (0); +} + +/* cli_parser_strtotab_quit() + Free all allocated memory generated by "strtotab()" */ +void cli_parser_strtotab_quit(int *argc, char ***argv) +{ + if (argc == NULL || argv == NULL) + return; + if (*argv == NULL) { + *argc = 0; + return; + } + while (--(*argc) >= 0) { + if ((*argv)[*argc] != NULL) + free((*argv)[*argc]); + } + free(*argv); + *argv = NULL; + *argc = 0; +} diff --git a/src/fs/smemfs/mount.c b/src/fs/smemfs/mount.c new file mode 100644 index 0000000..4325e7c --- /dev/null +++ b/src/fs/smemfs/mount.c @@ -0,0 +1,117 @@ +#include "vxBoot/fs/smemfs.h" +#include "vxBoot/terminal.h" + +#include +#include +#include + +#include +#include + +/* Define the super block information */ +struct smemfs_superblock smemfs_superblock = { + .root_inode = NULL, + .fake_root_inode = NULL +}; + +/* wide_char_convert(): convert wide character to ASCII format */ +static size_t wide_char_convert(char *pathname, uint16_t *pathname_wc) +{ + size_t i; + + i = -1; + while (pathname_wc[++i] != 0x0000 && pathname_wc[i] != 0xffff) + pathname[i] = pathname_wc[i] & 0x00ff; + pathname[i] = '\0'; + return (i); +} + +/* dump_smem_level(): Dump one level of the SMEM FileSystem */ +static void dump_smem_level(struct smemfs_inode *parent, + struct smemfs_inode **sibling, + uint16_t *path, off_t cursor) +{ + struct BFile_FileInfo file_info; + struct smemfs_inode *inode; + uint16_t buffer[32]; + int handle; + + /* Generate searching path: + This format is used by the `Bfile_Find*()` syscall */ + if (parent != NULL) { + for (int j = 0; parent->name[j] != '\0'; ++j) + path[cursor++] = (uint16_t)(parent->name[j]); + path[cursor++] = '\\'; + } + path[cursor + 0] = '*'; + path[cursor + 1] = 0x0000; + + /* Find the first file: + The search buffer and the buffer which will content the file name is + the same. But it's not used at the same time so we can use this + tricky way to save some stack space. */ + if (BFile_FindFirst(path, &handle, buffer, &file_info) != 0) + return; + inode = NULL; + do { + /* Try to alloc new inode */ + *sibling = calloc(1, sizeof(struct smemfs_inode)); + if (*sibling == NULL) + break; + + /* Save the first inode (used after for directories checking) */ + if (inode == NULL) + inode = *sibling; + + /* Convert wide char to ASCII */ + wide_char_convert((*sibling)->name, buffer); + + /* Dump file informations */ + (*sibling)->type = file_info.type; + (*sibling)->fsize = file_info.file_size; + (*sibling)->dsize = file_info.data_size; + + /* Link node and get next sibling */ + (*sibling)->parent = parent; + sibling = &(*sibling)->sibling; + + /* try to find the next file information */ + } while (BFile_FindNext(handle, buffer, &file_info) == 0); + BFile_FindClose(handle); + + /* Now let's check all files to find directories */ + while (inode != NULL) { + if (inode->type == BFile_Type_Directory) + dump_smem_level(inode, &inode->child, path, cursor); + inode = inode->sibling; + } +} + +/* smemfs_mount(): Mount the file system + + We only use internal Casio's syscall, so this dummy primitive can + be ported easly. */ +struct smemfs_inode *smemfs_mount(void) +{ + uint16_t buffer[512]; + void *root_inode; + + root_inode = smemfs_superblock.root_inode; + if (root_inode == NULL) { + /* Generate fake root inode */ + smemfs_superblock.fake_root_inode = SMEMFS_FAKE_ROOT_INODE; + + /* Dump SMEM files organisation */ + smemfs_superblock.root_inode = NULL; + memcpy(buffer, u"\\\\fls0\\", 14); + dump_smem_level(smemfs_superblock.root_inode, + &smemfs_superblock.root_inode, + buffer, 7); + + /* Get the "fake" root inode */ + root_inode = smemfs_superblock.fake_root_inode; + } + + /* Return the sector table to simulate the root inode. */ + return (root_inode); +} diff --git a/src/fs/smemfs/pread.c b/src/fs/smemfs/pread.c new file mode 100644 index 0000000..a0de81a --- /dev/null +++ b/src/fs/smemfs/pread.c @@ -0,0 +1,77 @@ +#include "vxBoot/fs/smemfs.h" + +#include +#include + +#include + +/* internal struct */ +struct __file_info { + uint16_t pathname[256]; + void *buf; + size_t count; + off_t pos; +}; + +/* generate_abolute_path(): Generate abolute path + + This function will generate the absolute path of a file because Casio's open + primitive doesn't handle cannonical path */ +static void generate_absolute_path(uint16_t *pathname, + struct smemfs_inode *inode, int *pos) +{ + if (inode == NULL) { + memcpy(pathname, u"\\\\fls0", 12); + *pos = 6; + return; + } + + generate_absolute_path(pathname, inode->parent, pos); + + pathname[(*pos)++] = '\\'; + for (int i = 0; inode->name[i] != '\0'; ) { + pathname[*pos] = inode->name[i]; + *pos = *pos + 1; + i = i + 1; + } + pathname[*pos] = '\0'; +} + +/* __smemfs_pread() : involved in Casio's world */ +static void __smemfs_pread(struct __file_info *info, ssize_t *read) +{ + int handle; + + *read = -1; + handle = BFile_Open(info->pathname, BFile_ReadOnly); + if (handle >= 0) { + *read = BFile_Read(handle, info->buf, info->count, info->pos); + BFile_Close(handle); + } +} + +/* smemfs_read(): Read primitive */ +ssize_t smemfs_pread(struct smemfs_inode *inode, + void *buf, size_t count, off_t pos) +{ + struct __file_info file_info = { + .buf = buf, + .count = count, + .pos = pos + }; + ssize_t read; + int tmp; + + if (inode == NULL) + return (-1); + + tmp = 0; + generate_absolute_path(file_info.pathname, inode, &tmp); + + gint_world_switch(GINT_CALL( + (void*)&__smemfs_pread, + (void*)&file_info, &read + )); + + return (read); +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..b756317 --- /dev/null +++ b/src/main.c @@ -0,0 +1,81 @@ +#include "vxBoot/terminal.h" +#include "vxBoot/cli.h" +#include "vxBoot/builtin.h" +#include "vxBoot/fs/smemfs.h" + +#include +#include + +#include + +//TODO: better API for the command-line parser + +/* internal builtin list */ +struct { + const char *name; + int (*f)(int argc, char **argv); +} cmd_list[] = { + {.name = "ls", &ls_main}, + {.name = "os", NULL}, + {.name = "help", &help_main}, + {.name = NULL, NULL} +}; + +/* try to find the appropriate command */ +static int (*check_cmd(char *cmd))(int, char**) +{ + for (int i = 0; cmd_list[i].name != NULL; ++i) { + if (strcmp(cmd, cmd_list[i].name) != 0) + continue; + if (cmd_list[i].f == NULL) + terminal_write("command exist but not implemented\n"); + return (cmd_list[i].f); + } + return (NULL); +} + +/* entry of the bootloader */ +int main(void) +{ + int (*builtin)(int, char**); + const char *usrline; + char buff[128]; + char **argv; + int argc; + int ret; + + /* automated hook */ + /* TODO: better way to execute early command */ + smemfs_mount(); + + ret = 0; + terminal_open(); + terminal_write("Welcome to vxBoot, the bootstrapper for the Vhex kernel!\n"); + terminal_write("Type `help` for instruction on how to use vxBoot\n"); + while (1) { + /* get user command */ + usrline = (ret != 0) ? "/[%d]>" : "/>"; + terminal_write(usrline, ret); + ret = 0; + if (terminal_read(buff, 128) <= 1) + continue; + + /* parse and try to find the command */ + if (cli_parser_strtotab(&argc, &argv, buff) != 0) { + terminal_write("error when processing \"%s\"", buff); + ret = 255; + continue; + } + builtin = check_cmd(argv[0]); + if (builtin == NULL) { + terminal_write("command \"%s\" not found\n", argv[0]); + ret = 127; + continue; + } + + /* execute the command and free'd allocated memories */ + ret = builtin(argc, argv); + cli_parser_strtotab_quit(&argc, &argv); + } + return (1); +} diff --git a/src/terminal/close.c b/src/terminal/close.c new file mode 100644 index 0000000..01ec2c9 --- /dev/null +++ b/src/terminal/close.c @@ -0,0 +1,18 @@ +#include "vxBoot/terminal.h" + +#include + +#include + +/* terminal_close(): Uninitialize the terminal */ +int terminal_close(void) +{ + if (terminal.private.watermark != TERM_PRIVATE_WATERMARK) + return (-1); + if (terminal.private.timer.id >= 0) + timer_stop(terminal.private.timer.id); + if (terminal.buffer.data != NULL) + free(terminal.buffer.data); + terminal.private.watermark = TERM_PRIVATE_WATERMARK; + return (0); +} diff --git a/src/terminal/open.c b/src/terminal/open.c new file mode 100644 index 0000000..0c7b7b3 --- /dev/null +++ b/src/terminal/open.c @@ -0,0 +1,47 @@ +#include "vxBoot/terminal.h" + +#include +#include + +#include +#include + +/* internal symbols */ +struct terminal terminal; + +/* terminal_open(): Initialize and open the terminal */ +int terminal_open(void) +{ + if (terminal.private.watermark == TERM_PRIVATE_WATERMARK) + terminal_close(); + memset(&terminal, 0x00, sizeof(struct terminal)); + terminal.private.timer.id = -1; + terminal.winsize.ws_xpixel = DWIDTH; + terminal.winsize.ws_ypixel = DHEIGHT; + terminal.winsize.ft_xpixel = FWIDTH + 1; + terminal.winsize.ft_ypixel = FHEIGHT + 1; + terminal.winsize.ws_col = DWIDTH / terminal.winsize.ft_xpixel; + terminal.winsize.ws_row = DHEIGHT / terminal.winsize.ft_ypixel; + terminal.buffer.size = terminal.winsize.ws_row + * terminal.winsize.ws_col + * TERM_RDBUFFER_NBLINE + * sizeof(uint8_t); + terminal.buffer.data = calloc(1, terminal.buffer.size); + if (terminal.buffer.data == NULL) { + terminal_close(); + return (-1); + } + terminal.private.timer.id = timer_configure( + TIMER_ANY, + 250000, + GINT_CALL(terminal_cursor_handler) + ); + if (terminal.private.timer.id < 0) { + terminal_close(); + return (-1); + } + terminal.private.color.bg = C_BLACK; + terminal.private.color.fg = C_WHITE; + terminal.private.watermark = TERM_PRIVATE_WATERMARK; + return (0); +} diff --git a/src/terminal/read.c b/src/terminal/read.c new file mode 100644 index 0000000..6a312f2 --- /dev/null +++ b/src/terminal/read.c @@ -0,0 +1,245 @@ +#include "vxBoot/terminal.h" + +#include +#include +#include + +#include + +/* internal structure used to store many information */ +struct { + struct { + unsigned short x; + unsigned short y; + int visible; + off_t saved; + } cursor; + struct { + uint8_t alpha: 1; + uint8_t shift: 1; + uint8_t ctrl: 1; + uint8_t exit: 1; + uint8_t const: 4; + } mode; + struct { + size_t max; + size_t size; + off_t cursor; + char *data; + } buffer; +} term_rdinfo; + +//--- +// +//--- +void term_display_all(void) +{ + /* stop the timer too avoid interrupt-loop */ + if (terminal.private.timer.id >= 0) + timer_pause(terminal.private.timer.id); + + /* mark special characte that the cursor is here */ + if (term_rdinfo.cursor.visible == 1) + term_rdinfo.buffer.data[term_rdinfo.buffer.cursor] |= 0x80; + + /* restore terminal context */ + terminal.cursor.x = term_rdinfo.cursor.x; + terminal.cursor.y = term_rdinfo.cursor.y; + terminal.buffer.cursor = term_rdinfo.cursor.saved; + terminal_buffer_insert(term_rdinfo.buffer.data, + term_rdinfo.buffer.size); + + /* display management */ + dclear(terminal.private.color.bg); + terminal_buffer_display(); + dupdate(); + + /* remove cursor mark */ + term_rdinfo.buffer.data[term_rdinfo.buffer.cursor] &= ~0x80; + + /* restart the timer */ + if (terminal.private.timer.id >= 0) + timer_start(terminal.private.timer.id); +} + +//--- +// Callback function +//--- + +int terminal_cursor_handler(void) +{ + term_rdinfo.cursor.visible ^= 1; + term_display_all(); + return (0); +} + +//--- +// buffer functions +//--- + +/* term_buffer_remove(): Remove character based on current cursor position */ +static void term_buffer_remove(void) +{ + /* check if this action is possible */ + if (term_rdinfo.buffer.cursor == 0) + return; + /* move data if needed */ + if (term_rdinfo.buffer.cursor < term_rdinfo.buffer.size - 1) { + memcpy( + &term_rdinfo.buffer.data[term_rdinfo.buffer.cursor - 1], + &term_rdinfo.buffer.data[term_rdinfo.buffer.cursor], + term_rdinfo.buffer.size - term_rdinfo.buffer.cursor + ); + } + /* force NULL-char and update cursor/size */ + term_rdinfo.buffer.cursor = term_rdinfo.buffer.cursor - 1; + term_rdinfo.buffer.data[--term_rdinfo.buffer.size - 1] = '\0'; +} + +/* term_buffer_insert() - Insert character based on current cursor position */ +static int term_buffer_insert(char n) +{ + /* save space for the "\n\0" (EOL) */ + if (term_rdinfo.buffer.size + 1 >= term_rdinfo.buffer.max) + return (-1); + /* move data if needed */ + if (term_rdinfo.buffer.cursor < term_rdinfo.buffer.size - 1) { + off_t i = term_rdinfo.buffer.size + 1; + while (--i >= term_rdinfo.buffer.cursor) { + term_rdinfo.buffer.data[i] = + term_rdinfo.buffer.data[i - 1]; + } + } + /* insert the character and force NULL-char */ + term_rdinfo.buffer.data[term_rdinfo.buffer.cursor++] = n; + term_rdinfo.buffer.data[++term_rdinfo.buffer.size] = '\0'; + return (0); +} + +//--- +// key handling +//--- + +// TODO +// - F_UP -> history +// - F_DOWN -> history +static int term_key_handle_special(key_event_t key_event) +{ + switch (key_event.key) { + case KEY_SHIFT: term_rdinfo.mode.shift ^= 1; return (1); + case KEY_ALPHA: term_rdinfo.mode.alpha ^= 1; return (1); + case KEY_OPTN: term_rdinfo.mode.ctrl ^= 1; return (1); + case KEY_DOT: term_buffer_insert(' '); return (1); + case KEY_DEL: term_buffer_remove(); return (1); + case KEY_EXE: + /* Add End Of Line character */ + term_rdinfo.buffer.data[term_rdinfo.buffer.size - 1] = '\n'; + term_rdinfo.buffer.data[term_rdinfo.buffer.size] = '\0'; + + /* indicate that the EXE key has been pressed. */ + term_rdinfo.mode.exit = 1; + return (1); + case KEY_LEFT: + if (term_rdinfo.buffer.cursor > 0) + term_rdinfo.buffer.cursor -= 1; + return (1); + case KEY_RIGHT: + if (term_rdinfo.buffer.cursor < term_rdinfo.buffer.size - 1) + term_rdinfo.buffer.cursor += 1; + return (1); + default: + return (0); + } +} + +/* term_buffer_update() - Update the internal buffer with the given key code */ +static int term_key_buffer_update(key_event_t key_event) +{ + static const uint8_t keylist_alpha[] = { + KEY_XOT, KEY_LOG, KEY_LN, KEY_SIN, KEY_COS, KEY_TAN, + KEY_FRAC, KEY_FD, KEY_LEFTP, KEY_RIGHTP, KEY_COMMA, KEY_ARROW, + KEY_7, KEY_8, KEY_9, + KEY_4, KEY_5, KEY_6, KEY_MUL, KEY_DIV, + KEY_1, KEY_2, KEY_3, KEY_PLUS, KEY_MINUS, + KEY_0, 0xff + }; + static const uint8_t keylist_num[] = { + KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, + KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, + KEY_PLUS, KEY_MINUS, KEY_MUL, KEY_DIV, + KEY_LEFTP, KEY_RIGHTP, KEY_COMMA, KEY_POWER, + KEY_DOT, KEY_FD, KEY_ARROW, 0xff + }; + static const char keylist_num_char[] = "0123456789+-x/(),^.|_"; + const uint8_t *keycode_list; + char character; + int i; + + /* Get the appropriate key list. */ + keycode_list = keylist_alpha; + if (term_rdinfo.mode.shift == 1) + keycode_list = keylist_num; + + /* Try to find the pressed key. */ + i = -1; + while (keycode_list[++i] != 0xff && keycode_list[i] != key_event.key); + if (keycode_list[i] != key_event.key) + return (0); + + /* handle mode then update the buffer */ + if (term_rdinfo.mode.shift == 0) { + character = 'a' + i; + if (term_rdinfo.mode.alpha == 1) + character = 'A' + i;; + } else { + character = keylist_num_char[i]; + } + term_buffer_insert(character); + return (1); +} + + + +//--- +// primitive +//--- +int terminal_read(void *buffer, size_t nb) +{ + key_event_t key; + + /* check obvious error */ + if (buffer == NULL || nb == 0) + return (0); + + /* initialize internal data */ + memset(&term_rdinfo, 0x00, sizeof(term_rdinfo)); + memset(buffer, 0x00, nb); + + /* save terminal information */ + term_rdinfo.cursor.saved = terminal.buffer.cursor; + term_rdinfo.cursor.x = terminal.cursor.x; + term_rdinfo.cursor.y = terminal.cursor.y; + term_rdinfo.buffer.data = buffer; + term_rdinfo.buffer.size = 1; + term_rdinfo.buffer.max = nb; + + /* start cursor blink timer */ + if (terminal.private.timer.id >= 0) + timer_start(terminal.private.timer.id); + + /* keyboard handling */ + while (term_rdinfo.mode.exit == 0) { + /* handle pressed keys */ + key = getkey_opt(GETKEY_REP_ALL | GETKEY_MENU, NULL); + if (term_key_handle_special(key) == 0) + term_key_buffer_update(key); + + /* display */ + term_display_all(); + } + + /* stop the timer */ + if (terminal.private.timer.id >= 0) + timer_pause(terminal.private.timer.id); + return (term_rdinfo.buffer.size); +} diff --git a/src/terminal/util.c b/src/terminal/util.c new file mode 100644 index 0000000..0b10883 --- /dev/null +++ b/src/terminal/util.c @@ -0,0 +1,168 @@ +#include "vxBoot/terminal.h" + +#include + +#include + + +//--- +// Update the internal buffer +//--- + +/* terminal_buffer_insert() : insert string anywhere in the output buffer */ +void terminal_buffer_insert(char *buffer, size_t nb) +{ + size_t dump; + void *start; + + /* calculate the "real" number of byte to dump into the buffer */ + dump = nb; + start = &buffer[0]; + if (dump > terminal.buffer.size) { + dump -= terminal.buffer.size; + start = &buffer[nb - dump]; + } + + /* dump the buffer (be carful with the circular effect) */ + if (terminal.buffer.cursor + dump > terminal.buffer.size) { + memcpy( + &terminal.buffer.data[terminal.buffer.cursor], + start, + terminal.buffer.size - terminal.buffer.cursor + ); + dump -= terminal.buffer.size - terminal.buffer.cursor; + terminal.buffer.cursor = 0; + } + memcpy(&terminal.buffer.data[terminal.buffer.cursor], start, dump); + terminal.buffer.cursor += dump; +} + + +//--- +// Display the internal buffer +//--- + +/* terminal_vertical_update() - Update vertical cursor */ +static void terminal_vertical_update(void) +{ + if (terminal.cursor.y + 1 < terminal.winsize.ws_col) { + terminal.cursor.y = terminal.cursor.y + 1; + return; + } +} + +/* earlyterm_horizontal_update() - Update horizotal cursor */ +static int terminal_horizontal_update(void) +{ + terminal.cursor.x = terminal.cursor.x + 1; + if (terminal.cursor.x >= terminal.winsize.ws_col) { + terminal_vertical_update(); + terminal.cursor.x = 0; + return (1); + } + return (0); +} + +/* line_discipline() - Check "special" char */ +static int terminal_line_discipline(char n) +{ + int offset; + + switch (n) { + case '\0': + return (1); + case '\n': + terminal.cursor.x = 0; + terminal_vertical_update(); + return (1); + case '\b': + if (terminal.cursor.x > 0) + terminal.cursor.x = terminal.cursor.x - 1; + return (1); + case '\v': + terminal_vertical_update(); + return (1); + case '\r': + terminal.cursor.x = 0; + return (1); + case '\t': + /* Check if we need a new line or not. */ + offset = terminal.cursor.x - ((terminal.cursor.x / 5) * 5); + offset = 5 - offset; + while (--offset >= 0) + terminal_horizontal_update(); + return (1); + default: + return (0); + } +} + +/* terminal_buffer_write() : display the buffer on screen */ +void terminal_buffer_display(void) +{ + uint8_t *buffer; + uint16_t tmp; + int cursor; + int x; + int y; + int i; + + /* Due to potential special char, we sould find the "real" starting + index for the internal buffer */ + terminal.cursor.x = 0; + terminal.cursor.y = 0; + i = terminal.buffer.cursor - 1; + buffer = &terminal.buffer.data[0]; + while (1) { + /* decrease the cursor and avoid circular effect */ + if (--i < 0) + i = terminal.buffer.size - 1; + + /* check loop condition */ + if (i == (int)terminal.buffer.cursor) + break; + + /* check EOL */ + if (buffer[i] == '\0') { + break; + } + + /* handle the character (only to force update cursors) */ + if (terminal_line_discipline(buffer[i] & 0x7f) == 0) + terminal_horizontal_update(); + if (terminal.cursor.y >= terminal.winsize.ws_row) + break; + } + + /* Display character per character because we need to check special + behaviour (like cariege return, line feed, ...) */ + terminal.cursor.x = 0; + terminal.cursor.y = 0; + while (1) { + /* update the index */ + if (++i >= (int)terminal.buffer.size) + i = 0; + if (i == (int)terminal.buffer.cursor) + break; + + /* get the cursor and remove the potential cursor marker */ + cursor = ((buffer[i] & 0x80) != 0); + buffer[i] &= 0x7f; + + /* display part (character + cursor if needed) */ + x = terminal.cursor.x * terminal.winsize.ft_xpixel; + y = terminal.cursor.y * terminal.winsize.ft_ypixel; + if (terminal_line_discipline(buffer[i]) == 0) { + tmp = buffer[i] << 8; + dtext(x, y, terminal.private.color.fg, (void*)&tmp); + terminal_horizontal_update(); + } + if (cursor != 0) { + dline(x, + y + terminal.winsize.ft_ypixel, + x + terminal.winsize.ft_xpixel - 2, + y + terminal.winsize.ft_ypixel, + terminal.private.color.fg); + } + } +} diff --git a/src/terminal/write.c b/src/terminal/write.c new file mode 100644 index 0000000..6cb8f9b --- /dev/null +++ b/src/terminal/write.c @@ -0,0 +1,29 @@ +#include "vxBoot/terminal.h" + +#include + +#include +#include +#include + +/* terminal_write() - printf wrapper for the terminal device */ +int terminal_write(const char *format, ...) +{ + char buffer[1024]; + va_list ap; + int nb; + + /* process the format */ + va_start(ap, format); + nb = vsnprintf(buffer, 1024, format, ap); + va_end(ap); + + /* update the internal buffer */ + terminal_buffer_insert(buffer, nb); + + /* display the internal buffer */ + dclear(terminal.private.color.bg); + terminal_buffer_display(); + dupdate(); + return (nb); +}