#include #include #include /* * 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; }