255 lines
6.1 KiB
C
255 lines
6.1 KiB
C
/**
|
|
* @file kernel/misc/fbterm.c
|
|
* @brief Crude framebuffer terminal for 32bpp framebuffer devices.
|
|
* @author K. Lange
|
|
*
|
|
* Provides a simple graphical text renderer for early startup, with
|
|
* support for simple escape sequences, on top of a framebuffer set up
|
|
* with the `lfbvideo` module.
|
|
*/
|
|
#include <kernel/printf.h>
|
|
#include <kernel/string.h>
|
|
#include <kernel/args.h>
|
|
|
|
/* Exported cell sizing */
|
|
size_t fbterm_width = 0;
|
|
size_t fbterm_height = 0;
|
|
|
|
/* Whether to scroll or wrap when cursor reaches the bottom. */
|
|
static int fbterm_scroll = 0;
|
|
|
|
/* Is this in a header somewhere? */
|
|
extern uint8_t * lfb_vid_memory;
|
|
extern uint16_t lfb_resolution_x;
|
|
extern uint16_t lfb_resolution_y;
|
|
extern uint16_t lfb_resolution_b;
|
|
extern uint32_t lfb_resolution_s;
|
|
extern size_t lfb_memsize;
|
|
|
|
/* Bitmap font details */
|
|
#include "../../apps/terminal-font.h"
|
|
#define char_height 20
|
|
#define char_width 9
|
|
|
|
/* Default colors */
|
|
#define BG_COLOR 0xFF050505 /* Background */
|
|
#define FG_COLOR 0xFFCCCCCC /* Main text color */
|
|
|
|
static uint32_t fg_color = FG_COLOR;
|
|
static uint32_t bg_color = BG_COLOR;
|
|
|
|
extern uint32_t lfb_resolution_s;
|
|
|
|
static void set_point(int x, int y, uint32_t value) {
|
|
((uint32_t*)lfb_vid_memory)[y * (lfb_resolution_s/4) + x] = value;
|
|
}
|
|
|
|
static void write_char(int x, int y, int val, uint32_t color) {
|
|
if (val > 128) {
|
|
val = 4;
|
|
}
|
|
uint16_t * c = large_font[val];
|
|
for (uint8_t i = 0; i < char_height; ++i) {
|
|
for (uint8_t j = 0; j < char_width; ++j) {
|
|
if (c[i] & (1 << (15-j))) {
|
|
set_point(x+j,y+i,color);
|
|
} else {
|
|
set_point(x+j,y+i,bg_color);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* We push text in one pixel, which unfortunately means we have slightly less room,
|
|
* but it also means the text doesn't run right into the left and right edges which
|
|
* just looks kinda bad. */
|
|
#define LEFT_PAD 1
|
|
static int x = LEFT_PAD;
|
|
static int y = 0;
|
|
|
|
/**
|
|
* @brief Basic 16-color ANSI palette with Tango colors.
|
|
*/
|
|
static uint32_t term_colors[] = {
|
|
0xFF000000,
|
|
0xFFCC0000,
|
|
0xFF4E9A06,
|
|
0xFFC4A000,
|
|
0xFF3465A4,
|
|
0xFF75507B,
|
|
0xFF06989A,
|
|
0xFFD3D7CF,
|
|
|
|
0xFF555753,
|
|
0xFFEF2929,
|
|
0xFF8AE234,
|
|
0xFFFCE94F,
|
|
0xFF729FCF,
|
|
0xFFAD7FA8,
|
|
0xFF34E2E2,
|
|
0xFFEEEEEC,
|
|
};
|
|
|
|
static int term_state = 0;
|
|
static char term_buf[1024] = {0};
|
|
static int term_buf_c = 0;
|
|
|
|
static void invert_at(int x, int y) {
|
|
for (uint8_t i = 0; i < char_height; ++i) {
|
|
for (uint8_t j = 0; j < char_width; ++j) {
|
|
uint32_t current = ((uint32_t*)lfb_vid_memory)[(y+i) * lfb_resolution_x + (x+j)];
|
|
uint8_t r = (current >> 16) & 0xFF;
|
|
uint8_t g = (current >> 8) & 0xFF;
|
|
uint8_t b = (current) & 0xFF;
|
|
current = 0xFF000000 | ((0xFF-r) << 16) | ((0xFF-g) << 8) | ((0xFF-b));
|
|
((uint32_t*)lfb_vid_memory)[(y+i) * lfb_resolution_x + (x+j)] = current;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void process_char(char ch) {
|
|
if (term_state == 1) {
|
|
if (ch == '[') {
|
|
term_buf_c = 0;
|
|
term_buf[term_buf_c] = '\0';
|
|
term_state = 2;
|
|
} else {
|
|
term_state = 0;
|
|
process_char(ch);
|
|
}
|
|
return;
|
|
} else if (term_state == 2) {
|
|
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
|
|
/* do the thing */
|
|
switch (ch) {
|
|
case 'm': {
|
|
char * arg = &term_buf[0];
|
|
char * next;
|
|
int argC = 0;
|
|
int isBold = 0;
|
|
do {
|
|
next = strchr(arg, ';');
|
|
if (next) { *next = '\0'; next++; }
|
|
int asInt = atoi(arg);
|
|
if (asInt == 0) {
|
|
fg_color = FG_COLOR;
|
|
bg_color = BG_COLOR;
|
|
isBold = 0;
|
|
} else if (asInt == 1) {
|
|
isBold = 1;
|
|
} else if (asInt == 22) {
|
|
fg_color = FG_COLOR;
|
|
isBold = 0;
|
|
} else if (asInt >= 30 && asInt <= 37) {
|
|
fg_color = term_colors[asInt-30 + (isBold ? 8 : 0)];
|
|
} else if (asInt >= 90 && asInt <= 97) {
|
|
fg_color = term_colors[asInt-90 + 8];
|
|
} else if (asInt >= 40 && asInt <= 47) {
|
|
bg_color = term_colors[asInt-40 + (isBold ? 8 : 0)];
|
|
} else if (asInt >= 100 && asInt <= 107) {
|
|
bg_color = term_colors[asInt-100 + 8];
|
|
} else if (asInt == 38) {
|
|
fg_color = FG_COLOR;
|
|
} else if (asInt == 48) {
|
|
bg_color = BG_COLOR;
|
|
} else if (asInt == 7) {
|
|
uint32_t tmp = fg_color;
|
|
fg_color = bg_color;
|
|
bg_color = tmp;
|
|
}
|
|
arg = next;
|
|
argC++;
|
|
} while (arg);
|
|
break;
|
|
}
|
|
case 'G': {
|
|
/* Set cursor column */
|
|
invert_at(x,y);
|
|
x = LEFT_PAD + (atoi(term_buf) - 1) * char_width;
|
|
invert_at(x,y);
|
|
break;
|
|
}
|
|
case 'K': {
|
|
if (atoi(term_buf) == 0) {
|
|
for (int j = y; j < y + char_height; ++j) {
|
|
for (int i = x; i < lfb_resolution_x; ++i) {
|
|
set_point(i,j,bg_color);
|
|
}
|
|
}
|
|
invert_at(x,y);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
term_state = 0;
|
|
} else {
|
|
term_buf[term_buf_c++] = ch;
|
|
term_buf[term_buf_c] = '\0';
|
|
}
|
|
return;
|
|
} else if (ch == '\033') {
|
|
term_state = 1;
|
|
return;
|
|
}
|
|
|
|
write_char(x,y,' ',bg_color);
|
|
switch (ch) {
|
|
case '\n':
|
|
x = LEFT_PAD;
|
|
y += char_height;
|
|
break;
|
|
case '\r':
|
|
x = LEFT_PAD;
|
|
break;
|
|
case '\b':
|
|
if (x > LEFT_PAD) {
|
|
x -= char_width;
|
|
write_char(x,y,' ',fg_color);
|
|
}
|
|
break;
|
|
default:
|
|
if ((unsigned int)ch > 127) return;
|
|
write_char(x,y,ch,fg_color);
|
|
x += char_width;
|
|
break;
|
|
}
|
|
if (x > lfb_resolution_x) {
|
|
y += char_height;
|
|
x = LEFT_PAD;
|
|
}
|
|
if (y > lfb_resolution_y - char_height) {
|
|
if (fbterm_scroll) {
|
|
y -= char_height;
|
|
memmove(lfb_vid_memory, lfb_vid_memory + sizeof(uint32_t) * lfb_resolution_x * char_height, (lfb_resolution_y - char_height) * lfb_resolution_x * 4);
|
|
memset(lfb_vid_memory + sizeof(uint32_t) * (lfb_resolution_y - char_height) * lfb_resolution_x, 0x05, char_height * lfb_resolution_x * 4);
|
|
} else {
|
|
y = 0;
|
|
}
|
|
}
|
|
invert_at(x,y);
|
|
}
|
|
|
|
static size_t (*previous_writer)(size_t,uint8_t*) = NULL;
|
|
|
|
size_t fbterm_write(size_t size, uint8_t *buffer) {
|
|
if (!buffer) return 0;
|
|
for (unsigned int i = 0; i < size; ++i) {
|
|
process_char(buffer[i]);
|
|
}
|
|
if (previous_writer) previous_writer(size,buffer);
|
|
return size;
|
|
}
|
|
|
|
void fbterm_initialize(void) {
|
|
if (!lfb_resolution_x) return;
|
|
|
|
if (args_present("fbterm-scroll")) {
|
|
fbterm_scroll = 1;
|
|
}
|
|
|
|
fbterm_width = (lfb_resolution_x - LEFT_PAD) / char_width;
|
|
fbterm_height = (lfb_resolution_y) / char_height;
|
|
previous_writer = printf_output;
|
|
printf_output = fbterm_write;
|
|
}
|