The Pedigree Project 0.1
SerialIO.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/debugger/SerialIO.h"
22#include "pedigree/kernel/machine/Serial.h"
23#include "pedigree/kernel/utilities/StaticString.h"
24
26 : m_UpperCliLimit(0),
27 m_LowerCliLimit(0),
28 m_nWidth(80),
29 m_nHeight(25),
30 m_nCursorX(0),
31 m_nCursorY(0),
32 m_nOldCursorX(0),
33 m_nOldCursorY(0),
34 m_ForeColour(DebuggerIO::Red),
35 m_BackColour(DebuggerIO::Red),
36 m_pSerial(pSerial),
37 m_bCli(false) {
38 // initialise();
39}
40
41SerialIO::~SerialIO() {
42 destroy();
43}
44
45void SerialIO::initialise() {
46 // Save cursor and attributes.
47 // m_pSerial->write_str("\033[s");
48
49#if !SERIAL_IS_FILE
50 // Read cursor location.
51 readCursor();
52 m_nOldCursorX = m_nCursorX;
53 m_nOldCursorY = m_nCursorY;
54 NOTICE(Hex << "oldx: " << m_nOldCursorX << ", y: " << m_nOldCursorY);
55
56#endif
57
58 // Push screen contents.
59 m_pSerial->write_str("\033[?1049h");
60
61 // Move the cursor back to the top left.
62 // m_pSerial->write_str("\033[0;0H");
63
64 // Enable line wrapping.
65 m_pSerial->write_str("\033[7h");
66}
67
68void SerialIO::destroy() {
69 // Pop screen contents.
70 m_pSerial->write_str("\033[?1049l");
71
72 // Disable scrolling.
73 m_pSerial->write_str("\033[0;0r");
74
75 // Load cursor and attributes.
76 // m_pSerial->write_str("\033[u");
77
78 // Just reset the terminal.
79 // m_pSerial->write_str("\033c");
80
81 // Set the cursor
83 str += "\033[";
84 str += m_nOldCursorY;
85 str += ";";
86 str += m_nOldCursorX;
87 str += "H";
88 m_pSerial->write_str(str);
89}
90
91void SerialIO::setCliUpperLimit(size_t nlines) {
92 // Do a quick sanity check.
93 if (nlines < m_nHeight)
94 m_UpperCliLimit = nlines;
95}
96
97void SerialIO::setCliLowerLimit(size_t nlines) {
98 // Do a quick sanity check.
99 if (nlines < m_nHeight)
100 m_LowerCliLimit = nlines;
101}
102
104 // Clear the screen.
105 m_pSerial->write_str("\033[2J");
106
107 // Set the scrollable region.
108 TinyStaticString str("\033[");
109 str += (m_UpperCliLimit + 1);
110 str += ';';
111 str += m_nHeight - m_LowerCliLimit;
112 str += 'r';
113 m_pSerial->write_str(str);
114
115 // Set the cursor to just below the upper limit.
116 str = "\033[";
117 str += (m_UpperCliLimit + 1);
118 str += ";0H";
119 m_pSerial->write_str(str);
120 m_pCommand[0] = '\0';
121
122 m_bCli = true;
123}
124
125void SerialIO::disableCli() {
126 // Clear the screen.
127 m_pSerial->write_str("\033[2J");
128
129 // Disable scrolling.
130 m_pSerial->write_str("\033[0;0r");
131
132 // Reposition the cursor.
133 // m_pSerial->write_str("\033[0;0H");
134
135 m_bCli = false;
136}
137
139 char c = m_pSerial->read();
140 if (c == 0x7f) // We hardcode DEL -> BACKSPACE.
141 return 0x08;
142 if (c == '\033') {
143 // Agh! VT100 code!
144 ERROR("VT100 code!!");
145 // while ( c != 'R' )
146 // c = m_pSerial->read();
147 return 0;
148 }
149 return c;
150}
151
152void SerialIO::drawHorizontalLine(char c, size_t row, size_t colStart, size_t colEnd,
153 DebuggerIO::Colour foreColour, DebuggerIO::Colour backColour) {
154 saveCursor();
155
156 // colEnd must be bigger than colStart.
157 if (colStart > colEnd) {
158 size_t tmp = colStart;
159 colStart = colEnd;
160 colEnd = tmp;
161 }
162
163 if (colEnd >= m_nWidth)
164 colEnd = m_nWidth - 1;
165 if (static_cast<int32_t>(colStart) < 0)
166 colStart = 0;
167 if (row >= m_nHeight)
168 row = m_nHeight - 1;
169 if (static_cast<int32_t>(row) < 0)
170 row = 0;
171
172 startColour(foreColour, backColour);
173
174 // Here we can do clever stuff. If we're erasing to the start or the end of
175 // the line, and we're trying to clear it (c == ' ') vt100 has some nice
176 // codes that make our life easier and faster.
177 if (colEnd == m_nWidth - 1 && c == ' ') {
178 // Position the cursor at the specified column, row.
179 TinyStaticString cmd("\033[");
180 cmd += (row + 1);
181 cmd += ';';
182 cmd += (colStart + 1);
183 cmd += 'H';
184 m_pSerial->write_str(cmd);
185
186 // Erase to the end of line.
187 m_pSerial->write_str("\033[K");
188 } else if (colStart == 0 && c == ' ') {
189 // Position the cursor where the line is supposed to *end*.
190 TinyStaticString cmd("\033[");
191 cmd += (row + 1);
192 cmd += ';';
193 cmd += (colEnd + 1);
194 cmd += 'H';
195 m_pSerial->write_str(cmd);
196
197 // Erase backwards to the start of line.
198 m_pSerial->write_str("\033[1K");
199 } else {
200 // Position the cursor at the specified column, row.
201 TinyStaticString cmd("\033[");
202 cmd += (row + 1);
203 cmd += ';';
204 cmd += (colStart + 1);
205 cmd += 'H';
206 m_pSerial->write_str(cmd);
207
208 // Write each character seperately.
209 for (size_t i = colStart; i <= colEnd; i++) {
210 m_pSerial->write(c);
211 }
212 }
213
214 endColour();
215
216 unsaveCursor();
217}
218
219void SerialIO::drawVerticalLine(char c, size_t col, size_t rowStart, size_t rowEnd,
220 DebuggerIO::Colour foreColour, DebuggerIO::Colour backColour) {
221 // rowEnd must be bigger than rowStart.
222 if (rowStart > rowEnd) {
223 size_t tmp = rowStart;
224 rowStart = rowEnd;
225 rowEnd = tmp;
226 }
227
228 if (rowEnd >= m_nHeight)
229 rowEnd = m_nHeight - 1;
230 if (static_cast<int32_t>(rowStart) < 0)
231 rowStart = 0;
232 if (col >= m_nWidth)
233 col = m_nWidth - 1;
234 if (static_cast<int32_t>(col) < 0)
235 col = 0;
236
237 // TODO position cursor, draw line.
238}
239
240void SerialIO::drawString(const char* str, size_t row, size_t col, DebuggerIO::Colour foreColour,
241 DebuggerIO::Colour backColour) {
242 saveCursor();
243
244 // Position the cursor at the specified column, row.
245 TinyStaticString cmd("\033[");
246 cmd += (row + 1);
247 cmd += ';';
248 cmd += (col + 1);
249 cmd += 'H';
250 m_pSerial->write_str(cmd);
251
252 startColour(foreColour, backColour);
253
254 m_pSerial->write_str(str);
255 endColour();
256 unsaveCursor();
257}
258
262
263void SerialIO::disableRefreshes() {
264 m_bRefreshesEnabled = false;
265}
266
268
270
271void SerialIO::cls() {
272 // Clear the screen.
273 m_pSerial->write_str("\033[2J");
274}
275
276void SerialIO::putChar(char c, DebuggerIO::Colour foreColour, DebuggerIO::Colour backColour) {
277 startColour(foreColour, backColour);
278
279 if (c == 0x08) // Backspace - handle differently.
280 {
281 readCursor();
282 // Go back one space.
283 // Are we at the screen edge?
284 if (m_nCursorX == 1) {
285 m_nCursorX = m_nWidth - 1;
286 m_nCursorY--;
287 } else {
288 m_nCursorX--;
289 }
290 setCursor();
291 m_pSerial->write(' ');
292 setCursor();
293 } else {
296 // if (m_bCli) // If we're not in CLI mode we dont bother with the
297 // costly wrap-check.
298 // {
299 // readCursor();
300 // if (m_nCursorX == m_nWidth)
301 // m_pSerial->write_str("\n\r");
302 // }
303 if (c == '\n') // Newline - output a '\r' as well.
304 m_pSerial->write('\r');
305 m_pSerial->write(c);
306 }
307 endColour();
308}
309
310void SerialIO::forceRefresh() {}
311
312void SerialIO::startColour(DebuggerIO::Colour foreColour, DebuggerIO::Colour backColour) {
313 if (foreColour == m_ForeColour && backColour == m_BackColour)
314 return;
315
316 m_ForeColour = foreColour;
317 m_BackColour = backColour;
318
319 m_pSerial->write_str("\033[");
320 switch (foreColour) {
321 case DebuggerIO::Black:
322 m_pSerial->write_str("30");
323 break;
324 case DebuggerIO::Red:
325 m_pSerial->write_str("31");
326 break;
327 case DebuggerIO::Green:
328 m_pSerial->write_str("32");
329 break;
330 case DebuggerIO::Yellow:
331 m_pSerial->write_str("1;33");
332 break; // It's actually brown.
333 case DebuggerIO::Blue:
334 m_pSerial->write_str("34");
335 break;
336 case DebuggerIO::Magenta:
337 m_pSerial->write_str("35");
338 break;
339 case DebuggerIO::Cyan:
340 m_pSerial->write_str("36");
341 break;
342 case DebuggerIO::White:
343 m_pSerial->write_str("37");
344 break;
345 case DebuggerIO::DarkGrey:
346 m_pSerial->write_str("1;30");
347 break;
348 case DebuggerIO::LightRed:
349 m_pSerial->write_str("1;31");
350 break;
351 case DebuggerIO::LightGreen:
352 m_pSerial->write_str("1;32");
353 break;
354 case DebuggerIO::LightBlue:
355 m_pSerial->write_str("1;34");
356 break;
357 case DebuggerIO::LightMagenta:
358 m_pSerial->write_str("1;35");
359 break;
360 case DebuggerIO::LightCyan:
361 m_pSerial->write_str("1;36");
362 break;
363 default:
364 m_pSerial->write('1');
365 }
366 m_pSerial->write_str(";");
367 switch (backColour) {
368 case DebuggerIO::Black:
369 m_pSerial->write_str("40");
370 break;
371 case DebuggerIO::Red:
372 m_pSerial->write_str("41");
373 break;
374 case DebuggerIO::Green:
375 m_pSerial->write_str("42");
376 break;
377 case DebuggerIO::DarkGrey:
378 m_pSerial->write_str("43");
379 break; // It's actually brown.
380 case DebuggerIO::Blue:
381 m_pSerial->write_str("44");
382 break;
383 case DebuggerIO::Magenta:
384 m_pSerial->write_str("45");
385 break;
386 case DebuggerIO::Cyan:
387 m_pSerial->write_str("46");
388 break;
389 case DebuggerIO::White:
390 m_pSerial->write_str("47");
391 break;
392 default:
393 m_pSerial->write('1');
394 }
395 m_pSerial->write('m');
396}
397
398char SerialIO::getCharNonBlock() {
399 return m_pSerial->readNonBlock();
400}
401
402void SerialIO::endColour() {
403 m_pSerial->write_str("\033[0m");
404}
405
406void SerialIO::readCursor() {
407 // Ask the device wherethe cursor is.
408 m_pSerial->write_str("\033[6n");
409
410 // Expect a string of the form "\033[%d;%dR"
411 char c = m_pSerial->read();
412 if (c != '\033') {
413 ERROR("SerialIO - device responded incorrectly to size query.");
414 return;
415 }
416 if (m_pSerial->read() != '[') {
417 ERROR("SerialIO - device responded incorrectly to size query.");
418 return;
419 }
420
422 c = m_pSerial->read();
423 while (c >= '0' && c <= '9') {
424 str += c;
425 c = m_pSerial->read();
426 }
427
428 m_nCursorY = str.intValue();
429
430 if (c != ';') {
431 ERROR("SerialIO - device responded incorrectly to size query.");
432 return;
433 }
434
435 str = "";
436 c = m_pSerial->read();
437 while (c >= '0' && c <= '9') {
438 str += c;
439 c = m_pSerial->read();
440 }
441
442 m_nCursorX = str.intValue();
443 if (c != 'R') {
444 ERROR("SerialIO - device responded incorrectly to size query.");
445 return;
446 }
447}
448
449void SerialIO::setCursor() {
450 TinyStaticString str("\033[");
451 str += m_nCursorY;
452 str += ";";
453 str += m_nCursorX;
454 str += "H";
455 m_pSerial->write_str(str);
456}
457
458void SerialIO::saveCursor() {
459 // readCursor();
460 m_pSerial->write_str("\033[s");
461}
462
463void SerialIO::unsaveCursor() {
464 // setCursor();
465 m_pSerial->write_str("\033[u");
466}
467
468void SerialIO::readDimensions() {
469 // Read old cursor position
470 readCursor();
471#if SERIAL_IS_FILE
472 m_nOldCursorX = m_nCursorX;
473 m_nOldCursorY = m_nCursorY;
474#endif
475 // Move the cursor off the bottom right somewhere. The device will clamp to
476 // its available area.
477 m_nCursorY = 10000;
478 m_nCursorX = 10000;
479 setCursor();
480 readCursor();
482 m_nHeight = m_nCursorY;
483
484 // Move the cursor back to the top left.
485 m_pSerial->write_str("\033[0;0H");
486}
char m_pCommand[COMMAND_MAX]
Definition DebuggerIO.h:175
bool m_bRefreshesEnabled
Definition DebuggerIO.h:180
Serial * m_pSerial
Definition SerialIO.h:156
size_t m_UpperCliLimit
Definition SerialIO.h:131
SerialIO(Serial *pSerial)
Definition SerialIO.cc:25
void moveCursor()
Definition SerialIO.cc:269
void putChar(char c, DebuggerIO::Colour foreColour, DebuggerIO::Colour backColour)
Definition SerialIO.cc:276
char getChar()
Definition SerialIO.cc:138
void scroll()
Definition SerialIO.cc:267
void drawString(const char *str, size_t row, size_t col, DebuggerIO::Colour foreColour, DebuggerIO::Colour backColour)
Definition SerialIO.cc:240
void enableRefreshes()
Definition SerialIO.cc:259
size_t m_nCursorX
Definition SerialIO.h:145
void enableCli()
Definition SerialIO.cc:103
void drawHorizontalLine(char c, size_t row, size_t colStart, size_t colEnd, DebuggerIO::Colour foreColour, DebuggerIO::Colour backColour)
Definition SerialIO.cc:152
size_t m_nWidth
Definition SerialIO.h:139
void setCliUpperLimit(size_t nlines)
Definition SerialIO.cc:91
size_t m_LowerCliLimit
Definition SerialIO.h:133
@ Hex
Definition Log.h:142
Definition cmd.h:30