use Gint + add terminal device

This commit is contained in:
Yatis 2021-01-10 13:48:14 +01:00
commit b50a84e47b
15 changed files with 1105 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.idea
build*
*.g1a
*.g3a

208
Makefile Normal file
View File

@ -0,0 +1,208 @@
#! /usr/bin/make -f
# Default Makefile for fxSDK add-ins. This file was probably copied there by
# the [fxsdk] program.
#---
#
# Configuration
#
include project.cfg
# Compiler flags
CFLAGSFX = $(CFLAGS) $(CFLAGS_FX) $(INCLUDE_FX)
CFLAGSCG = $(CFLAGS) $(CFLAGS_CG) $(INCLUDE_CG)
# Linker flags
LDFLAGSFX := $(LDFLAGS) $(LDFLAGS_FX)
LDFLAGSCG := $(LDFLAGS) $(LDFLAGS_CG)
# Dependency list generation flags
depflags = -MMD -MT $@ -MF $(@:.o=.d) -MP
# ELF to binary flags
BINFLAGS := -R .bss -R .gint_bss
# G1A and G3A generation flags
NAME_G1A ?= $(NAME)
NAME_G3A ?= $(NAME)
G1AF := -i "$(ICON_FX)" -n "$(NAME_G1A)" --internal="$(INTERNAL)"
G3AF := -n basic:"$(NAME_G3A)" -i uns:"$(ICON_CG_UNS)" -i sel:"$(ICON_CG_SEL)"
ifeq "$(TOOLCHAIN_FX)" ""
TOOLCHAIN_FX := sh3eb-elf
endif
ifeq "$(TOOLCHAIN_CG)" ""
TOOLCHAIN_CG := sh4eb-elf
endif
# fxconv flags
FXCONVFX := --fx --toolchain=$(TOOLCHAIN_FX)
FXCONVCG := --cg --toolchain=$(TOOLCHAIN_CG)
# Determine the compiler install and include path
GCC_BASE_FX := $(shell $(TOOLCHAIN_FX)-gcc --print-search-dirs | grep install | sed 's/install: //')
GCC_BASE_CG := $(shell $(TOOLCHAIN_CG)-gcc --print-search-dirs | grep install | sed 's/install: //')
GCC_INCLUDE_FX := $(GCC_BASE_FX)/include
GCC_INCLUDE_CG := $(GCC_BASE_CG)/include
#
# File listings
#
NULL :=
TARGET := $(subst $(NULL) $(NULL),-,$(NAME))
ifeq "$(TARGET_FX)" ""
TARGET_FX := $(TARGET).g1a
endif
ifeq "$(TARGET_CG)" ""
TARGET_CG := $(TARGET).g3a
endif
ELF_FX := build-fx/$(shell basename "$(TARGET_FX)" .g1a).elf
BIN_FX := $(ELF_FX:.elf=.bin)
ELF_CG := build-cg/$(shell basename "$(TARGET_CG)" .g3a).elf
BIN_CG := $(ELF_CG:.elf=.bin)
# Source files
src := $(wildcard src/*.[csS] \
src/*/*.[csS] \
src/*/*/*.[csS] \
src/*/*/*/*.[csS])
assets-fx := $(wildcard assets-fx/*/*)
assets-cg := $(wildcard assets-cg/*/*)
# Object files
obj-fx := $(src:%=build-fx/%.o) \
$(assets-fx:assets-fx/%=build-fx/assets/%.o)
obj-cg := $(src:%=build-cg/%.o) \
$(assets-cg:assets-cg/%=build-cg/assets/%.o)
# Additional dependencies
deps-fx := $(ICON_FX)
deps-cg := $(ICON_CG_UNS) $(ICON_CG_SEL)
# All targets
all :=
ifneq "$(wildcard build-fx)" ""
all += all-fx
endif
ifneq "$(wildcard build-cg)" ""
all += all-cg
endif
#
# Build rules
#
all: $(all)
all-fx: $(TARGET_FX)
all-cg: $(TARGET_CG)
$(TARGET_FX): $(obj-fx) $(deps-fx)
@ mkdir -p $(dir $@)
$(TOOLCHAIN_FX)-gcc -o $(ELF_FX) $(obj-fx) $(CFLAGSFX) $(LDFLAGSFX)
$(TOOLCHAIN_FX)-objcopy -O binary $(BINFLAGS) $(ELF_FX) $(BIN_FX)
fxg1a $(BIN_FX) -o $@ $(G1AF)
$(TARGET_CG): $(obj-cg) $(deps-cg)
@ mkdir -p $(dir $@)
$(TOOLCHAIN_CG)-gcc -o $(ELF_CG) $(obj-cg) $(CFLAGSCG) $(LDFLAGSCG)
$(TOOLCHAIN_CG)-objcopy -O binary $(BINFLAGS) $(ELF_CG) $(BIN_CG)
mkg3a $(G3AF) $(BIN_CG) $@
# C sources
build-fx/%.c.o: %.c
@ mkdir -p $(dir $@)
$(TOOLCHAIN_FX)-gcc -c $< -o $@ $(CFLAGSFX) $(depflags)
build-cg/%.c.o: %.c
@ mkdir -p $(dir $@)
$(TOOLCHAIN_CG)-gcc -c $< -o $@ $(CFLAGSCG) $(depflags)
# Assembler sources
build-fx/%.s.o: %.s
@ mkdir -p $(dir $@)
$(TOOLCHAIN_FX)-gcc -c $< -o $@
build-cg/%.s.o: %.s
@ mkdir -p $(dir $@)
$(TOOLCHAIN_CG)-gcc -c $< -o $@
# Preprocessed assembler sources
build-fx/%.S.o: %.S
@ mkdir -p $(dir $@)
$(TOOLCHAIN_FX)-gcc -c $< -o $@ $(INCLUDE_FX)
build-cg/%.S.o: %.S
@ mkdir -p $(dir $@)
$(TOOLCHAIN_CG)-gcc -c $< -o $@ $(INCLUDE_CG)
# Images
build-fx/assets/img/%.o: assets-fx/img/%
@ mkdir -p $(dir $@)
fxconv --bopti-image $< -o $@ $(FXCONVFX) name:img_$(basename $*) $(IMG.$*)
build-cg/assets/img/%.o: assets-cg/img/%
@ mkdir -p $(dir $@)
fxconv --bopti-image $< -o $@ $(FXCONVCG) name:img_$(basename $*) $(IMG.$*)
# Fonts
build-fx/assets/fonts/%.o: assets-fx/fonts/%
@ mkdir -p $(dir $@)
fxconv -f $< -o $@ $(FXCONVFX) name:font_$(basename $*) $(FONT.$*)
build-cg/assets/fonts/%.o: assets-cg/fonts/%
@ mkdir -p $(dir $@)
fxconv -f $< -o $@ $(FXCONVCG) name:font_$(basename $*) $(FONT.$*)
# Binaries
build-fx/assets/bin/%.o: assets-fx/bin/%
@ mkdir -p $(dir $@)
fxconv -b $< -o $@ $(FXCONVFX) name:bin_$(basename $*) $(BIN.$*)
build-cg/assets/bin/%.o: assets-cg/bin/%
@ mkdir -p $(dir $@)
fxconv -b $< -o $@ $(FXCONVCG) name:bin_$(basename $*) $(BIN.$*)
# Custom conversions
build-fx/assets/%.o: assets-fx/%
@ mkdir -p $(dir $@)
fxconv --custom $< -o $@ $(FXCONVFX) type:$(subst /,,$(dir $*)) name:$(subst /,_,$(basename $*))
build-cg/assets/%.o: assets-cg/%
@ mkdir -p $(dir $@)
fxconv --custom $< -o $@ $(FXCONVCG) type:$(subst /,,$(dir $*)) name:$(subst /,_,$(basename $*))
#
# Cleaning and utilities
#
# Dependency information
-include $(shell find build* -name *.d 2> /dev/null)
build-fx/%.d: ;
build-cg/%.d: ;
.PRECIOUS: build-fx build-cg build-fx/%.d build-cg/%.d %/
clean-fx:
@ rm -rf build-fx/
clean-cg:
@ rm -rf build-cg/
distclean-fx: clean-fx
@ rm -f $(TARGET_FX)
distclean-cg: clean-cg
@ rm -f $(TARGET_CG)
clean: clean-fx clean-cg
distclean: distclean-fx distclean-cg
install-fx: $(TARGET_FX)
p7 send -f $<
install-cg: $(TARGET_CG)
@ while [[ ! -h /dev/Prizm1 ]]; do sleep 0.25; done
@ while ! mount /dev/Prizm1; do sleep 0.25; done
@ rm -f /mnt/prizm/$<
@ cp $< /mnt/prizm
@ umount /dev/Prizm1
@- eject /dev/Prizm1
.PHONY: all all-fx all-cg clean distclean install-fx install-cg

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
assets-fx/icon-fx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

10
include/fxBoot/parser.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __FXBOOT_PARSER_H__
# define __FXBOOT_PARSER_H__
#include <stddef.h>
#include <stdint.h>
extern int parser_strtotab(int *argc, char ***argv, char const *str);
extern void parser_strtotab_quit(int *argc, char ***argv);
#endif /*__FXBOOT_PARSER_H__*/

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

@ -0,0 +1,79 @@
#ifndef __FXBOOT_TERMINAL_H__
# define __FXBOOT_TERMINAL_H__
#include <stddef.h>
#include <stdint.h>
#define TERM_PRIVATE_WATERMARK (0xdeadbeef)
#define TERM_RDBUFFER_NBLINE (32)
/* */
#ifdef FXCG50
#define FWIDTH 8
#define FHEIGHT 9
#endif
#ifdef FX9860G
#define FWIDTH 5
#define FHEIGHT 7
#endif
/* define offset type */
typedef unsigned int off_t;
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__*/

88
project.cfg Normal file
View File

@ -0,0 +1,88 @@
#---
# fxSDK project configuration file for fxBoot
#---
# Project name, should be at most 8 bytes long.
# (You can also specify NAME_G1A or NAME_G3A to override individually.)
NAME := fxBoot
# Internal name, should be '@' followed by at most 7 uppercase letters.
# WARNING: If this convention is not followed, the add-in might not appear in
# the main menu of the calculator!
INTERNAL := @FXBOOT
# Output file name. The default is to take <NAME>, replace spaces with dashes,
# and add .g1a (or .g3a). You can specify a different folder if you want.
TARGET_FX :=
TARGET_CG :=
# fx-9860G icon location
ICON_FX = assets-fx/icon-fx.png
# fx-CG 50 icon locations
ICON_CG_UNS = assets-cg/icon-cg-uns.png
ICON_CG_SEL = assets-cg/icon-cg-sel.png
#---
# Toolchain selection
#---
# Toolchain for fx9860g. Please see also CFLAGS_FX below.
TOOLCHAIN_FX := sh-elf
# Toolchain for fxcg50. Please see also CFLAGS_CG below.
TOOLCHAIN_CG := sh-elf
#---
# Compiler flags
#---
# Base compiler flags for the fxSDK, you usually want to keep these.
CFLAGS := -mb -ffreestanding -nostdlib -fstrict-volatile-bitfields
# Platform-specific compiler flags.
# <> If you are using sh3eb-elf, use -m3. (You can do this on both FX and CG.)
# <> If you are using sh4eb-elf, use -m4-nofpu. (Not ideal on FX but works.)
# <> If you are using sh4eb-nofpu-elf, then your compiler will likely use the
# FPU and cause problems on the calculator. Consider another configuration.
# <> If you are using an sh-elf with several targets, specify whichever you
# support. I recommend -m3 on FX and -m4-nofpu on CG.
# Please see also TOOLCHAIN_FX and TOOLCHAIN_CG above.
CFLAGS_FX := -D FX9860G -m3
CFLAGS_CG := -D FXCG50 -m4-nofpu
# Additional compiler flags, change to your own taste!
CFLAGS += -Wall -Wextra -Wno-missing-field-initializers -Os
# Include paths. Add one -I option for each folder from which you want to
# be able to include files with #include<>. The Makefile provides a variable
# GCC_INCLUDE_FX/GCC_INCLUDE_CG that represents the default include folder,
# which is useful for some libraries such as OpenLibm.
INCLUDE_FX = -I include
INCLUDE_CG = -I include
# Libraries. Add one -l option for each library you are using, and also
# suitable -L options if you have library files in custom folders. To use
# fxlib, add libfx.a to the project directory and use "-L . -lfx".
LIBS_FX :=
LIBS_CG :=
# Base linker flags for the fxSDK, you usually want to keep these.
LDFLAGS_FX := -T fx9860g.ld -lgint-fx $(LIBS_FX) -lgint-fx -lgcc
LDFLAGS_CG := -T fxcg50.ld -lgint-cg $(LIBS_CG) -lgint-cg -lgcc
# Additional linker flags, if you need any.
LDFLAGS :=
# Additional platform-specific linker flags.
LDFLAGS_FX += -Wl,-Map=build-fx/map
LDFLAGS_CG += -Wl,-Map=build-cg/map
#---
# File conversion parameters
#---
# Here you can add fxconv options for each converted file, individually.
# The syntax is "<type>.<file>". For example, to specify the parameters for a
# font named "hexa.png", you might write:
#
# FONT.hexa.png = charset:print grid.size:3x5 grid.padding:1

66
src/main.c Normal file
View File

@ -0,0 +1,66 @@
#include "fxBoot/terminal.h"
#include "fxBoot/parser.h"
#include <gint/std/string.h>
#include <gint/keyboard.h>
#include <gint/display.h>
/* internal builtin list */
struct {
const char *name;
int (*f)(int argc, char **argv);
} cmd_list[] = {
{.name = "ls", NULL},
{.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);
}
int main(void)
{
int (*builtin)(int, char**);
const char *usrline;
char buff[128];
char **argv;
int argc;
int ret;
ret = 0;
terminal_open();
terminal_write("Welcome to fxBoot!\n");
while (1) {
/* get user command */
usrline = "/>";
if (ret != 0) {
usrline = "/[%d]>";
}
terminal_write(usrline, ret);
if (terminal_read(buff, 128) <= 1)
continue;
/* parse and try to find the command */
if (parser_strtotab(&argc, &argv, buff) != 0) {
terminal_write("error when processing \"%s\"", buff);
}
builtin = check_cmd(argv[0]);
if (builtin == NULL) {
terminal_write("command \"%s\" not found...\n", argv[0]);
continue;
}
/* execute the command and free'd allocated memories */
ret = builtin(argc, argv);
parser_strtotab_quit(&argc, &argv);
}
return (1);
}

141
src/parser.c Normal file
View File

@ -0,0 +1,141 @@
//---
// fxBoot:parser - Parser used to generate ARGC and ARGV
//---
#include "fxBoot/parser.h"
#include <gint/std/stdlib.h>
#include <gint/std/string.h>
/* define external symbols */
extern int parser_strtotab(int *argc, char ***argv, char const *str);
extern void 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(i + 1, 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(i + 1, 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);
}
/* parser_strtotab()
Generate word table and indicated the number of word find in the string. */
int 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(sizeof(char *) * (*argc + 1), 1);
if (*argv == NULL)
return (-3);
/* Dump all word. */
if (parser_entry(argv, str) != *argc) {
parser_strtotab_quit(argc, argv);
return (-4);
}
(*argv)[*argc] = NULL;
return (0);
}
/* parser_strtotab_quit(): Free all allocated memory generated by "strtotab()"*/
void 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;
}

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

@ -0,0 +1,22 @@
//---
// fxBoot:terminal:close - Close primitive for the terminal
//---
#include "fxBoot/terminal.h"
#include <gint/std/stdlib.h>
#include <gint/timer.h>
/* internal symbols */
extern struct terminal terminal;
/* 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);
}

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

@ -0,0 +1,45 @@
//---
// fxBoot:terminal:open - Open primitive for the terminal
//---
#include "fxBoot/terminal.h"
#include <gint/std/string.h>
#include <gint/std/stdlib.h>
#include <gint/display.h>
#include <gint/timer.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(terminal.buffer.size, 1);
if (terminal.buffer.data == NULL) {
terminal_close();
return (-1);
}
terminal.private.timer.id = timer_setup(TIMER_ANY, 250000,
(void*)&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);
}

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

@ -0,0 +1,246 @@
//---
// fxBoot:terminal:read - Read primitive for the terminal device
//---
#include "fxBoot/terminal.h"
#include <gint/std/string.h>
#include <gint/keyboard.h>
#include <gint/display.h>
#include <gint/timer.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);
}

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

@ -0,0 +1,166 @@
//---
// fxBoot:terminal:util - usefull function for handle the terminal device
//---
#include "fxBoot/terminal.h"
#include <gint/std/string.h>
#include <gint/display.h>
//---
// Update the internal 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);
}
}
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);
}
}
}

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

@ -0,0 +1,30 @@
//---
// fxBoot:terminal:write - Write primitive for terminal device
//---
#include "fxBoot/terminal.h"
#include <gint/std/stdio.h>
#include <gint/std/string.h>
#include <gint/display.h>
#include <stdarg.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);
}