virtual.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-02-25 GuEe-GUI the first version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #include <dt-bindings/input/event-codes.h>
  13. #define DBG_TAG "serial.virtual"
  14. #define DBG_LVL DBG_INFO
  15. #include <rtdbg.h>
  16. #include "render.h"
  17. struct virtual_serial
  18. {
  19. struct rt_serial_device parent;
  20. struct rt_device *fbdev;
  21. struct rt_thread *render_task;
  22. struct rt_device *idev;
  23. struct rt_input_handler input_handler;
  24. int param;
  25. rt_bool_t input_int;
  26. struct render_point start, end;
  27. struct rt_spinlock lock;
  28. rt_uint8_t in[RT_CONSOLEBUF_SIZE];
  29. rt_uint16_t in_head, in_tail;
  30. rt_bool_t shift, ctrl, alt, caps;
  31. rt_bool_t is_escape, is_bracket;
  32. rt_bool_t in_pending;
  33. rt_uint8_t out[RT_CONSOLEBUF_SIZE];
  34. rt_uint16_t out_head, out_tail;
  35. rt_bool_t out_pending;
  36. };
  37. #define raw_to_virtual_serial(raw) rt_container_of(raw, struct virtual_serial, parent)
  38. static rt_uint8_t virtual_font[] =
  39. {
  40. #include "psf.inc"
  41. };
  42. enum
  43. {
  44. COLOR_BLACK,
  45. COLOR_RED,
  46. COLOR_GREEN,
  47. COLOR_YELLOW,
  48. COLOR_BLUE,
  49. COLOR_MAGENTA,
  50. COLOR_CYAN,
  51. COLOR_LIGHT_GRAY,
  52. COLOR_DARK_GRAY,
  53. COLOR_LIGHT_RED,
  54. COLOR_LIGHT_GREEN,
  55. COLOR_LIGHT_YELLOW,
  56. COLOR_LIGHT_BLUE,
  57. COLOR_LIGHT_MAGENTA,
  58. COLOR_LIGHT_CYAN,
  59. COLOR_WHITE,
  60. };
  61. static struct render_color font_colors[] =
  62. { /* R G B A */
  63. [COLOR_BLACK] = { 0, 0, 0, 255 },
  64. [COLOR_RED] = { 205, 0, 0, 255 },
  65. [COLOR_GREEN] = { 0, 205, 0, 255 },
  66. [COLOR_YELLOW] = { 205, 205, 0, 255 },
  67. [COLOR_BLUE] = { 0, 0, 238, 255 },
  68. [COLOR_MAGENTA] = { 205, 0, 205, 255 },
  69. [COLOR_CYAN] = { 0, 205, 205, 255 },
  70. [COLOR_LIGHT_GRAY] = { 229, 229, 229, 255 },
  71. [COLOR_DARK_GRAY] = { 127, 127, 127, 255 },
  72. [COLOR_LIGHT_RED] = { 255, 0, 0, 255 },
  73. [COLOR_LIGHT_GREEN] = { 0, 255, 0, 255 },
  74. [COLOR_LIGHT_YELLOW] = { 255, 255, 0, 255 },
  75. [COLOR_LIGHT_BLUE] = { 92, 92, 255, 255 },
  76. [COLOR_LIGHT_MAGENTA] = { 255, 0, 255, 255 },
  77. [COLOR_LIGHT_CYAN] = { 0, 255, 255, 255 },
  78. [COLOR_WHITE] = { 255, 255, 255, 255 },
  79. };
  80. static const rt_uint8_t unix_color_map[] =
  81. {
  82. /* \033[Xm */
  83. [0] = COLOR_WHITE,
  84. [30] = COLOR_BLACK,
  85. [31] = COLOR_RED,
  86. [32] = COLOR_GREEN,
  87. [33] = COLOR_YELLOW,
  88. [34] = COLOR_BLUE,
  89. [35] = COLOR_MAGENTA,
  90. [36] = COLOR_CYAN,
  91. [37] = COLOR_LIGHT_GRAY,
  92. [90] = COLOR_DARK_GRAY,
  93. [91] = COLOR_LIGHT_RED,
  94. [92] = COLOR_LIGHT_GREEN,
  95. [93] = COLOR_LIGHT_YELLOW,
  96. [94] = COLOR_LIGHT_BLUE,
  97. [95] = COLOR_LIGHT_MAGENTA,
  98. [96] = COLOR_LIGHT_CYAN,
  99. [97] = COLOR_WHITE,
  100. };
  101. static char key_map[] =
  102. {
  103. [KEY_1] = '1',
  104. [KEY_2] = '2',
  105. [KEY_3] = '3',
  106. [KEY_4] = '4',
  107. [KEY_5] = '5',
  108. [KEY_6] = '6',
  109. [KEY_7] = '7',
  110. [KEY_8] = '8',
  111. [KEY_9] = '9',
  112. [KEY_0] = '0',
  113. [KEY_MINUS] = '-',
  114. [KEY_EQUAL] = '=',
  115. [KEY_Q] = 'q',
  116. [KEY_W] = 'w',
  117. [KEY_E] = 'e',
  118. [KEY_R] = 'r',
  119. [KEY_T] = 't',
  120. [KEY_Y] = 'y',
  121. [KEY_U] = 'u',
  122. [KEY_I] = 'i',
  123. [KEY_O] = 'o',
  124. [KEY_P] = 'p',
  125. [KEY_LEFTBRACE] = '[',
  126. [KEY_RIGHTBRACE] = ']',
  127. [KEY_A] = 'a',
  128. [KEY_S] = 's',
  129. [KEY_D] = 'd',
  130. [KEY_F] = 'f',
  131. [KEY_G] = 'g',
  132. [KEY_H] = 'h',
  133. [KEY_J] = 'j',
  134. [KEY_K] = 'k',
  135. [KEY_L] = 'l',
  136. [KEY_SEMICOLON] = ';',
  137. [KEY_APOSTROPHE] = '\'',
  138. [KEY_BACKSLASH] = '\\',
  139. [KEY_Z] = 'z',
  140. [KEY_X] = 'x',
  141. [KEY_C] = 'c',
  142. [KEY_V] = 'v',
  143. [KEY_B] = 'b',
  144. [KEY_N] = 'n',
  145. [KEY_M] = 'm',
  146. [KEY_COMMA] = ',',
  147. [KEY_DOT] = '.',
  148. [KEY_SLASH] = '/',
  149. [KEY_SPACE] = ' ',
  150. };
  151. static char key_shift_map[] =
  152. {
  153. [KEY_1] = '!',
  154. [KEY_2] = '@',
  155. [KEY_3] = '#',
  156. [KEY_4] = '$',
  157. [KEY_5] = '%',
  158. [KEY_6] = '^',
  159. [KEY_7] = '&',
  160. [KEY_8] = '*',
  161. [KEY_9] = '(',
  162. [KEY_0] = ')',
  163. [KEY_MINUS] = '_',
  164. [KEY_EQUAL] = '+',
  165. [KEY_Q] = 'Q',
  166. [KEY_W] = 'W',
  167. [KEY_E] = 'E',
  168. [KEY_R] = 'R',
  169. [KEY_T] = 'T',
  170. [KEY_Y] = 'Y',
  171. [KEY_U] = 'U',
  172. [KEY_I] = 'I',
  173. [KEY_O] = 'O',
  174. [KEY_P] = 'P',
  175. [KEY_LEFTBRACE] = '{',
  176. [KEY_RIGHTBRACE] = '}',
  177. [KEY_A] = 'A',
  178. [KEY_S] = 'S',
  179. [KEY_D] = 'D',
  180. [KEY_F] = 'F',
  181. [KEY_G] = 'G',
  182. [KEY_H] = 'H',
  183. [KEY_J] = 'J',
  184. [KEY_K] = 'K',
  185. [KEY_L] = 'L',
  186. [KEY_SEMICOLON] = ':',
  187. [KEY_APOSTROPHE] = '\"',
  188. [KEY_BACKSLASH] = '|',
  189. [KEY_Z] = 'Z',
  190. [KEY_X] = 'X',
  191. [KEY_C] = 'C',
  192. [KEY_V] = 'V',
  193. [KEY_B] = 'B',
  194. [KEY_N] = 'N',
  195. [KEY_M] = 'M',
  196. [KEY_COMMA] = '<',
  197. [KEY_DOT] = '>',
  198. [KEY_SLASH] = '?',
  199. [KEY_SPACE] = ' ',
  200. };
  201. static enum cursor cursor_shape = CURSOR_BLOCK;
  202. static struct virtual_serial _vs = {};
  203. static void push_out_char(struct virtual_serial *vs, char c);
  204. static void virtual_serial_render_char(struct virtual_serial *vs, char ch);
  205. static int pop_in_char(struct virtual_serial *vs);
  206. static rt_err_t virtual_serial_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
  207. {
  208. return RT_EOK;
  209. }
  210. static rt_err_t virtual_serial_control(struct rt_serial_device *serial, int cmd, void *arg)
  211. {
  212. struct virtual_serial *vs = raw_to_virtual_serial(serial);
  213. switch (cmd)
  214. {
  215. case RT_DEVICE_CTRL_SUSPEND:
  216. case RT_DEVICE_CTRL_CLR_INT:
  217. vs->input_int = RT_FALSE;
  218. break;
  219. case RT_DEVICE_CTRL_RESUME:
  220. case RT_DEVICE_CTRL_SET_INT:
  221. vs->input_int = RT_TRUE;
  222. break;
  223. default:
  224. return -RT_ENOSYS;
  225. }
  226. return RT_EOK;
  227. }
  228. static int virtual_serial_putc(struct rt_serial_device *serial, char c)
  229. {
  230. struct virtual_serial *vs = raw_to_virtual_serial(serial);
  231. rt_spin_lock(&vs->lock);
  232. if (!rt_critical_level())
  233. {
  234. virtual_serial_render_char(vs, c);
  235. }
  236. else
  237. {
  238. push_out_char(vs, c);
  239. rt_thread_resume(vs->render_task);
  240. }
  241. rt_spin_unlock(&vs->lock);
  242. return 1;
  243. }
  244. static int virtual_serial_getc(struct rt_serial_device *serial)
  245. {
  246. struct virtual_serial *vs = raw_to_virtual_serial(serial);
  247. return pop_in_char(vs);
  248. }
  249. static const struct rt_uart_ops virtual_serial_ops =
  250. {
  251. .configure = virtual_serial_configure,
  252. .control = virtual_serial_control,
  253. .putc = virtual_serial_putc,
  254. .getc = virtual_serial_getc,
  255. };
  256. static rt_bool_t parse_ctrl(struct virtual_serial *vs, char c)
  257. {
  258. if (vs->is_bracket && c == 'm')
  259. {
  260. render_set_foreground(&font_colors[unix_color_map[vs->param]]);
  261. return RT_TRUE;
  262. }
  263. if (c == 'J' && vs->param == 2)
  264. {
  265. render_clear_display();
  266. return RT_TRUE;
  267. }
  268. if (c == 'K' && vs->param == 2)
  269. {
  270. rt_uint32_t old_col;
  271. struct render_point point;
  272. render_current_cursor(&point);
  273. old_col = point.col;
  274. for (int i = vs->start.col; i < old_col; ++i)
  275. {
  276. --point.col;
  277. render_move_cursor(&point);
  278. render_put_char(' ');
  279. }
  280. point.col = old_col;
  281. render_move_cursor(&point);
  282. return RT_TRUE;
  283. }
  284. if (c == 'H')
  285. {
  286. render_move_cursor(&vs->start);
  287. return RT_TRUE;
  288. }
  289. return RT_FALSE;
  290. }
  291. static void push_out_char(struct virtual_serial *vs, char c)
  292. {
  293. rt_uint16_t next = (vs->out_head + 1) % sizeof(vs->out);
  294. if (next == vs->out_tail)
  295. {
  296. /* Full */
  297. return;
  298. }
  299. vs->out[vs->out_head] = c;
  300. vs->out_head = next;
  301. vs->out_pending = RT_TRUE;
  302. }
  303. static int pop_out_char(struct virtual_serial *vs)
  304. {
  305. int c;
  306. if (vs->out_head == vs->out_tail)
  307. {
  308. return -1;
  309. }
  310. c = vs->out[vs->out_tail];
  311. vs->out_tail = (vs->out_tail + 1) % sizeof(vs->out);
  312. return c;
  313. }
  314. static void push_in_char(struct virtual_serial *vs, char c)
  315. {
  316. rt_uint16_t next = (vs->in_head + 1) % sizeof(vs->in);
  317. if (next == vs->in_tail)
  318. {
  319. /* Full, drop */
  320. return;
  321. }
  322. vs->in[vs->in_head] = (rt_uint8_t)c;
  323. vs->in_head = next;
  324. vs->in_pending = RT_TRUE;
  325. }
  326. static int pop_in_char(struct virtual_serial *vs)
  327. {
  328. int ch;
  329. if (vs->in_head == vs->in_tail)
  330. {
  331. return -1;
  332. }
  333. ch = vs->in[vs->in_tail];
  334. vs->in_tail = (vs->in_tail + 1) % sizeof(vs->in);
  335. return ch;
  336. }
  337. static char key_to_char(struct virtual_serial *vs, int code)
  338. {
  339. char base, shiftc;
  340. base = key_map[code];
  341. shiftc = key_shift_map[code];
  342. if (!base && !shiftc)
  343. {
  344. return 0;
  345. }
  346. if (code >= KEY_A && code <= KEY_Z)
  347. {
  348. rt_bool_t upper = (vs->shift ^ vs->caps);
  349. return upper ? (shiftc ? shiftc : base - 'a' + 'A')
  350. : (base ? base : shiftc + 'a' - 'A');
  351. }
  352. if (vs->shift && shiftc)
  353. {
  354. return shiftc;
  355. }
  356. return base;
  357. }
  358. static void virtual_serial_render_char(struct virtual_serial *vs, char ch)
  359. {
  360. if (vs->is_escape)
  361. {
  362. if (ch == '[')
  363. {
  364. vs->param = 0;
  365. vs->is_bracket = RT_TRUE;
  366. return;
  367. }
  368. else if (vs->is_bracket && (ch >= '0' && ch <= '9'))
  369. {
  370. vs->param = vs->param * 10 + (ch - '0');
  371. return;
  372. }
  373. else
  374. {
  375. if (!parse_ctrl(vs, ch))
  376. {
  377. goto _render_char;
  378. }
  379. vs->is_bracket = RT_FALSE;
  380. vs->is_escape = RT_FALSE;
  381. return;
  382. }
  383. }
  384. _render_char:
  385. if (ch >= ' ')
  386. {
  387. render_put_char(ch);
  388. }
  389. else
  390. {
  391. struct render_point point;
  392. switch (ch)
  393. {
  394. case '\n':
  395. render_return_cursor(RT_NULL);
  396. break;
  397. case '\033':
  398. vs->is_escape = RT_TRUE;
  399. break;
  400. case '\t':
  401. render_current_cursor(&point);
  402. point.col = (point.col / 4 + 1) * 4;
  403. if (point.col > vs->end.col)
  404. {
  405. point.col -= vs->end.col;
  406. point.row++;
  407. }
  408. render_move_cursor(&point);
  409. break;
  410. case '\r':
  411. render_reset_cursor(RT_NULL);
  412. break;
  413. case '\b':
  414. render_current_cursor(&point);
  415. if (point.col > 0)
  416. {
  417. point.col--;
  418. render_move_cursor(&point);
  419. }
  420. break;
  421. default:
  422. break;
  423. }
  424. }
  425. }
  426. static void virtual_serial_render_task(void *param)
  427. {
  428. struct virtual_serial *vs = param;
  429. while (RT_TRUE)
  430. {
  431. rt_spin_lock(&vs->lock);
  432. if (vs->out_head == vs->out_tail)
  433. {
  434. rt_spin_unlock(&vs->lock);
  435. rt_thread_suspend(rt_thread_self());
  436. rt_schedule();
  437. continue;
  438. }
  439. virtual_serial_render_char(vs, pop_out_char(vs));
  440. rt_spin_unlock(&vs->lock);
  441. }
  442. }
  443. static rt_bool_t virtual_serial_input_test_cap(struct rt_input_handler *handler,
  444. struct rt_input_device *idev)
  445. {
  446. return rt_bitmap_test_bit(idev->key_map, KEY_ENTER);
  447. }
  448. static rt_bool_t virtual_serial_input_callback(struct rt_input_handler *handler,
  449. struct rt_input_event *ev)
  450. {
  451. char ch;
  452. struct virtual_serial *vs = handler->priv;
  453. if (ev->type == EV_KEY)
  454. {
  455. if (!vs->input_int)
  456. {
  457. return RT_TRUE;
  458. }
  459. if (ev->value == 0)
  460. {
  461. switch (ev->code)
  462. {
  463. case KEY_LEFTSHIFT:
  464. case KEY_RIGHTSHIFT:
  465. vs->shift = RT_FALSE;
  466. break;
  467. case KEY_LEFTCTRL:
  468. case KEY_RIGHTCTRL:
  469. vs->ctrl = RT_FALSE;
  470. break;
  471. case KEY_LEFTALT:
  472. case KEY_RIGHTALT:
  473. vs->alt = RT_FALSE;
  474. break;
  475. default:
  476. break;
  477. }
  478. return RT_TRUE;
  479. }
  480. if (ev->value != 1)
  481. {
  482. return RT_TRUE;
  483. }
  484. switch (ev->code)
  485. {
  486. case KEY_LEFTSHIFT:
  487. case KEY_RIGHTSHIFT:
  488. vs->shift = RT_TRUE;
  489. break;
  490. case KEY_LEFTCTRL:
  491. case KEY_RIGHTCTRL:
  492. vs->ctrl = RT_TRUE;
  493. break;
  494. case KEY_LEFTALT:
  495. case KEY_RIGHTALT:
  496. vs->alt = RT_TRUE;
  497. break;
  498. case KEY_CAPSLOCK:
  499. vs->caps = !vs->caps;
  500. break;
  501. case KEY_ENTER:
  502. case KEY_KPENTER:
  503. push_in_char(vs, '\r');
  504. break;
  505. case KEY_BACKSPACE:
  506. push_in_char(vs, '\b');
  507. break;
  508. case KEY_TAB:
  509. push_in_char(vs, '\t');
  510. break;
  511. case KEY_UP:
  512. push_in_char(vs, 0x1b);
  513. push_in_char(vs, '[');
  514. push_in_char(vs, 'A');
  515. break;
  516. case KEY_DOWN:
  517. push_in_char(vs, 0x1b);
  518. push_in_char(vs, '[');
  519. push_in_char(vs, 'B');
  520. break;
  521. case KEY_LEFT:
  522. push_in_char(vs, 0x1b);
  523. push_in_char(vs, '[');
  524. push_in_char(vs, 'D');
  525. break;
  526. case KEY_RIGHT:
  527. push_in_char(vs, 0x1b);
  528. push_in_char(vs, '[');
  529. push_in_char(vs, 'C');
  530. break;
  531. default:
  532. if ((ch = key_to_char(vs, ev->code)))
  533. {
  534. push_in_char(vs, ch);
  535. }
  536. break;
  537. }
  538. return RT_TRUE;
  539. }
  540. else if (ev->type == EV_SYN)
  541. {
  542. if (vs->input_int && vs->in_pending)
  543. {
  544. vs->in_pending = RT_FALSE;
  545. rt_hw_serial_isr(&vs->parent, RT_SERIAL_EVENT_RX_IND);
  546. }
  547. return RT_TRUE;
  548. }
  549. return RT_FALSE;
  550. }
  551. static int virtual_serial_setup(void)
  552. {
  553. rt_err_t err;
  554. for (int id = 0; id < RT_DM_IDA_NUM; ++id)
  555. {
  556. if ((_vs.fbdev = rt_dm_device_find(MASTER_ID_GRAPHIC_FRAMEBUFFER, id)))
  557. {
  558. break;
  559. }
  560. }
  561. if (!_vs.fbdev)
  562. {
  563. return (int)-RT_ENOSYS;
  564. }
  565. _vs.input_handler.idev = RT_NULL;
  566. _vs.input_handler.identify = &virtual_serial_input_test_cap;
  567. _vs.input_handler.callback = &virtual_serial_input_callback;
  568. _vs.input_handler.priv = &_vs;
  569. if ((err = rt_input_add_handler(&_vs.input_handler)))
  570. {
  571. return (int)err;
  572. }
  573. if (!(_vs.render_task = rt_thread_create("vuart", virtual_serial_render_task, &_vs,
  574. DM_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX / 2, 32)))
  575. {
  576. goto _fail;
  577. }
  578. if ((err = render_load_fbdev(_vs.fbdev)))
  579. {
  580. LOG_E("Load fbdev error = %s", rt_strerror(err));
  581. goto _fail;
  582. }
  583. if ((err = render_load_font((void *)virtual_font, sizeof(virtual_font),
  584. &font_colors[COLOR_WHITE], &font_colors[COLOR_BLACK],
  585. &_vs.start, &_vs.end)))
  586. {
  587. LOG_E("Load PSF font error = %s", rt_strerror(err));
  588. goto _fail;
  589. }
  590. render_select_cursor(cursor_shape);
  591. rt_device_open(_vs.fbdev, 0);
  592. rt_spin_lock_init(&_vs.lock);
  593. rt_thread_startup(_vs.render_task);
  594. _vs.input_int = RT_TRUE;
  595. _vs.parent.ops = &virtual_serial_ops;
  596. _vs.parent.config = (struct serial_configure)RT_SERIAL_CONFIG_DEFAULT;
  597. rt_hw_serial_register(&_vs.parent, "vuart", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, &_vs);
  598. return 0;
  599. _fail:
  600. rt_input_del_handler(&_vs.input_handler);
  601. return (int)err;
  602. }
  603. INIT_EXPORT(virtual_serial_setup, "3.end");
  604. #if defined(RT_USING_CONSOLE) && defined(RT_USING_MSH)
  605. static int virtual_serial_cmd_color(int argc, char**argv)
  606. {
  607. const char *color;
  608. static const char * const color_names[] =
  609. {
  610. [COLOR_BLACK] = "black",
  611. [COLOR_RED] = "red",
  612. [COLOR_GREEN] = "green",
  613. [COLOR_YELLOW] = "yellow",
  614. [COLOR_BLUE] = "blue",
  615. [COLOR_MAGENTA] = "magenta",
  616. [COLOR_CYAN] = "cyan",
  617. [COLOR_LIGHT_GRAY] = "light gray",
  618. [COLOR_DARK_GRAY] = "dark gray",
  619. [COLOR_LIGHT_RED] = "light red",
  620. [COLOR_LIGHT_GREEN] = "light green",
  621. [COLOR_LIGHT_YELLOW] = "light yellow",
  622. [COLOR_LIGHT_BLUE] = "light blue",
  623. [COLOR_LIGHT_MAGENTA] = "light magenta",
  624. [COLOR_LIGHT_CYAN] = "light cyan",
  625. [COLOR_WHITE] = "white",
  626. };
  627. if (argc != 2)
  628. {
  629. goto _help;
  630. }
  631. color = argv[1];
  632. if (!((color[0] >= '0' && color[0] <= '9') || (color[0] >= 'a' && color[0] <= 'f')) ||
  633. !((color[1] >= '0' && color[1] <= '9') || (color[1] >= 'a' && color[1] <= 'f')))
  634. {
  635. goto _help;
  636. }
  637. if (color[0] == color[1])
  638. {
  639. rt_kprintf("foreground cannot equal background\n");
  640. return (int)-RT_EINVAL;
  641. }
  642. render_set_foreground(&font_colors[color[0] - (color[0] >= 'a' ? ('a' - 10) : '0')]);
  643. render_set_background(&font_colors[color[1] - (color[1] >= 'a' ? ('a' - 10) : '0')]);
  644. return 0;
  645. _help:
  646. rt_kprintf("Usage: color [attr]\nattr:\n");
  647. for (int i = 0; i < RT_ARRAY_SIZE(font_colors); ++i)
  648. {
  649. rt_kprintf("\t%x = %s\n", i, color_names[i]);
  650. }
  651. return (int)-RT_EINVAL;
  652. }
  653. MSH_CMD_EXPORT_ALIAS(virtual_serial_cmd_color, color, set virtual serial foreground and background);
  654. #endif /* RT_USING_CONSOLE && RT_USING_MSH */