// // http://en.wikipedia.org/wiki/VT52 // http://vt100.net/docs/vt520-rm/ // #include "vt52.h" #include "kernel/kmalloc.h" #define VT52_WIDTH 80 #define VT52_HEIGHT 25 #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;xwidth;x++) for(int y=0;yheight;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+1height)tty->y++; break; case VT52_LEFT: if(tty->x+1width)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;yheight;y++) { for(uint32_t x=0;xwidth-1;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;xwidth-1;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=0; } 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;yheight;y++) { for(uint32_t x=0;xwidth-1;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); } } } tty->screen->update_cursor(tty->x,tty->y); return true; }