summaryrefslogtreecommitdiff
path: root/terminal/vt52.c
blob: 919734775c3afbba0126e70607ba02660107ca4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// 
// 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;
}