terminal.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. #include "terminal.h"
  2. #include <string.h>
  3. #include <stdarg.h>
  4. static char tmpCommand[40];
  5. //-----------------------------------------------------------------------------
  6. // Microrl callbacks
  7. //-----------------------------------------------------------------------------
  8. extern "C" {
  9. //Configure terminal
  10. void configure_terminal() {
  11. pTerminal->configure();
  12. }
  13. //Print micrrl callback
  14. void print_terminal(const char *str) {
  15. pTerminal->print(str);
  16. }
  17. //Execute microrl callback
  18. int execute_terminal(int argc, const char * const * argv) {
  19. return pTerminal->execute(argc, argv);}
  20. //Sigint microrl callback
  21. void sigint_terminal (void) {
  22. pTerminal->sigint();}
  23. //Complete microrl callback
  24. char** completion_terminal (int argc, const char * const * argv) {
  25. return pTerminal->completion(argc, argv);}
  26. }
  27. //-----------------------------------------------------------------------------
  28. // Terminal class
  29. //-----------------------------------------------------------------------------
  30. Terminal::Terminal():
  31. m_countPrintFunction(0),
  32. prl(&rl)
  33. {
  34. memset(&f_print, 0, sizeof(f_print));
  35. memset(tmpCommand, 0, sizeof(tmpCommand));
  36. }
  37. //Configure microrl callbacks
  38. void Terminal::configure()
  39. {
  40. m_countPrintFunction = 0;
  41. prl = &rl;
  42. memset(&f_print, 0, sizeof(f_print));
  43. memset(tmpCommand, 0, sizeof(tmpCommand));
  44. microrl_init (prl, ::print_terminal);
  45. microrl_set_execute_callback (prl, ::execute_terminal);
  46. microrl_set_sigint_callback (prl, ::sigint_terminal);
  47. microrl_set_complete_callback (prl, ::completion_terminal);
  48. }
  49. void Terminal::connectCallback() {
  50. printeol();
  51. printll("Hello stranger. It is goot day for work :)");
  52. }
  53. //Insert char to microrl
  54. void Terminal::insert(int ch) {
  55. microrl_insert_char(prl, ch);
  56. }
  57. //Out message to all terminals
  58. void Terminal::print(const char *str) {
  59. for (int i = 0; i < m_countPrintFunction; i++) {
  60. if (f_print[i] != 0) {
  61. f_print[i](str);
  62. }
  63. }
  64. }
  65. void Terminal::printl(const char * str) {
  66. print(str);
  67. print(EOL);
  68. }
  69. void Terminal::printll(const char * str) {
  70. print(str);
  71. print(EOL);
  72. print(EOL);
  73. }
  74. void Terminal::eol() {
  75. print(EOL);
  76. }
  77. void Terminal::printeol() {
  78. print(EOL);
  79. }
  80. //Execute microrl callbacks
  81. int Terminal::execute(int argc, const char * const *argv) {
  82. return 0;
  83. }
  84. char* helloNull[] = {0};
  85. //Comletion microrl callbacks
  86. char ** Terminal::completion(int argc, const char * const * argv) {
  87. int i = 0;
  88. i++;
  89. return helloNull;
  90. }
  91. //Sigint microrl callbacks
  92. void Terminal::sigint()
  93. {
  94. }
  95. //Add external print function
  96. void Terminal::addPrint(InterfacePrint print_func) {
  97. if (m_countPrintFunction < COUNT_TERMINAL_INTERFACE) {
  98. f_print[m_countPrintFunction] = print_func;
  99. m_countPrintFunction++;
  100. }
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Вывод команд в терминал
  104. //-----------------------------------------------------------------------------
  105. //Очистка экрана
  106. void Terminal::clearScreen() {
  107. //Clear
  108. print("\033[2J");
  109. //Move to up left corner
  110. print("\033[H");
  111. }
  112. //Сдвинуть в указанную позицию
  113. void Terminal::moveToPos(uint32_t h, uint32_t v)
  114. {
  115. uint32_t sizeCommand = 0;
  116. getCommand_MoveToPos(tmpCommand, sizeCommand, h, v);
  117. print(tmpCommand);
  118. }
  119. //Сдвинуть в верхний левый угол
  120. void Terminal::moveToUpLeftCorner() {
  121. //Move to up left corner
  122. print("\033[H");
  123. }
  124. //Reset terminal to initial state
  125. void Terminal::reset() {
  126. //Сбросить настройки терминала
  127. print("\033c");
  128. }
  129. //Сбросить аттрибуты текста
  130. void Terminal::resetAttribute() {
  131. print("\033[0m");
  132. }
  133. //Сохранить позицию курсора и атрибуты
  134. void Terminal::saveCursorPos() {
  135. //Save cursor position and attributes
  136. print("\0337");
  137. }
  138. //Востановить позицию курсора и аттрибуты
  139. void Terminal::restoreCursorPos() {
  140. //Restore cursor position and attributes
  141. print("\0338");
  142. }
  143. //Скрыть курсов
  144. void Terminal::hideCursor() {
  145. print("\033[8m");
  146. }
  147. //Очистить строку
  148. void Terminal::clearCurrentLine() {
  149. print("\033[2K");
  150. }
  151. void write(const char* src, int src_size, char* dst, uint32_t& size) {
  152. memcpy(&dst[size], src, src_size);
  153. size += src_size;
  154. }
  155. //Формирование команды для установки курсора в заданную позицию
  156. uint32_t Terminal::getCommand_MoveToPos(
  157. char* res_command, uint32_t& res_size, uint32_t h, uint32_t v
  158. )
  159. {
  160. //Esc[Line;ColumnH
  161. res_size = 0;
  162. write("\x1B[", 2, res_command, res_size);
  163. char* vStr = utoa(v);
  164. uint32_t sizeV = strlen(vStr);
  165. write(vStr, sizeV, res_command, res_size);
  166. write(";", 1, res_command, res_size);
  167. char* hStr = utoa(h);
  168. uint32_t sizeH = strlen(hStr);
  169. write(hStr, sizeH, res_command, res_size);
  170. write("H", 1, res_command, res_size);
  171. write("\0", 1, res_command, res_size);
  172. return res_size;
  173. }
  174. //Формирование команды для сдвига курсора вверх на n позиций
  175. uint32_t Terminal::getCommand_MoveUpNLines(
  176. char* res_command, uint32_t& res_size, uint32_t n)
  177. {
  178. return 0;
  179. }
  180. //Формирование команды для сдвига курсора вниз на n позиций
  181. uint32_t Terminal::getCommand_MoveDownNLines(
  182. char* res_command, uint32_t& res_size, uint32_t n)
  183. {
  184. return 0;
  185. }
  186. //Формирование команды для сдвига курсора вправо на n позиций
  187. uint32_t Terminal::getCommand_MoveRightNLines(
  188. char* res_command, uint32_t& res_size, uint32_t n)
  189. {
  190. return 0;
  191. }
  192. //Формирование команды для сдвига курсора влево на n позиций
  193. uint32_t Terminal::getCommand_MoveLeftNLines(
  194. char* res_command, uint32_t& res_size, uint32_t n)
  195. {
  196. return 0;
  197. }
  198. //Формирование команды для установки цвета текста
  199. uint32_t Terminal::getCommand_SetTextColor(char* res_command, uint32_t& res_size, TextColor color)
  200. {
  201. //Esc[3ColorH
  202. res_size = 0;
  203. write("\x1B[3", 3, res_command, res_size);
  204. char* vStr = utoa(color);
  205. write(vStr, 1, res_command, res_size);
  206. write("m", 1, res_command, res_size);
  207. write("\0", 1, res_command, res_size);
  208. return res_size;
  209. }
  210. //Формирование команды для установки аттрибута подчёркивания
  211. uint32_t Terminal::getCommand_UnderlineText(char* res_command, uint32_t& res_size)
  212. {
  213. res_size = 0;
  214. write("\x1B[4m", 4, res_command, res_size);
  215. write("\0", 1, res_command, res_size);
  216. return res_size;
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Класс реализации таблицы
  220. //-----------------------------------------------------------------------------
  221. Table::Table() {
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Вывод элементов таблицы
  225. //-----------------------------------------------------------------------------
  226. //Вывод сктроки в заданную ячейку
  227. void Table::outToCell(uint8_t col, uint8_t row, const char* str)
  228. {
  229. //CellAttribute &cell = cells[col][row];
  230. //print(cell.pos_command);
  231. //print(cell.color_command);
  232. pTerminal->resetAttribute();
  233. //Выводим атрибуты
  234. CellAttribute &cell = cells[col][row];
  235. print(cell.attributes);
  236. //Выводим строку
  237. print(str);
  238. //Выводим пробелы на до конца ячейки
  239. int32_t countSpace = m_width[col] - strlen(str) - 1;
  240. for (uint8_t i = 0; i < countSpace; i++)
  241. print(" ");
  242. }
  243. //Вывод значения в заданную ячейку
  244. void Table::outToCell(uint8_t col, uint8_t row, uint32_t val) {
  245. outToCell(col, row, utoa(val));
  246. }
  247. //Выводим в нужную строку разделяющую линию
  248. void Table::outCrossLine(uint8_t row) {
  249. uint32_t line = m_y + row;
  250. pTerminal->moveToPos(m_x, line);
  251. printCrossLine(line);
  252. }
  253. //Вывод внешней границы в строке
  254. void Table::outExternalBorder() {
  255. uint32_t line = m_y;
  256. printTopLine(line);
  257. for (uint8_t r = 0; r < m_row; r++)
  258. printTextLine(line);
  259. printBottomLine(line);
  260. }
  261. //Печать статической части таблицы
  262. void Table::outStatic()
  263. {
  264. pTerminal->saveCursorPos();
  265. outExternalBorder();
  266. pTerminal->restoreCursorPos();
  267. }
  268. //Печатает в таблице счётчик ячеек
  269. void Table::outCellNumber()
  270. {
  271. uint32_t count = 0;
  272. for (uint8_t c = 0; c < m_col; c ++) {
  273. for (uint8_t r = 0; r < m_row; r++) {
  274. print(cells[c][r].attributes);
  275. print(utoa(count));
  276. count ++;
  277. }
  278. }
  279. }
  280. void Table::startUpdate() {
  281. pTerminal->saveCursorPos();
  282. }
  283. void Table::endUpdate() {
  284. pTerminal->restoreCursorPos();
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Конфигурация талицы
  288. //-----------------------------------------------------------------------------
  289. //Задать геометрию таблицы
  290. void Table::setGeometry(uint8_t x, uint8_t y, uint8_t col, uint8_t row, uint32_t width, ...)
  291. {
  292. setPos(x, y);
  293. setSize(col, row);
  294. if ((m_col == 0) || (m_row == 0))
  295. return;
  296. //Читаем ширину колонок
  297. va_list ap;
  298. va_start(ap, width);
  299. uint8_t c = 0;
  300. m_width[c] = width;
  301. do {
  302. c++;
  303. m_width[c] = va_arg(ap, int32_t);
  304. } while (c < m_col);
  305. va_end(ap);
  306. resetAttributes();
  307. }
  308. //Задать геометрию таблицы
  309. void Table::setGeometry(uint8_t x, uint8_t y, uint8_t col, uint8_t row, const uint32_t* width)
  310. {
  311. setPos(x, y);
  312. setSize(col, row);
  313. if ((m_col == 0) || (m_row == 0))
  314. return;
  315. for (int c = 0; c < m_col; c++)
  316. m_width[c] = width[c];
  317. resetAttributes();
  318. }
  319. //Установить позицию таблицы
  320. void Table::setPos(uint8_t x, uint8_t y) {
  321. m_x = x; m_y = y;
  322. }
  323. //Установить размеры таблицы
  324. void Table::setSize(uint8_t col, uint8_t row) {
  325. m_col = col;
  326. m_row = row;
  327. if (m_col > MAX_COL)
  328. m_col = MAX_COL;
  329. if (m_row > MAX_ROW)
  330. m_row = MAX_ROW;
  331. }
  332. //Сброс аттрибутов для ячеек
  333. void Table::resetAttributes()
  334. {
  335. //Добавляем аттрибут для перемещения
  336. //курсора в начало каждой ячейки
  337. for (uint8_t c = 0; c < m_col; c ++) {
  338. for (uint8_t r = 0; r < m_row; r++) {
  339. clearCellAttributes(c, r);
  340. addCellPosAttribute(c, r);
  341. }
  342. }
  343. }
  344. //-----------------------------------------------------------------------------
  345. // Работа с аттрибутами
  346. //-----------------------------------------------------------------------------
  347. //Атрибуты - строка с управляющими командами для
  348. //терминала VT100, которые выводятся в терминал
  349. //перед выводом в ячейку (перемещение курсора
  350. //на ячейку, установка цвета)
  351. static char tmpAttr[20];
  352. static uint32_t tmpAttrSize = 0;
  353. //Расчитать для начала ячейки позицию курсора
  354. void Table::addCellPosAttribute(uint8_t col, uint8_t row) {
  355. //Расчитываем позицию курсора для ячейки
  356. uint32_t y = m_y + 1;
  357. uint32_t x = m_x + 1;
  358. for (uint32_t c = 0; c < col; c++)
  359. x += m_width[c];
  360. x += col;
  361. y += row;
  362. //Формируем команду перемещения курсора в рассчитанную позицию
  363. pTerminal->getCommand_MoveToPos(tmpAttr, tmpAttrSize, x, y);
  364. addCellAttribute(col, row, tmpAttr);
  365. }
  366. //Добавить аттрибут цвета текста
  367. void Table::addCellColorAttribute(uint8_t col, uint8_t row, TextColor color) {
  368. pTerminal->getCommand_SetTextColor(tmpAttr, tmpAttrSize, color);
  369. addCellAttribute(col, row, tmpAttr);
  370. }
  371. //Добавить аттрибут цвета текста
  372. void Table::addCellUnderlineAttribute(uint8_t col, uint8_t row) {
  373. pTerminal->getCommand_UnderlineText(tmpAttr, tmpAttrSize);
  374. addCellAttribute(col, row, tmpAttr);
  375. }
  376. //Очистить аттрибуты ячейки
  377. void Table::clearCellAttributes(uint8_t col, uint8_t row) {
  378. CellAttribute& cell = cells[col][row];
  379. cell.text = 0;
  380. char* attributes = cell.attributes;
  381. uint32_t attrSize = sizeof(cell.attributes);
  382. memset(attributes, 0, attrSize);
  383. }
  384. //Дописать аттрибут к ячейке
  385. void Table::addCellAttribute(uint8_t col, uint8_t row, const char* attr) {
  386. CellAttribute& cell = cells[col][row];
  387. uint8_t attrSize = strlen(cell.attributes);
  388. char* dst = &cell.attributes[attrSize];
  389. attrSize = strlen(attr);
  390. memcpy(dst, attr, attrSize);
  391. }
  392. //-----------------------------------------------------------------------------
  393. // Работа с выводом элементов рамки
  394. //-----------------------------------------------------------------------------
  395. //Символы псевдографики
  396. //----------------------------------------
  397. //─│┌┐└┘├┤┬┴┼═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬
  398. //----------------------------------------
  399. //Печать верхней границы рамки
  400. void Table::printTopLine(uint32_t& line) {
  401. printFrameLine(line, "┌", "┐", "┬", "─");
  402. }
  403. //Печать линии в таблице
  404. void Table::printCrossLine(uint32_t& line) {
  405. printFrameLine(line, "├", "┤", "┼", "─");
  406. }
  407. //Печать рамки для отдельной строки
  408. void Table::printTextLine(uint32_t& line) {
  409. printFrameLine(line, "│", "│", "│", " ");
  410. }
  411. //Печать нижней границы рамки таблицы
  412. void Table::printBottomLine(uint32_t& line) {
  413. printFrameLine(line, "└", "┘", "┴", "─");
  414. }
  415. ////Печать верхней границы рамки
  416. //void Table::printTopLine(uint32_t& line) {
  417. // printFrameLine(line, "╔", "╗", "╤", "═");
  418. //}
  419. ////Печать линии в таблице
  420. //void Table::printCrossLine(uint32_t& line) {
  421. // printFrameLine(line, "╟", "╢", "┼", "─");
  422. //}
  423. ////Печать рамки для отдельной строки
  424. //void Table::printTextLine(uint32_t& line) {
  425. // printFrameLine(line, "║", "║", "│", " ");
  426. //}
  427. ////Печать нижней границы рамки таблицы
  428. //void Table::printBottomLine(uint32_t& line) {
  429. // printFrameLine(line, "╚", "╝", "╧", "═");
  430. //}
  431. //Выводит строку рамки таблицы
  432. void Table::printFrameLine(uint32_t& line,
  433. const char* lc, const char* rc, const char* cr, const char* ln)
  434. {
  435. pTerminal->moveToPos(m_x, line);
  436. //Left corner
  437. print(lc);
  438. for (uint8_t c = 0; c < m_col; c++)
  439. {
  440. //Print line charachter
  441. uint8_t width = 0;
  442. while (width < m_width[c]) {
  443. print(ln);
  444. width++;
  445. }
  446. if (c < (m_col - 1))
  447. //Print cross character
  448. print(cr);
  449. else
  450. //Print right corner
  451. print(rc);
  452. }
  453. line++;
  454. }
  455. void Table::print(const char* str) {
  456. pTerminal->print(str);
  457. }
  458. //-----------------------------------------------------------------------------
  459. // Преобразование числа в строку ANSI C через быстрое деление
  460. //-----------------------------------------------------------------------------
  461. struct divmod10_t
  462. {
  463. uint32_t quot;
  464. uint8_t rem;
  465. };
  466. inline static divmod10_t divmodu10(uint32_t n)
  467. {
  468. divmod10_t res;
  469. res.quot = n >> 1;
  470. res.quot += res.quot >> 1;
  471. res.quot += res.quot >> 4;
  472. res.quot += res.quot >> 8;
  473. res.quot += res.quot >> 16;
  474. uint32_t qq = res.quot;
  475. res.quot >>= 3;
  476. res.rem = uint8_t(n - ((res.quot << 1) + (qq & ~7ul)));
  477. if(res.rem > 9)
  478. {
  479. res.rem -= 10;
  480. res.quot++;
  481. }
  482. return res;
  483. }
  484. static char utoaBuffer[13];
  485. //utoa fast div
  486. char * utoa(uint32_t value)
  487. {
  488. char* buffer = &utoaBuffer[1];
  489. buffer += 11;
  490. *--buffer = 0;
  491. do
  492. {
  493. divmod10_t res = divmodu10(value);
  494. *--buffer = res.rem + '0';
  495. value = res.quot;
  496. }
  497. while (value != 0);
  498. return buffer;
  499. }
  500. //utoa fast div
  501. char * itoa(int32_t value)
  502. {
  503. //Чёто неохото было гуглить. Мой
  504. //тупой вариант взятия модуля
  505. uint32_t unsignedValue = value;
  506. if (value < 0)
  507. unsignedValue = (uint32_t)(value - (2*value));
  508. char* unsignedStr = utoa(unsignedValue);
  509. //Добавляем знак минус в начало
  510. if (value < 0) {
  511. unsignedStr--;
  512. *unsignedStr = '-';
  513. }
  514. return unsignedStr;
  515. }