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
This commit is contained in:
Yann MAGNIN 2021-09-25 16:02:50 +02:00
commit 7993f4b88f
20 changed files with 1233 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@ -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

46
CMakeLists.txt Normal file
View File

@ -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()

BIN
assets-cg/icon-sel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
assets-cg/icon-uns.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
assets-fx/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

11
include/vxBoot/builtin.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef __VXBOOT_BUILTIN_H__
# define __VXBOOT_BUILTIN_H__
#include <stddef.h>
#include <stdint.h>
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__*/

10
include/vxBoot/cli.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __VXBOOT_PARSER_H__
# define __VXBOOT_PARSER_H__
#include <stddef.h>
#include <stdint.h>
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__*/

View File

@ -0,0 +1,52 @@
#ifndef __VXBOOT_FS_SMEMFS_H__
# define __VXBOOT_FS_SMEMFS_H__
#include <stddef.h>
#include <stdint.h>
#include <gint/defs/types.h>
//----
// 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__*/

79
include/vxBoot/terminal.h Normal file
View File

@ -0,0 +1,79 @@
#ifndef __VXBOOT_TERMINAL_H__
# define __VXBOOT_TERMINAL_H__
#include <stddef.h>
#include <stdint.h>
#include <gint/defs/types.h>
/* 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__*/

21
src/builtin/help.c Normal file
View File

@ -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);
}

78
src/builtin/ls.c Normal file
View File

@ -0,0 +1,78 @@
#include "vxBoot/builtin.h"
#include "vxBoot/terminal.h"
#include "vxBoot/fs/smemfs.h"
#include <gint/bfile.h>
#include <string.h>
/* 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);
}

140
src/cli/parser.c Normal file
View File

@ -0,0 +1,140 @@
#include "vxBoot/cli.h"
#include <stdlib.h>
#include <string.h>
/* 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;
}

117
src/fs/smemfs/mount.c Normal file
View File

@ -0,0 +1,117 @@
#include "vxBoot/fs/smemfs.h"
#include "vxBoot/terminal.h"
#include <gint/bfile.h>
#include <gint/gint.h>
#include <gint/defs/call.h>
#include <string.h>
#include <stdlib.h>
/* 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);
}

77
src/fs/smemfs/pread.c Normal file
View File

@ -0,0 +1,77 @@
#include "vxBoot/fs/smemfs.h"
#include <gint/bfile.h>
#include <gint/gint.h>
#include <string.h>
/* 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);
}

81
src/main.c Normal file
View File

@ -0,0 +1,81 @@
#include "vxBoot/terminal.h"
#include "vxBoot/cli.h"
#include "vxBoot/builtin.h"
#include "vxBoot/fs/smemfs.h"
#include <gint/keyboard.h>
#include <gint/display.h>
#include <string.h>
//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);
}

18
src/terminal/close.c Normal file
View File

@ -0,0 +1,18 @@
#include "vxBoot/terminal.h"
#include <gint/timer.h>
#include <stdlib.h>
/* 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);
}

47
src/terminal/open.c Normal file
View File

@ -0,0 +1,47 @@
#include "vxBoot/terminal.h"
#include <gint/display.h>
#include <gint/timer.h>
#include <string.h>
#include <stdlib.h>
/* 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);
}

245
src/terminal/read.c Normal file
View File

@ -0,0 +1,245 @@
#include "vxBoot/terminal.h"
#include <gint/keyboard.h>
#include <gint/display.h>
#include <gint/timer.h>
#include <string.h>
/* 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);
}

168
src/terminal/util.c Normal file
View File

@ -0,0 +1,168 @@
#include "vxBoot/terminal.h"
#include <gint/display.h>
#include <string.h>
//---
// 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);
}
}
}

29
src/terminal/write.c Normal file
View File

@ -0,0 +1,29 @@
#include "vxBoot/terminal.h"
#include <gint/display.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
/* 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);
}