libc/newlib/libc/sys/sh3eb/console.c

279 lines
7.5 KiB
C

#include <sys/console.h>
#include <sys/keybios.h>
#include <sys/casio_syscalls.h>
/*
* Console instance for printf etc.
*/
_console _console_ctx = {
.cursor_x = 0,
.cursor_y = 0,
.buf_strlen = 0,
.buf = {0},
};
/*
* GetKeyWait provides a row from 2 (bottom) to 10 (top).
* The only exception is the AC key with a row of 1.
* This macro maps the row to 0 (top) to 8 (bottom)
* and 0 (AC)
*/
#define _CONSOLE_CONV_ROW(row) (!!(row - _CASIO_ROW_AC) * (_CASIO_ROW_MAX - row))
/*
* GetKeyWait provides a column from 2 (right) to 10 (left).
* The only exception is the AC key with a column of 1.
* This macro maps the column to 0 (left) to 8 (right)
* and 0 (AC)
*/
#define _CONSOLE_CONV_COL(col) (!!(col - _CASIO_COL_AC) * (_CASIO_COL_MAX - col))
#define _CONSOLE_MAX_ROW (_CASIO_ROW_MAX - _CASIO_ROW_MIN + 1)
#define _CONSOLE_MAX_COL (_CASIO_COL_MAX - _CASIO_COL_MIN + 1)
#define _CONSOLE_MODES 3
#define _CONSOLE_MODE_NORMAL 0
#define _CONSOLE_MODE_SHIFT 1
#define _CONSOLE_MODE_ALPHA 2
static const char row_col_to_ascii[_CONSOLE_MODES][_CONSOLE_MAX_ROW][_CONSOLE_MAX_COL] =
{
//row_col_to_ascii[_CONSOLE_MAX_MODE_NORMAL]
{
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, '(', ')', ',', 0},
{'7', '8', '9', '\b', 0, 0},
{'4', '5', '6', '\x9E', '\xF6', 0},
{'1', '2', '3', '+', '-', 0},
{'0', '.', 0, ' ', '\n', 0}
},
//row_col_to_ascii[_CONSOLE_MAX_MODE_SHIFT]
{
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 'e', 0, 0, 0},
{0, 0, 0, 'x', 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, '{', '}', 0},
{0, 0, 0, '[', ']', 0},
{'i', '=', 0, 0, '\n', 0},
},
//row_col_to_ascii[_CONSOLE_MAX_MODE_ALPHA]
{
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 'r', 0, 0, 0},
{'A', 'B', 'C', 'D', 'E', 'F'},
{'G', 'H', 'I', 'J', 'K', 'L'},
{'M', 'N', 'O', '\b', 0, 0},
{'P', 'Q', 'R', 'S', 'T', 0},
{'U', 'V', 'W', 'X', 'Y', 0},
{'Z', ' ', '"', 0, 0, 0},
},
};
/*
*
*/
int _console_read(_console *ctx, int file, char *ptr, int len) {
char mode = _CONSOLE_MODE_NORMAL;
int col, row;
int i = 0;
while (i < len) {
GetKeyWait(&col, &row, 0, 0, 0, 0);
if (col == _CASIO_COL_SHIFT && row == _CASIO_ROW_SHIFT) {
mode = _CONSOLE_MODE_SHIFT;
continue;
}
if (col == _CASIO_COL_ALPHA && row == _CASIO_ROW_ALPHA) {
mode = _CONSOLE_MODE_ALPHA;
continue;
}
// append char to string
ptr[i] = row_col_to_ascii[mode][_CONSOLE_CONV_ROW(row)][_CONSOLE_CONV_COL(col)];
// if the read character was a LF, stop
if (ptr[i] == '\n') {
return i + 1;
}
// print character to stdout
_console_write(&_console_ctx, 1, ptr+i, 1);
_console_flush(&_console_ctx);
Bdisp_PutDisp_DD();
// reset mode
mode = _CONSOLE_MODE_NORMAL;
// increment i if the current char was not '\0' only
i += !!ptr[i];
}
return i;
}
/*
* Sets the internal cursor position on the console.
* Note that the Casio cursor position will not be set until
* the console is flushed (automatically or manually).
*/
void _console_set_cursor(_console *ctx, unsigned char x, unsigned char y) {
/*
* No need to flush here, because the buffer already was flushed
* at the end of the _console_write() function.
*/
if (x < _CONSOLE_WIDTH && y < _CONSOLE_HEIGHT) {
ctx->cursor_x = x;
ctx->cursor_y = y;
}
}
/*
* Writes the (potentially but not necessarily null-terminated)
* string *ptr to the internal buffer. May flush and invoke
* the Casio "locate" and "Print" syscalls.
*/
int _console_write (_console *ctx, int file, char *ptr, int len)
{
/*
* Start parsing
*/
while (len-- && *ptr) {
/*
* Filter out all control characters
*/
switch (*ptr) {
case '\a':
// ignore
ptr++;
continue;
case '\b':
// undo last char (if not first char in line)
// no wrapping
ctx->cursor_x -= !!ctx->cursor_x;
ctx->buf_strlen -= !!ctx->buf_strlen;
ctx->buf[ctx->buf_strlen] = '\0';
ptr++;
continue;
case '\f':
case '\v':
_console_flush(ctx);
ctx->cursor_y = (ctx->cursor_y + 1) % _CONSOLE_HEIGHT;
ptr++;
continue;
case '\n':
_console_flush(ctx);
ctx->cursor_x = 0;
ctx->cursor_y = (ctx->cursor_y + (ctx->cursor_x < _CONSOLE_WIDTH)) % _CONSOLE_HEIGHT;
ptr++;
continue;
case '\r':
_console_flush(ctx);
ctx->cursor_x = 0;
ptr++;
continue;
case '\t':
;
/*
* Go to next tab stop (or to the end of the line).
*/
/*
* Somehow the following statement (see int s) cannot be written directly inside
* the condition of the for loop (or the program will act strangely).
* Possibly due to signedness? TODO
*/
int s = _CONSOLE_TAB_LEN - (ctx->cursor_x % _CONSOLE_TAB_LEN);
for (int i = 0; i < s; i++) {
_console_write(ctx, file, " ", 1);
}
ptr++;
continue;
}
// Add char to the buffer (flushes before it overflows)
_console_putc(ctx, *ptr);
// Flush buffer if there is a line wrap
if (ctx->cursor_x == _CONSOLE_WIDTH - 1) {
/*
* Temporarily increment cursor_x (without wrapping)
* because _console_flush expects the cursor to point
* to the position of the next char.
*/
ctx->cursor_x++;
_console_flush(ctx);
ctx->cursor_x--;
}
// Move curser to the left (wrap if bounds are exceeded)
ctx->cursor_x = (ctx->cursor_x + 1) % _CONSOLE_WIDTH;
// Move curser down if (ctx->cursor_x == 0) (wrap if bounds are exceeded)
ctx->cursor_y = (ctx->cursor_y + !ctx->cursor_x) % _CONSOLE_HEIGHT;
ptr++;
}
// Always flush in the end
_console_flush(ctx);
return len;
}
/*
* Adds a character to the internal buffer.
* Does not take care of the cursor position.
* May invoke _console_flush() to print the contents of the internal buffer.
* Use _console_flush() to manually flush the contents to the console output.
* Does not change the position of the internal cursor.
*/
void _console_putc(_console *ctx, char c) {
if (ctx->buf_strlen == _CONSOLE_BUF_WIDTH - 1) {
_console_flush(ctx);
}
ctx->buf[ctx->buf_strlen++] = c;
ctx->buf[ctx->buf_strlen] = '\0';
}
/*
* Prints the buffer out to the console and invokes
* the Casio "locate" and "Print" syscalls.
* Resets the internal buffer to "".
* Does not change the position of the internal cursor.
*/
void _console_flush(_console *ctx) {
/*
* Local syscall to Casio's locate
* because Casio's syscall is overwritten by _casio_set_cursor()
*/
typedef void (*console_locate_type)(int, int);
static const unsigned int console_locate_address[] = { _CASIO_SYSCALLS_SCA, _CASIO_SYSCALLS_SCB,_CASIO_SYSCALLS_SCE, 0x807 };
static const console_locate_type console_locate_ptr = (console_locate_type) console_locate_address;
if (!ctx->buf_strlen) {
return;
}
// +1 because the CASIO cursor position is 1-based
console_locate_ptr(ctx->cursor_x - ctx->buf_strlen + 1, ctx->cursor_y + 1);
Print((unsigned char*) ctx->buf);
ctx->buf[0] = '\0';
ctx->buf_strlen = 0;
}