diff options
| author | Michal Idziorek <m.i@gmx.at> | 2015-05-22 03:28:49 +0200 |
|---|---|---|
| committer | Michal Idziorek <m.i@gmx.at> | 2015-05-22 03:28:49 +0200 |
| commit | fceb15b1d325a7bb0bcab8993a1057cb991172e8 (patch) | |
| tree | ca95bf9b600d8687f2f6307628db4066e485119a /terminal | |
| parent | a6184be79e3918764d5e683796afbd8e8ccba018 (diff) | |
support for fg and bg color escape sequences
Diffstat (limited to 'terminal')
| -rw-r--r-- | terminal/terminal.c | 552 | ||||
| -rw-r--r-- | terminal/terminal.h | 72 | ||||
| -rw-r--r-- | terminal/vt52.c | 198 | ||||
| -rw-r--r-- | terminal/vt52.h | 63 |
4 files changed, 624 insertions, 261 deletions
diff --git a/terminal/terminal.c b/terminal/terminal.c new file mode 100644 index 0000000..4d3a1a0 --- /dev/null +++ b/terminal/terminal.c @@ -0,0 +1,552 @@ +// +// http://en.wikipedia.org/wiki/VT52 +// http://vt100.net/docs/vt520-rm/ +// man 4 console_codes +// + +#include "terminal.h" +#include "kernel/kmalloc.h" +#include "driver/screen.h" + +#define SET_LFNL true +#define SET_BUFF true +#define SET_ECHO true + + +typedef enum { + + ecma48_reset, + ecma48_bold, + ecma48_halfbright, + ecma48_underscore, + ecma48_blink, + ecma48_reverse_video, + ecma48_reset_mapping, + ecma48_null_mapping_1, + ecma48_null_mapping_2, + ecma48_normalbright_1, + ecma48_normalbright_2, + ecma48_nounderline, + ecma48_blinkoff, + ecma48_reverse_video_off, + + ecma48_fg_black =30, + ecma48_fg_red, + ecma48_fg_green, + ecma48_fg_brown, + ecma48_fg_blue, + ecma48_fg_magenta, + ecma48_fg_cyan, + ecma48_fg_white, + ecma48_undersore_on, // set def color + ecma48_undersore_off, // set def color + + ecma48_bg_black, + ecma48_bg_red, + ecma48_bg_green, + ecma48_bg_brown, + ecma48_bg_blue, + ecma48_bg_magenta, + ecma48_bg_cyan, + ecma48_bg_white, + + ecma48_bg_default =49, + +}terminal_settings; + + +// deprecated +#define VT52_WIDTH 75 +#define VT52_HEIGHT 24 + +#define VT52_ESC_1 0x1b //ESC + +#define VT52_UP 'A' +#define VT52_DOWN 'B' +#define VT52_RIGHT 'C' +#define VT52_LEFT 'D' +#define VT52_GRAPH_ON 'F' +#define VT52_GRAPH_OFF 'G' +#define VT52_HOME 'H' +#define VT52_REV_FEED 'I' +#define VT52_ERASE_SCR 'J' +#define VT52_ERASE_LINE 'K' +#define VT52_KEYPAD_ON '=' +#define VT52_KEYPAD_OFF '>' + +#define VT52_EXIT '<' + +#define VT52_ENTER_AUTOPRINT '^' +#define VT52_EXIT_AUTOPRINT '_' + +#define VT52_PRINT_LINE 'W' +#define VT52_ENTER_PRINT 'W' +#define VT52_EXIT_PRINT 'X' +#define VT52_PRINT ']' +#define VT52_JUMP 'Y' // followed by LINE COL (subtr -32 from val) +#define VT52_IDENTIFY 'Z' +#define VT52_IDENTIFY_TO_HOST "/Z" +// + +#define NPAR_START 1000 + +static uint32_t index(terminal_tty *tty, uint32_t x, uint32_t y) +{ + return tty->width*y+x; +} + +static void set_char(terminal_tty *tty, uint32_t x, uint32_t y, uint8_t c, uint8_t fg, uint8_t bg) +{ + tty->data[index(tty,x,y)]=c; + tty->data[index(tty,x,y)]|=fg<<8; + tty->data[index(tty,x,y)]|=bg<<16; + tty->screen->put_char(c,fg,bg,x,y); +} + +static void process_graphic_npar(terminal_tty *tty, terminal_settings s) +{ + switch(s) + { + case ecma48_fg_black: + tty->fg=SCR_BLACK; + break; + + case ecma48_fg_red: + tty->fg=SCR_RED; + break; + + case ecma48_fg_green: + tty->fg=SCR_GREEN; + break; + + case ecma48_fg_brown: + tty->fg=SCR_BROWN; + break; + + case ecma48_fg_blue: + tty->fg=SCR_BLUE; + break; + + case ecma48_fg_magenta: + tty->fg=SCR_MAGENTA; + break; + + case ecma48_fg_cyan: + tty->fg=SCR_CYAN; + break; + + case ecma48_fg_white: + tty->fg=SCR_WHITE; + break; + + + + case ecma48_bg_black: + tty->bg=SCR_BLACK; + break; + + case ecma48_bg_red: + tty->bg=SCR_RED; + break; + + case ecma48_bg_green: + tty->bg=SCR_GREEN; + break; + + case ecma48_bg_brown: + tty->bg=SCR_BROWN; + break; + + case ecma48_bg_blue: + tty->bg=SCR_BLUE; + break; + + case ecma48_bg_magenta: + tty->bg=SCR_MAGENTA; + break; + + case ecma48_bg_cyan: + tty->bg=SCR_CYAN; + break; + + case ecma48_bg_white: + tty->bg=SCR_WHITE; + break; + + + + + + + + case ecma48_bg_default: + tty->fg=SCR_BLACK; + break; + + } +} + + +static void process_graphic_npars(terminal_tty *tty) +{ + + char buf[4]; + int b=0; + + tty->escaping=0; + + for(int i=0;i<tty->npar+1;i++) + { + char c=tty->command[NPAR_START+i]; + buf[b++]=c; + + if(i==tty->npar||c==';') + { + if(b==2)process_graphic_npar(tty,buf[0]-'0'); + if(b==3)process_graphic_npar(tty,(buf[0]-'0')*10+(buf[1]-'0')); + b=0; + } + //terminal_put(tty,tty->command[NPAR_START+i]); + } + + tty->npar=0; + + + + +} + +static void reset(terminal_tty *tty) +{ + tty->bg=SCR_BLACK; + tty->fg=SCR_WHITE; + + for(int x=0;x<tty->width;x++) + for(int y=0;y<tty->height;y++) + { + set_char(tty,x,y,' ',tty->fg,tty->bg); + } + + tty->x=0; + tty->y=0; + tty->command_l=0; +} + +terminal_tty terminal_init(term_out *screen,term_in *input) +{ + terminal_tty tty; + + tty.data=kballoc(2); + + tty.command=kballoc(1); + tty.command_l=0; + + tty.escaping=0; + + tty.screen=screen; + tty.input=input; + + tty.x=0; + tty.y=0; + + tty.width=VT52_WIDTH; + tty.height=VT52_HEIGHT; + + reset(&tty); + + return tty; +} + + + +void terminal_kb(terminal_tty *tty, uint8_t c) +{ + + terminal_put(tty,c); + tty->command[tty->command_l]=c; + (tty->command_l)++; + + if(c==0x08) + { + tty->command_l-=2; + if(tty->command_l<0)tty->command_l=0; + } + else if(c=='\n') + { + // write command to ringbuff + for(int i=0;i<tty->command_l;i++) + tty->input->put_char(tty->command[i]); + + tty->command_l=0; + } + +} + +// send one ASCII character to the terminal +bool terminal_put(terminal_tty *tty, uint8_t c) +{ + + // CONTROL CHARACTERS + if(c==0x07){return;} // BEL + if(c==0x7F){return;} // nothing + + if(c==0x09){return;} // TAB TODO! + if(c==0x0E){return;} // G1 set + if(c==0x0F){return;} // G0 set + + if(c==0x18||c==0x1A){tty->escaping=0;return;} // cancel escaping + if(c==0x1B){tty->escaping=1;return;} // ESC + if(c==0x9B){tty->escaping=2;tty->npar=0;return;} // CSI = ESC [ + + if(c==0x08) //BACKSPACE + { + if(tty->x>0&&tty->command_l>0) + { + set_char(tty,tty->x-1,tty->y,' ',tty->fg,tty->bg); + tty->x--; + } + } + + else if(c==0x0D) // CR + { + tty->x=0; + return; + } + + else if(c==0x0A||c==0x0B||c==0x0C) // \n NEXTLINE + { + for(uint32_t x=tty->x;x<tty->width;x++) + { + set_char(tty,x,tty->y,' ',tty->fg,tty->bg); + } + tty->y++; + if(SET_LFNL)tty->x=0; + } + else // + { + // ESC- but not CSI-sequences + if(tty->escaping==1) + { + if(c=='c'){reset(tty);} // RESET + if(c=='D'){tty->y++;} // LINEFEED + if(c=='E'){tty->y++;tty->x=0;} //NEWLINE + if(c=='H'){} // SET TABSTOP: TODO + if(c=='M'){ // REVERSE LINEFEED + + if(tty->y==0) + { + for(int32_t y=tty->height-1;y>=0;y--) + { + for(uint32_t x=0;x<tty->width;x++) + { + uint32_t c=' '|tty->fg<<8|tty->bg<<16; + if(y!=0) c=tty->data[index(tty,x,y-1)]; + tty->data[index(tty,x,y)] = c; + + tty->screen->put_char(c&0xff,(c>>8)&0xff,c>>16,x,y); //TODO: get from buffer + } + } + } + else + tty->y--; + + } + + if(c=='Z'){// IDENTIFY: claim we are vt102 + + tty->input->put_char(0x1B); //ESC + tty->input->put_char('['); + tty->input->put_char('?'); + tty->input->put_char('6'); + tty->input->put_char('c'); + + return;} + + if(c=='7'){}// SAVE STATE + if(c=='8'){}// RESTORE STATE + if(c=='['){tty->escaping=2;tty->npar=0;return;} // CONTROL SEQ INTRODUCER + + + // TODO + // %, %@, %G, %8, #8, (, (B, (O, (U, (K + // ), >, =, ] (???) + // + // + + tty->escaping=0; // DONE + } + // CSI SEQEUENCES (AFTER ESC [..) + else if(tty->escaping==2) + { + //ECMA-48: TODO + //ECMA-48 GRAPHIC RENDITION: TODO + if(c!='m') + { + tty->command[NPAR_START+(tty->npar++)]=c; + } + else + { + process_graphic_npars(tty); + } + + //ECMA-48 MODE SWITCHES: TODO + //ECMA-48 STATUS REPORT: TODO + + //DEC PRIVATE MODE: TODO + //LINUX CONSOLE PRIVATE CSI: TODO + + } + else //PROBABLY (AND HOPEFULLY) JUST A NORMAL CHAR + { + set_char(tty,tty->x,tty->y,c,tty->fg,tty->bg); + tty->x++; + } + + } + + + + + + //autobreak + if(tty->x>=tty->width) + { + tty->x=0; + tty->y++; + } + + //autoscroll + if(tty->y>=tty->height) + { + tty->y--; + for(uint32_t y=0;y<tty->height;y++) + { + for(uint32_t x=0;x<tty->width;x++) + { + uint32_t c=tty->data[index(tty,x,y+1)]; + if(y==tty->height-1)c=' '|tty->fg<<8|tty->bg<<16; + tty->data[index(tty,x,y)] = c; + tty->screen->put_char(c&0xff,(c>>8)&0xff,c>>16,x,y); //TODO: get from buffer + } + } + } + + //cusor pos + tty->screen->update_cursor(tty->x,tty->y); + return true; +} + +//deprecated +/* +bool vt52_put(terminal_tty *tty, uint8_t c) +{ + if(c==VT52_ESC_1){tty->escaping=1;return;} + if(c=='['){if(tty->escaping==1)escaping=2;return;} + + if(escaping==3){tty->x=c-32; escaping++;return;} //TODO: check for overflow? + if(escaping==4){tty->y=c-32; escaping=0;return;} + + // does this really need to be escaped with ESC [ not JUST ESC?? TODO; check? + if(escaping==2) // two last characters are escape seq: ^[ + { + if(c==VT52_JUMP)escaping++; + + else + { + switch('c') + { + case VT52_UP: + if(tty->y>0)tty->y--; + break; + + case VT52_DOWN: + if(tty->y+1<tty->height)tty->y++; + break; + + case VT52_LEFT: + if(tty->x+1<tty->width)tty->x++; + break; + + case VT52_RIGHT: + if(tty->x>0)tty->x--; + break; + + case VT52_HOME: + tty->x=tty->y=0; + break; + + case VT52_REV_FEED: + + break; + + case VT52_ERASE_SCR: + for(uint32_t y=tty->y+1;y<tty->height;y++) + { + for(uint32_t x=0;x<tty->width;x++) + { + uint32_t c=tty->data[index(tty,x,y+1)]; + tty->data[index(tty,x,y)] = c; + tty->screen->put_char(c,0xf,x,y); + } + } + case VT52_ERASE_LINE: + + for(uint32_t x=tty->x;x<tty->width;x++) + { + uint32_t c=tty->data[index(tty,x,tty->y)]; + tty->data[index(tty,x,tty->y)] = c; + tty->screen->put_char(c,0xf,x,tty->y); + } + + break; + + } + + escaping=0; + } + + return; + + } + + if(c!='\n') + { + tty->data[index(tty,tty->x,tty->y)]=c; + tty->screen->put_char(c,0xf,tty->x,tty->y); + } + else + { + tty->y++; + tty->x=-1; + + } + + tty->x++; + + if(tty->x>=tty->width) + { + tty->x=0; + tty->y++; + + } + + //autoscroll + if(tty->y>=tty->height) + { + tty->y--; + for(uint32_t y=0;y<tty->height;y++) + { + for(uint32_t x=0;x<tty->width;x++) + { + uint32_t c=tty->data[index(tty,x,y+1)]; + if(y==tty->height-1)c=' '; + tty->data[index(tty,x,y)] = c; + tty->screen->put_char(c,0xf,x,y); + } + } + } + + tty->screen->update_cursor(tty->x,tty->y); + return true; +} +*/ diff --git a/terminal/terminal.h b/terminal/terminal.h new file mode 100644 index 0000000..e97a413 --- /dev/null +++ b/terminal/terminal.h @@ -0,0 +1,72 @@ +#ifndef TERMINAL_H +#define TERMINAL_H + +#include <stdint.h> +#include <stdbool.h> + + +// +// Terminal emulator implementing (a subset) of console codes of the +// linux console (see man 4 console_codes) +// +// 1. pass a term_out and term_in struct to terminal_init(..). +// 2. use the terminal_kb function for terminal/user input (eg. keyboard). +// 3. use the terminal_put function for input from the host/programms. +// +// +// +// _____________ +// terminal_put()----> | | ----> (term_out_struct) +// | TERMINAL | +// (term_in_struct)<---|___________| <---- terminal_kb() +// +// +// OTHER REQUIREMENTS +// +// Your also need to provide some memory allocation +// +// * uint32_t kballoc(uint32_t bloks); // block wise in-kernel allocation +// + +typedef struct term_out_struct +{ + + void (*put_char)(uint8_t c,uint8_t color_fg, uint8_t color_bg, uint32_t x, uint32_t y); + void (*update_cursor)(uint32_t col,uint32_t row); + +}term_out; + +typedef struct term_in_struct +{ + + void (*put_char)(uint8_t c); + +}term_in; + +typedef struct terminal_tty_struct +{ + uint8_t fg; + uint8_t bg; + + uint32_t width; + uint32_t height; + uint32_t x; + uint32_t y; + uint32_t *data; // screen data + uint8_t *command; // command line / also holds npar for escape sequences somewhere + int32_t command_l; // command line length + + uint8_t escaping; // escaping mode? + uint8_t npar; // npar pos + + term_out *screen; + term_in *input; + +}terminal_tty; + +terminal_tty terminal_init(term_out *screen,term_in *input); +bool terminal_put(terminal_tty *tty, uint8_t c); +void terminal_kb(terminal_tty *tty, uint8_t c); + + +#endif diff --git a/terminal/vt52.c b/terminal/vt52.c deleted file mode 100644 index 9197347..0000000 --- a/terminal/vt52.c +++ /dev/null @@ -1,198 +0,0 @@ -// -// http://en.wikipedia.org/wiki/VT52 -// http://vt100.net/docs/vt520-rm/ -// - -#include "vt52.h" -#include "kernel/kmalloc.h" - -#define VT52_WIDTH 75 -#define VT52_HEIGHT 24 - - -#define VT52_ESC_1 0x1b //ESC -#define VT52_ESC_2 0x5b //[ - -#define VT52_UP 'A' -#define VT52_DOWN 'B' -#define VT52_RIGHT 'C' -#define VT52_LEFT 'D' -#define VT52_GRAPH_ON 'F' -#define VT52_GRAPH_OFF 'G' -#define VT52_HOME 'H' -#define VT52_REV_FEED 'I' -#define VT52_ERASE_SCR 'J' -#define VT52_ERASE_LINE 'K' -#define VT52_KEYPAD_ON '=' -#define VT52_KEYPAD_OFF '>' - -#define VT52_EXIT '<' - -#define VT52_ENTER_AUTOPRINT '^' -#define VT52_EXIT_AUTOPRINT '_' - -#define VT52_PRINT_LINE 'W' -#define VT52_ENTER_PRINT 'W' -#define VT52_EXIT_PRINT 'X' -#define VT52_PRINT ']' -#define VT52_JUMP 'Y' // followed by LINE COL (subtr -32 from val) -#define VT52_IDENTIFY 'Z' -#define VT52_IDENTIFY_TO_HOST "/Z" - -static uint32_t index(vt52_tty *tty, uint32_t x, uint32_t y) -{ - return tty->width*y+x; -} - -static void clear(vt52_tty *tty) -{ - for(int x=0;x<tty->width;x++) - for(int y=0;y<tty->height;y++) - { - tty->data[index(tty,x,y)]=' '; - tty->screen->put_char(' ',0xf,x,y); - } -} - -vt52_tty vt52_init(term_out *screen,term_in *input) -{ - vt52_tty tty; - - tty.data=kballoc(1); - tty.screen=screen; - tty.input=input; - - tty.x=0; - tty.y=0; - - tty.width=VT52_WIDTH; - tty.height=VT52_HEIGHT; - - clear(&tty); - - return tty; -} - - -static void set_char(vt52_tty *tty, uint32_t x, uint32_t y, uint32_t c) -{ - tty->data[index(tty,x,y)]=c; -} - -static uint8_t escaping=0; - -void vt52_kb(vt52_tty *tty, uint8_t c) -{ - vt52_put(tty,c); - tty->input->put_char(c); -} -// send one ASCII character to the terminal -bool vt52_put(vt52_tty *tty, uint8_t c) -{ - if(c==VT52_ESC_1){escaping=1;return;} - if(c==VT52_ESC_2){if(escaping==1)escaping=2;return;} - - if(escaping==3){tty->x=c-32; escaping++;return;} //TODO: check for overflow? - if(escaping==4){tty->y=c-32; escaping=0;return;} - - if(escaping==2) // two last characters are escape seq: ^[ - { - if(c==VT52_JUMP)escaping++; - - else - { - switch('c') - { - case VT52_UP: - if(tty->y>0)tty->y--; - break; - - case VT52_DOWN: - if(tty->y+1<tty->height)tty->y++; - break; - - case VT52_LEFT: - if(tty->x+1<tty->width)tty->x++; - break; - - case VT52_RIGHT: - if(tty->x>0)tty->x--; - break; - - case VT52_HOME: - tty->x=tty->y=0; - break; - - case VT52_REV_FEED: - - break; - - case VT52_ERASE_SCR: - for(uint32_t y=tty->y+1;y<tty->height;y++) - { - for(uint32_t x=0;x<tty->width;x++) - { - uint32_t c=tty->data[index(tty,x,y+1)]; - tty->data[index(tty,x,y)] = c; - tty->screen->put_char(c,0xf,x,y); - } - } - case VT52_ERASE_LINE: - - for(uint32_t x=tty->x;x<tty->width;x++) - { - uint32_t c=tty->data[index(tty,x,tty->y)]; - tty->data[index(tty,x,tty->y)] = c; - tty->screen->put_char(c,0xf,x,tty->y); - } - - break; - - } - - escaping=0; - } - - return; - - } - - if(c!='\n') - { - tty->data[index(tty,tty->x,tty->y)]=c; - tty->screen->put_char(c,0xf,tty->x,tty->y); - } - else - { - tty->y++; - tty->x=-1; - } - - tty->x++; - - if(tty->x>=tty->width) - { - tty->x=0; - tty->y++; - } - - //autoscroll - if(tty->y>=tty->height) - { - tty->y--; - for(uint32_t y=0;y<tty->height;y++) - { - for(uint32_t x=0;x<tty->width;x++) - { - uint32_t c=tty->data[index(tty,x,y+1)]; - if(y==tty->height-1)c=' '; - tty->data[index(tty,x,y)] = c; - tty->screen->put_char(c,0xf,x,y); - } - } - } - - tty->screen->update_cursor(tty->x,tty->y); - return true; -} - diff --git a/terminal/vt52.h b/terminal/vt52.h deleted file mode 100644 index 9258cec..0000000 --- a/terminal/vt52.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef VT52_H -#define VT52_H - -#include <stdint.h> -#include <stdbool.h> - - -// -// Emulator of a vt52 terminal -// -// 1. pass a term_out and term_in struct to vt52_init(..). -// 2. use the vt52_kb function for terminal/user input (eg. keyboard). -// 3. use the vt52_put function for input from the host/programms. -// -// -// -// ________ -// vt52_put() ------> | | ----> (term_out_struct) -// | VT52 | -// (term_in_struct)<-- |_______| <---- vt52_kb() -// -// -// OTHER REQUIREMENTS -// -// Your also need to provide some memory allocation -// -// * uint32_t kballoc(uint32_t bloks); // block wise in-kernel allocation -// - -typedef struct term_out_struct -{ - - void (*put_char)(uint8_t c,uint8_t color, uint32_t x, uint32_t y); - void (*update_cursor)(uint32_t col,uint32_t row); - -}term_out; - -typedef struct term_in_struct -{ - - void (*put_char)(uint8_t c); - -}term_in; - -typedef struct vt52_tty_struct -{ - - uint32_t width; - uint32_t height; - uint32_t x; - uint32_t y; - uint32_t *data; // screen data - - term_out *screen; - term_in *input; - -}vt52_tty; - -vt52_tty vt52_init(term_out *screen,term_in *input); -bool vt52_put(vt52_tty *tty, uint8_t c); -void vt52_kb(vt52_tty *tty, uint8_t c); - -#endif |
