term.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /*
  2. * Copyright (C) 2001-2003 by egnite Software GmbH. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. */
  33. /*
  34. * $Log$
  35. * Revision 1.8 2009/02/13 14:52:05 haraldkipp
  36. * Include memdebug.h for heap management debugging support.
  37. *
  38. * Revision 1.7 2008/08/11 06:59:42 haraldkipp
  39. * BSD types replaced by stdint types (feature request #1282721).
  40. *
  41. * Revision 1.6 2005/08/02 17:46:47 haraldkipp
  42. * Major API documentation update.
  43. *
  44. * Revision 1.5 2004/05/24 17:11:05 olereinhardt
  45. * dded terminal device driver for hd44780 compatible LCD displays directly
  46. * connected to the memory bus (memory mapped). See hd44780.c for more
  47. * information.Therefore some minor changed in include/dev/term.h and
  48. * dev/term.c are needet to
  49. * pass a base address to the lcd driver.
  50. *
  51. * Revision 1.4 2004/03/18 18:30:11 haraldkipp
  52. * Added Michael Fischer's TIOCGWINSZ ioctl
  53. *
  54. * Revision 1.3 2004/03/18 14:02:46 haraldkipp
  55. * Comments updated
  56. *
  57. * Revision 1.2 2004/03/16 16:48:27 haraldkipp
  58. * Added Jan Dubiec's H8/300 port.
  59. *
  60. * Revision 1.1.1.1 2003/05/09 14:40:52 haraldkipp
  61. * Initial using 3.2.1
  62. *
  63. * Revision 1.3 2003/05/06 18:34:22 harald
  64. * Cleanup
  65. *
  66. * Revision 1.2 2003/04/21 16:25:24 harald
  67. * Release prep
  68. *
  69. * Revision 1.1 2003/03/31 14:53:08 harald
  70. * Prepare release 3.1
  71. *
  72. */
  73. #include <dev/term.h>
  74. #include <stdlib.h>
  75. #include <string.h>
  76. #include <fcntl.h>
  77. #include <memdebug.h>
  78. /*!
  79. * \addtogroup xgTerminal
  80. */
  81. /*@{*/
  82. static const char termid[] = "Term 1.0";
  83. static void TermRefreshLineEnd(const TERMDCB * dcb, uint8_t row, uint8_t col)
  84. {
  85. uint8_t i = col;
  86. uint8_t *cp = dcb->dcb_smem + row * dcb->dcb_vcols + col;
  87. /* Disable cursor to avoid flickering. */
  88. if (dcb->dcb_modeflags & LCD_MF_CURSORON)
  89. (*dcb->dss_cursor_mode) (0);
  90. /* Position cursor to the rwo and column to refresh. */
  91. (*dcb->dss_set_cursor) (row * dcb->dcb_ncols + col);
  92. /*
  93. * This loop looks weird. But it was the only way I found to get
  94. * around a GCC bug in reload1.c:1920.
  95. */
  96. for (;;) {
  97. if (i++ >= dcb->dcb_vcols)
  98. break;
  99. (*dcb->dss_write) (*cp++);
  100. }
  101. /* Re-enable cursor. */
  102. if (dcb->dcb_modeflags & LCD_MF_CURSORON)
  103. (*dcb->dss_cursor_mode) (1);
  104. }
  105. void TermRefresh(TERMDCB * dcb)
  106. {
  107. uint8_t ir;
  108. for (ir = 0; ir < dcb->dcb_nrows; ir++)
  109. TermRefreshLineEnd(dcb, ir, 0);
  110. (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
  111. }
  112. static void TermClear(TERMDCB * dcb)
  113. {
  114. memset(dcb->dcb_smem, ' ', dcb->dcb_vcols * dcb->dcb_nrows);
  115. dcb->dcb_col = 0;
  116. dcb->dcb_row = 0;
  117. (*dcb->dss_clear) ();
  118. }
  119. static void TermDeleteLine(TERMDCB * dcb, uint8_t row)
  120. {
  121. uint8_t i;
  122. uint8_t *dcp;
  123. for (i = row; i < dcb->dcb_nrows - 1; i++) {
  124. dcp = dcb->dcb_smem + i * dcb->dcb_vcols;
  125. memcpy(dcp, dcp + dcb->dcb_vcols, dcb->dcb_vcols);
  126. }
  127. memset(dcb->dcb_smem + (dcb->dcb_nrows - 1) * dcb->dcb_vcols, ' ', dcb->dcb_vcols);
  128. TermRefresh(dcb);
  129. }
  130. static void TermInsertLine(TERMDCB * dcb, uint8_t row)
  131. {
  132. uint8_t i;
  133. uint8_t *dcp;
  134. for (i = dcb->dcb_nrows - 1; i > row; i--) {
  135. dcp = dcb->dcb_smem + i * dcb->dcb_vcols;
  136. memcpy(dcp, dcp - dcb->dcb_vcols, dcb->dcb_vcols);
  137. }
  138. memset(dcb->dcb_smem + row * dcb->dcb_vcols, ' ', dcb->dcb_vcols);
  139. TermRefresh(dcb);
  140. }
  141. static void TermCursorLeft(TERMDCB * dcb)
  142. {
  143. if (dcb->dcb_col) {
  144. (*dcb->dss_cursor_left) ();
  145. dcb->dcb_col--;
  146. }
  147. }
  148. static void TermCursorRight(TERMDCB * dcb)
  149. {
  150. if (++dcb->dcb_col < dcb->dcb_vcols)
  151. (*dcb->dss_cursor_right) ();
  152. else
  153. dcb->dcb_col = dcb->dcb_vcols - 1;
  154. }
  155. static void TermCursorUp(TERMDCB * dcb)
  156. {
  157. if (dcb->dcb_row) {
  158. dcb->dcb_row--;
  159. (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
  160. }
  161. }
  162. static void TermLinefeed(TERMDCB * dcb)
  163. {
  164. if (++dcb->dcb_row >= dcb->dcb_nrows) {
  165. dcb->dcb_row = dcb->dcb_nrows - 1;
  166. TermDeleteLine(dcb, 0);
  167. } else
  168. (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
  169. }
  170. static void TermReverseLinefeed(TERMDCB * dcb)
  171. {
  172. if (dcb->dcb_row--)
  173. (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
  174. else {
  175. dcb->dcb_row = 0;
  176. TermInsertLine(dcb, 0);
  177. }
  178. }
  179. static void TermEraseLineEnd(TERMDCB * dcb, uint8_t col)
  180. {
  181. if (col < dcb->dcb_vcols) {
  182. memset(dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols + col, ' ', dcb->dcb_vcols - col);
  183. TermRefresh(dcb);
  184. }
  185. }
  186. static void TermEraseEnd(TERMDCB * dcb)
  187. {
  188. uint8_t i;
  189. if (dcb->dcb_col < dcb->dcb_vcols)
  190. memset(dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols + dcb->dcb_col, ' ', dcb->dcb_vcols - dcb->dcb_col);
  191. for (i = dcb->dcb_row + 1; i < dcb->dcb_nrows; i++)
  192. memset(dcb->dcb_smem + i * dcb->dcb_vcols, ' ', dcb->dcb_vcols);
  193. TermRefresh(dcb);
  194. }
  195. static void TermEraseLineStart(TERMDCB * dcb)
  196. {
  197. if (dcb->dcb_col) {
  198. memset(dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols, ' ', dcb->dcb_col);
  199. TermRefresh(dcb);
  200. }
  201. }
  202. static void TermEraseStart(TERMDCB * dcb)
  203. {
  204. uint8_t i;
  205. if (dcb->dcb_col)
  206. memset(dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols, ' ', dcb->dcb_col);
  207. for (i = 0; i < dcb->dcb_row; i++)
  208. memset(dcb->dcb_smem + i * dcb->dcb_vcols, ' ', dcb->dcb_vcols);
  209. TermRefresh(dcb);
  210. }
  211. static void TermDeleteChar(TERMDCB * dcb, uint8_t col)
  212. {
  213. uint8_t i;
  214. uint8_t *cp = dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols + col;
  215. for (i = col; i < dcb->dcb_vcols - 1; i++, cp++)
  216. *cp = *(cp + 1);
  217. *cp = ' ';
  218. TermRefresh(dcb);
  219. }
  220. /*
  221. * Insert a space at the cursor position.
  222. */
  223. static void TermInsertSpace(TERMDCB * dcb)
  224. {
  225. uint8_t i;
  226. uint8_t *cp = dcb->dcb_smem + (dcb->dcb_row + 1) * dcb->dcb_vcols - 1;
  227. for (i = dcb->dcb_col; i < dcb->dcb_vcols - 1; i++, cp--)
  228. *cp = *(cp - 1);
  229. *cp = ' ';
  230. TermRefreshLineEnd(dcb, dcb->dcb_row, dcb->dcb_col);
  231. (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
  232. }
  233. /*
  234. * Clear display and print identification.
  235. */
  236. static void TermIdentify(TERMDCB * dcb)
  237. {
  238. const char *pcp = termid;
  239. TermClear(dcb);
  240. while (*pcp) {
  241. (*dcb->dss_write) (*pcp);
  242. pcp++;
  243. }
  244. }
  245. /*!
  246. * \brief Perform special LCD control functions.
  247. *
  248. * \param dev Identifies the device that receives the device-control
  249. * function.
  250. * \param req Requested control function. May be set to one of the
  251. * following constants:
  252. * - LCD_CMDBYTE Send command byte to display. Parameter conf points
  253. * to an u_char value containing the command byte.
  254. * - LCD_CMDWORD16 Send 16 bit command word to display. Parameter conf
  255. * points to an uint16_t value containing the command
  256. * bytes. The most significant byte is send first.
  257. * - LCD_CMDWORD32 Send 32 bit command byte to display. Parameter conf
  258. * points to an uint32_t value containing the command
  259. * bytes. The most significant bytes are send first.
  260. * - LCD_DATABYTE Send raw data byte to display. Parameter conf points
  261. * to an u_char value containing the data byte.
  262. * - LCD_DATAWORD16 Send 16 bit raw data word to display. Parameter conf
  263. * points to an uint16_t value containing the data
  264. * bytes. The most significant byte is send first.
  265. * - LCD_DATAWORD32 Send 32 bit raw data word to display. Parameter conf
  266. * points to an uint32_t value containing the data
  267. * bytes. The most significant bytes are send first.
  268. * - LCD_SETCOOKEDMODE Set terminal control character mode. Parameter conf
  269. * points to an uint32_t value containing 0 (off) or 1
  270. * (on).
  271. * - LCD_GETCOOKEDMODE Query terminal control character mode. Parameter
  272. * conf points to an uint32_t value receiving 0 (off)
  273. * or 1 (on).
  274. *
  275. * \param conf Points to a buffer that contains any data required for
  276. * the given control function or receives data from that
  277. * function.
  278. *
  279. * \return 0 on success, -1 otherwise.
  280. *
  281. */
  282. int TermIOCtl(NUTDEVICE * dev, int req, void *conf)
  283. {
  284. TERMDCB *dcb = dev->dev_dcb;
  285. uint16_t usv;
  286. uint32_t ulv;
  287. WINSIZE *win_size;
  288. switch (req) {
  289. case LCD_CMDBYTE:
  290. (*dcb->dss_command) (*(uint8_t *)conf, 10);
  291. break;
  292. case LCD_CMDWORD16:
  293. usv = *(uint16_t *)conf;
  294. (*dcb->dss_command) ((uint8_t)(usv >> 8), 10);
  295. (*dcb->dss_command) ((uint8_t)usv, 10);
  296. break;
  297. case LCD_CMDWORD32:
  298. ulv = *(uint32_t *)conf;
  299. (*dcb->dss_command) ((uint8_t)(ulv >> 24), 10);
  300. (*dcb->dss_command) ((uint8_t)(ulv >> 16), 10);
  301. (*dcb->dss_command) ((uint8_t)(ulv >> 8), 10);
  302. (*dcb->dss_command) ((uint8_t)ulv, 10);
  303. break;
  304. case LCD_DATABYTE:
  305. (*dcb->dss_write) (*(uint8_t *)conf);
  306. break;
  307. case LCD_DATAWORD16:
  308. usv = *(uint16_t *)conf;
  309. (*dcb->dss_write) ((uint8_t)(usv >> 8));
  310. (*dcb->dss_write) ((uint8_t)usv);
  311. break;
  312. case LCD_DATAWORD32:
  313. ulv = *(uint32_t *)conf;
  314. (*dcb->dss_write) ((uint8_t)(ulv >> 24));
  315. (*dcb->dss_write) ((uint8_t)(ulv >> 16));
  316. (*dcb->dss_write) ((uint8_t)(ulv >> 8));
  317. (*dcb->dss_write) ((uint8_t)ulv);
  318. break;
  319. case LCD_SETCOOKEDMODE:
  320. if (*(uint32_t *)conf)
  321. dcb->dcb_modeflags |= LCD_MF_COOKEDMODE;
  322. else
  323. dcb->dcb_modeflags &= ~LCD_MF_COOKEDMODE;
  324. break;
  325. case LCD_GETCOOKEDMODE:
  326. if (dcb->dcb_modeflags & LCD_MF_COOKEDMODE)
  327. *(uint32_t *)conf = 1;
  328. else
  329. *(uint32_t *)conf = 0;
  330. break;
  331. case LCD_SET_AUTOLF:
  332. if (*(uint32_t *)conf)
  333. dcb->dcb_modeflags |= LCD_MF_AUTOLF;
  334. else
  335. dcb->dcb_modeflags &= ~LCD_MF_AUTOLF;
  336. break;
  337. case LCD_GET_AUTOLF:
  338. if (dcb->dcb_modeflags & LCD_MF_AUTOLF)
  339. *(uint32_t *)conf = 1;
  340. else
  341. *(uint32_t *)conf = 0;
  342. break;
  343. case TIOCGWINSZ:
  344. win_size = (WINSIZE *)conf;
  345. win_size->ws_col = dcb->dcb_nrows;
  346. win_size->ws_row = dcb->dcb_vcols;
  347. win_size->ws_xpixel = 0;
  348. win_size->ws_ypixel = 0;
  349. break;
  350. }
  351. return 0;
  352. }
  353. /*!
  354. * \brief Initialize the terminal device.
  355. *
  356. * Prepares the device for subsequent writing.
  357. *
  358. * Application should not call this function directly, but use the
  359. * stdio interface.
  360. *
  361. * \param dev Identifies the device to initialize.
  362. *
  363. * \return 0 on success, -1 otherwise.
  364. */
  365. int TermInit(NUTDEVICE * dev)
  366. {
  367. TERMDCB *dcb = dev->dev_dcb;
  368. /*
  369. * Check if initialisazion needed.
  370. */
  371. if( dcb->dss_init != NULL) {
  372. /*
  373. * Initialize the display hardware.
  374. */
  375. if( dcb->dss_init(dev) != 0) {
  376. return -1;
  377. }
  378. }
  379. /*
  380. * Initialize driver control block.
  381. */
  382. dcb->dcb_smem = malloc(dcb->dcb_nrows * dcb->dcb_vcols);
  383. if( dcb->dcb_smem == NULL) {
  384. return -1;
  385. }
  386. TermClear(dcb);
  387. return 0;
  388. }
  389. /*!
  390. * \brief Write to the terminal device.
  391. *
  392. * \param fp File pointer to a previously opened device.
  393. * \param buffer Pointer to the data bytes to be written.
  394. * \param len Number of bytes to write.
  395. * \param pflg Set if the buffer is located in program space.
  396. *
  397. * \return The number of bytes written.
  398. *
  399. */
  400. static int TermPut(NUTDEVICE * dev, const void *buffer, int len, int pflg)
  401. {
  402. int rc;
  403. const uint8_t *cp;
  404. uint8_t ch;
  405. TERMDCB *dcb = dev->dev_dcb;
  406. /*
  407. * Call without data pointer is accepted.
  408. */
  409. if (buffer == 0)
  410. return 0;
  411. /*
  412. * Put characters in transmit buffer.
  413. */
  414. cp = buffer;
  415. for (rc = 0; rc < len; cp++, rc++) {
  416. ch = pflg ? PRG_RDB(cp) : *cp;
  417. if (dcb->dcb_modeflags & LCD_MF_COOKEDMODE) {
  418. /* Process special characters. */
  419. if (dcb->dcb_ctlseq == 0) {
  420. /* Linefeed. */
  421. if (ch == 10) {
  422. dcb->dcb_col = 0;
  423. TermLinefeed(dcb);
  424. continue;
  425. }
  426. /* Carriage return. */
  427. if (ch == 13) {
  428. dcb->dcb_col = 0;
  429. (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols);
  430. continue;
  431. }
  432. /* Escape. */
  433. if (ch == 27) {
  434. dcb->dcb_ctlseq = 1;
  435. continue;
  436. }
  437. /* Backspace. */
  438. if (ch == 8) {
  439. if (dcb->dcb_col) {
  440. dcb->dcb_col--;
  441. TermDeleteChar(dcb, dcb->dcb_col);
  442. }
  443. continue;
  444. }
  445. /* Formfeed. */
  446. if (ch == 12) {
  447. TermClear(dcb);
  448. continue;
  449. }
  450. }
  451. /* Last character was ESC. */
  452. if (dcb->dcb_ctlseq == 1) {
  453. dcb->dcb_ctlseq = 0;
  454. switch (ch) {
  455. /* Insert space. */
  456. case '@':
  457. TermInsertSpace(dcb);
  458. break;
  459. /* Cursor up. */
  460. case 'A':
  461. TermCursorUp(dcb);
  462. break;
  463. /* Cursor down. */
  464. case 'B':
  465. if (++dcb->dcb_row >= dcb->dcb_nrows)
  466. dcb->dcb_row = dcb->dcb_nrows - 1;
  467. else
  468. (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
  469. break;
  470. /* Cursor right. */
  471. case 'C':
  472. TermCursorRight(dcb);
  473. break;
  474. /* Cursor left. */
  475. case 'D':
  476. TermCursorLeft(dcb);
  477. break;
  478. /* Clear screen and cursor home. */
  479. case 'E':
  480. TermClear(dcb);
  481. break;
  482. /* Cursor home. */
  483. case 'H':
  484. dcb->dcb_col = 0;
  485. dcb->dcb_row = 0;
  486. (*dcb->dss_cursor_home) ();
  487. break;
  488. /* Reverse linefeed. */
  489. case 'I':
  490. TermReverseLinefeed(dcb);
  491. break;
  492. /* Erase to end of screen. */
  493. case 'J':
  494. TermEraseEnd(dcb);
  495. break;
  496. /* Erase to end of line. */
  497. case 'K':
  498. TermEraseLineEnd(dcb, dcb->dcb_col);
  499. break;
  500. /* Insert line. */
  501. case 'L':
  502. TermInsertLine(dcb, dcb->dcb_row);
  503. break;
  504. /* Delete line. */
  505. case 'M':
  506. TermDeleteLine(dcb, dcb->dcb_row);
  507. break;
  508. /* Delete character. */
  509. case 'P':
  510. TermDeleteChar(dcb, dcb->dcb_col);
  511. break;
  512. /* Cursor position. */
  513. case 'Y':
  514. dcb->dcb_ctlseq = 2;
  515. break;
  516. /* Identify. */
  517. case 'Z':
  518. TermIdentify(dcb);
  519. break;
  520. /* Cursor on. */
  521. case 'e':
  522. dcb->dcb_modeflags |= LCD_MF_CURSORON;
  523. (*dcb->dss_cursor_mode) (1);
  524. break;
  525. /* Cursor off. */
  526. case 'f':
  527. dcb->dcb_modeflags &= ~LCD_MF_CURSORON;
  528. (*dcb->dss_cursor_mode) (0);
  529. break;
  530. /* Erase to start of screen. */
  531. case 'd':
  532. TermEraseStart(dcb);
  533. break;
  534. /* Erase to start of line. */
  535. case 'o':
  536. TermEraseLineStart(dcb);
  537. break;
  538. case 'i':
  539. dcb->dcb_modeflags |= LCD_MF_INVERTED;
  540. (*dcb->dss_cursor_mode) (3);
  541. break;
  542. case 'n':
  543. dcb->dcb_modeflags &= ~LCD_MF_INVERTED;
  544. (*dcb->dss_cursor_mode) (2);
  545. break;
  546. }
  547. continue;
  548. }
  549. /* Receive cursor row position. */
  550. if (dcb->dcb_ctlseq == 2) {
  551. dcb->dcb_ctlseq = 3;
  552. if (ch < 32)
  553. dcb->dcb_row = 0;
  554. else if (ch - 32 >= dcb->dcb_nrows)
  555. dcb->dcb_row = dcb->dcb_nrows - 1;
  556. else
  557. dcb->dcb_row = ch - 32;
  558. continue;
  559. }
  560. /* Receive cursor column position. */
  561. if (dcb->dcb_ctlseq == 3) {
  562. dcb->dcb_ctlseq = 0;
  563. if (ch < 32)
  564. dcb->dcb_col = 0;
  565. else if (ch - 32 >= dcb->dcb_vcols)
  566. dcb->dcb_col = dcb->dcb_vcols - 1;
  567. else
  568. dcb->dcb_col = ch - 32;
  569. (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
  570. continue;
  571. }
  572. }
  573. /*
  574. * Send any character to the LCD driver, which had been left
  575. * unprocessed upto this point.
  576. */
  577. (*dcb->dss_write) (ch);
  578. if (dcb->dcb_modeflags & LCD_MF_COOKEDMODE) {
  579. /* Update shadow memory. */
  580. *(dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols + dcb->dcb_col) = ch;
  581. /* step cursor forward */
  582. if (++dcb->dcb_col >= dcb->dcb_vcols) {
  583. if( dcb->dcb_modeflags & LCD_MF_AUTOLF) {
  584. dcb->dcb_col = 0;
  585. if( dcb->dcb_row < dcb->dcb_nrows) dcb->dcb_row++;
  586. }
  587. else
  588. dcb->dcb_col = dcb->dcb_vcols - 1;
  589. (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
  590. }
  591. }
  592. }
  593. return rc;
  594. }
  595. /*!
  596. * \brief Write data to a terminal device.
  597. *
  598. * Application should not call this function directly, but use the
  599. * stdio interface.
  600. *
  601. * The data may contain special character sequences, which are interpreted
  602. * by the terminal device to control specific display functions:
  603. * - Ctrl-H (ASCII 8) Backspace
  604. * - Ctrl-J (ASCII 10) Linefeed
  605. * - Ctrl-L (ASCII 12) Formfeed
  606. * - Ctrl-M (ASCII 13) Carriage return
  607. *
  608. * In addition a superset of VT52 control sequences are interpreted. Each
  609. * sequence starts with an ESC character (ASCII 27):
  610. * - ESC @ Insert space(*).
  611. * - ESC A Move cursor up, ignored if on first line.
  612. * - ESC B Move cursor down, ignored if on last line.
  613. * - ESC C Move cursor right, ignored if on last column.
  614. * - ESC D Move cursor left, ignored if on first column.
  615. * - ESC E Clear display and move cursor home (*).
  616. * - ESC H Move cursor home.
  617. * - ESC I Reverse linefeed.
  618. * - ESC J Erase to end of display.
  619. * - ESC K Erase to end of line.
  620. * - ESC L Insert line (*).
  621. * - ESC M Delete line (*).
  622. * - ESC P Delete character (*).
  623. * - ESC R Reactivate display (*).
  624. * - ESC S Put display in sleep mode (*).
  625. * - ESC Y x+32 y+32 Move cursor to position.
  626. * - ESC e Cursor on (*).
  627. * - ESC f Cursor off (*).
  628. * - ESC d Erase to start of display (*).
  629. * - ESC o Erase to start of line (*).
  630. *
  631. * (*) Not a VT52 command.
  632. *
  633. * \param fp File pointer to a previously opened device.
  634. * \param buffer Pointer to the data bytes to be written.
  635. * \param len Number of bytes to write.
  636. *
  637. * \return The number of bytes written.
  638. *
  639. * \todo TAB should be interpreted.
  640. *
  641. * \bug Switching from graphic mode back to text mode will not work,
  642. * because all escape sequences are ignored as soon as the graphic
  643. * mode has been enabled. Applications should use _ioctl()
  644. * functions to switch modes.
  645. */
  646. int TermWrite(NUTFILE * fp, const void *buffer, int len)
  647. {
  648. return TermPut(fp->nf_dev, buffer, len, 0);
  649. }
  650. /*!
  651. * \brief Write data from program space to a terminal device.
  652. *
  653. * Similar to TermWrite() except that the data is located in program memory.
  654. *
  655. * Application should not call this function directly, but use the
  656. * stdio interface.
  657. *
  658. * \param fp File pointer to a previously opened device.
  659. * \param buffer Pointer to the data bytes in program space to be written.
  660. * \param len Number of bytes to write.
  661. *
  662. * \return The number of bytes written.
  663. */
  664. #ifdef __HARVARD_ARCH__
  665. int TermWrite_P(NUTFILE * fp, PGM_P buffer, int len)
  666. {
  667. return TermPut(fp->nf_dev, (const char *) buffer, len, 1);
  668. }
  669. #endif
  670. /*!
  671. * \brief Open a terminal device.
  672. *
  673. * Application should not call this function directly, but use the
  674. * stdio interface.
  675. *
  676. * \param dev Pointer to device information structure.
  677. * \param name Filename. Not used with terminal devices.
  678. * \param mode Operation mode. May be any of the following:
  679. * - _O_BINARY Raw mode, no control character
  680. * interpretation.
  681. * - _O_TEXT Text mode. Control characters are
  682. * interpreted and tranlated to LCD commands.
  683. * \param acc Access mode. Not used with terminal devices.
  684. *
  685. * \return Pointer to a NUTFILE structure or –1 to indicate an error.
  686. */
  687. NUTFILE *TermOpen(NUTDEVICE * dev, const char *name, int mode, int acc)
  688. {
  689. TERMDCB *dcb = dev->dev_dcb;
  690. NUTFILE *fp = malloc(sizeof(NUTFILE));
  691. if (fp == 0)
  692. return NUTFILE_EOF;
  693. if (mode & _O_BINARY)
  694. dcb->dcb_modeflags &= ~LCD_MF_COOKEDMODE;
  695. else
  696. dcb->dcb_modeflags |= LCD_MF_COOKEDMODE;
  697. fp->nf_dev = dev;
  698. fp->nf_fcb = NULL;
  699. return fp;
  700. }
  701. /*!
  702. * \brief Close a device or file.
  703. *
  704. * Application should not call this function directly, but use the
  705. * stdio interface.
  706. *
  707. * \param fp Pointer to a previously opened NUTFILE structure.
  708. *
  709. * \return 0 if the device was successfully closed or –1 to indicate an error.
  710. */
  711. int TermClose(NUTFILE * fp)
  712. {
  713. if (fp && fp != NUTFILE_EOF) {
  714. free(fp);
  715. return 0;
  716. }
  717. return -1;
  718. }
  719. /*@}*/