#include #include /* * Console instance for printf etc. */ _console _console_ctx = { .cursor_x = 0, .cursor_y = 0, .buf_strlen = 0, .buf = {0}, }; /* * 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; }