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