00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 #include <dev/term.h>
00076
00077 #include <stdlib.h>
00078 #include <string.h>
00079 #include <fcntl.h>
00080 #include <memdebug.h>
00081
00087
00088 static prog_char termid[] = "Term 1.0";
00089
00090 static void TermRefreshLineEnd(CONST TERMDCB * dcb, uint8_t row, uint8_t col)
00091 {
00092 uint8_t i = col;
00093 uint8_t *cp = dcb->dcb_smem + row * dcb->dcb_vcols + col;
00094
00095
00096 if (dcb->dcb_modeflags & LCD_MF_CURSORON)
00097 (*dcb->dss_cursor_mode) (0);
00098
00099
00100 (*dcb->dss_set_cursor) (row * dcb->dcb_ncols + col);
00101
00102
00103
00104
00105
00106 for (;;) {
00107 if (i++ >= dcb->dcb_vcols)
00108 break;
00109 (*dcb->dss_write) (*cp++);
00110 }
00111
00112
00113 if (dcb->dcb_modeflags & LCD_MF_CURSORON)
00114 (*dcb->dss_cursor_mode) (1);
00115 }
00116
00117 void TermRefresh(TERMDCB * dcb)
00118 {
00119 uint8_t ir;
00120
00121 for (ir = 0; ir < dcb->dcb_nrows; ir++)
00122 TermRefreshLineEnd(dcb, ir, 0);
00123 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
00124 }
00125
00126 static void TermClear(TERMDCB * dcb)
00127 {
00128 memset(dcb->dcb_smem, ' ', dcb->dcb_vcols * dcb->dcb_nrows);
00129 dcb->dcb_col = 0;
00130 dcb->dcb_row = 0;
00131 (*dcb->dss_clear) ();
00132 }
00133
00134 static void TermDeleteLine(TERMDCB * dcb, uint8_t row)
00135 {
00136 uint8_t i;
00137 uint8_t *dcp;
00138
00139 for (i = row; i < dcb->dcb_nrows - 1; i++) {
00140 dcp = dcb->dcb_smem + i * dcb->dcb_vcols;
00141 memcpy(dcp, dcp + dcb->dcb_vcols, dcb->dcb_vcols);
00142 }
00143 memset(dcb->dcb_smem + (dcb->dcb_nrows - 1) * dcb->dcb_vcols, ' ', dcb->dcb_vcols);
00144 TermRefresh(dcb);
00145 }
00146
00147 static void TermInsertLine(TERMDCB * dcb, uint8_t row)
00148 {
00149 uint8_t i;
00150 uint8_t *dcp;
00151
00152 for (i = dcb->dcb_nrows - 1; i > row; i--) {
00153 dcp = dcb->dcb_smem + i * dcb->dcb_vcols;
00154 memcpy(dcp, dcp - dcb->dcb_vcols, dcb->dcb_vcols);
00155 }
00156 memset(dcb->dcb_smem + row * dcb->dcb_vcols, ' ', dcb->dcb_vcols);
00157 TermRefresh(dcb);
00158 }
00159
00160 static void TermCursorLeft(TERMDCB * dcb)
00161 {
00162 if (dcb->dcb_col) {
00163 (*dcb->dss_cursor_left) ();
00164 dcb->dcb_col--;
00165 }
00166 }
00167
00168 static void TermCursorRight(TERMDCB * dcb)
00169 {
00170 if (++dcb->dcb_col < dcb->dcb_vcols)
00171 (*dcb->dss_cursor_right) ();
00172 else
00173 dcb->dcb_col = dcb->dcb_vcols - 1;
00174 }
00175
00176 static void TermCursorUp(TERMDCB * dcb)
00177 {
00178 if (dcb->dcb_row) {
00179 dcb->dcb_row--;
00180 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
00181 }
00182 }
00183
00184 static void TermLinefeed(TERMDCB * dcb)
00185 {
00186 if (++dcb->dcb_row >= dcb->dcb_nrows) {
00187 dcb->dcb_row = dcb->dcb_nrows - 1;
00188 TermDeleteLine(dcb, 0);
00189 } else
00190 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
00191 }
00192
00193 static void TermReverseLinefeed(TERMDCB * dcb)
00194 {
00195 if (dcb->dcb_row--)
00196 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
00197 else {
00198 dcb->dcb_row = 0;
00199 TermInsertLine(dcb, 0);
00200 }
00201 }
00202
00203 static void TermEraseLineEnd(TERMDCB * dcb, uint8_t col)
00204 {
00205 if (col < dcb->dcb_vcols) {
00206 memset(dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols + col, ' ', dcb->dcb_vcols - col);
00207 TermRefresh(dcb);
00208 }
00209 }
00210
00211 static void TermEraseEnd(TERMDCB * dcb)
00212 {
00213 uint8_t i;
00214
00215 if (dcb->dcb_col < dcb->dcb_vcols)
00216 memset(dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols + dcb->dcb_col, ' ', dcb->dcb_vcols - dcb->dcb_col);
00217 for (i = dcb->dcb_row + 1; i < dcb->dcb_nrows; i++)
00218 memset(dcb->dcb_smem + i * dcb->dcb_vcols, ' ', dcb->dcb_vcols);
00219 TermRefresh(dcb);
00220 }
00221
00222 static void TermEraseLineStart(TERMDCB * dcb)
00223 {
00224 if (dcb->dcb_col) {
00225 memset(dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols, ' ', dcb->dcb_col);
00226 TermRefresh(dcb);
00227 }
00228 }
00229
00230 static void TermEraseStart(TERMDCB * dcb)
00231 {
00232 uint8_t i;
00233
00234 if (dcb->dcb_col)
00235 memset(dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols, ' ', dcb->dcb_col);
00236 for (i = 0; i < dcb->dcb_row; i++)
00237 memset(dcb->dcb_smem + i * dcb->dcb_vcols, ' ', dcb->dcb_vcols);
00238 TermRefresh(dcb);
00239 }
00240
00241 static void TermDeleteChar(TERMDCB * dcb, uint8_t col)
00242 {
00243 uint8_t i;
00244 uint8_t *cp = dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols + col;
00245
00246 for (i = col; i < dcb->dcb_vcols - 1; i++, cp++)
00247 *cp = *(cp + 1);
00248 *cp = ' ';
00249 TermRefresh(dcb);
00250 }
00251
00252
00253
00254
00255 static void TermInsertSpace(TERMDCB * dcb)
00256 {
00257 uint8_t i;
00258 uint8_t *cp = dcb->dcb_smem + (dcb->dcb_row + 1) * dcb->dcb_vcols - 1;
00259
00260 for (i = dcb->dcb_col; i < dcb->dcb_vcols - 1; i++, cp--)
00261 *cp = *(cp - 1);
00262 *cp = ' ';
00263 TermRefreshLineEnd(dcb, dcb->dcb_row, dcb->dcb_col);
00264 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
00265 }
00266
00267
00268
00269
00270 static void TermIdentify(TERMDCB * dcb)
00271 {
00272 PGM_P pcp = termid;
00273
00274 TermClear(dcb);
00275 while (PRG_RDB(pcp)) {
00276 (*dcb->dss_write) (PRG_RDB(pcp));
00277 pcp++;
00278 }
00279 }
00280
00318 int TermIOCtl(NUTDEVICE * dev, int req, void *conf)
00319 {
00320 TERMDCB *dcb = dev->dev_dcb;
00321 uint16_t usv;
00322 uint32_t ulv;
00323 WINSIZE *win_size;
00324
00325 switch (req) {
00326 case LCD_CMDBYTE:
00327 (*dcb->dss_command) (*(uint8_t *)conf, 10);
00328 break;
00329 case LCD_CMDWORD16:
00330 usv = *(uint16_t *)conf;
00331 (*dcb->dss_command) ((uint8_t)(usv >> 8), 10);
00332 (*dcb->dss_command) ((uint8_t)usv, 10);
00333 break;
00334 case LCD_CMDWORD32:
00335 ulv = *(uint32_t *)conf;
00336 (*dcb->dss_command) ((uint8_t)(ulv >> 24), 10);
00337 (*dcb->dss_command) ((uint8_t)(ulv >> 16), 10);
00338 (*dcb->dss_command) ((uint8_t)(ulv >> 8), 10);
00339 (*dcb->dss_command) ((uint8_t)ulv, 10);
00340 break;
00341 case LCD_DATABYTE:
00342 (*dcb->dss_write) (*(uint8_t *)conf);
00343 break;
00344 case LCD_DATAWORD16:
00345 usv = *(uint16_t *)conf;
00346 (*dcb->dss_write) ((uint8_t)(usv >> 8));
00347 (*dcb->dss_write) ((uint8_t)usv);
00348 break;
00349 case LCD_DATAWORD32:
00350 ulv = *(uint32_t *)conf;
00351 (*dcb->dss_write) ((uint8_t)(ulv >> 24));
00352 (*dcb->dss_write) ((uint8_t)(ulv >> 16));
00353 (*dcb->dss_write) ((uint8_t)(ulv >> 8));
00354 (*dcb->dss_write) ((uint8_t)ulv);
00355 break;
00356 case LCD_SETCOOKEDMODE:
00357 if (*(uint32_t *)conf)
00358 dcb->dcb_modeflags |= LCD_MF_COOKEDMODE;
00359 else
00360 dcb->dcb_modeflags &= ~LCD_MF_COOKEDMODE;
00361 break;
00362 case LCD_GETCOOKEDMODE:
00363 if (dcb->dcb_modeflags & LCD_MF_COOKEDMODE)
00364 *(uint32_t *)conf = 1;
00365 else
00366 *(uint32_t *)conf = 0;
00367 break;
00368
00369 case LCD_SET_AUTOLF:
00370 if (*(uint32_t *)conf)
00371 dcb->dcb_modeflags |= LCD_MF_AUTOLF;
00372 else
00373 dcb->dcb_modeflags &= ~LCD_MF_AUTOLF;
00374 break;
00375 case LCD_GET_AUTOLF:
00376 if (dcb->dcb_modeflags & LCD_MF_AUTOLF)
00377 *(uint32_t *)conf = 1;
00378 else
00379 *(uint32_t *)conf = 0;
00380 break;
00381
00382 case TIOCGWINSZ:
00383 win_size = (WINSIZE *)conf;
00384 win_size->ws_col = dcb->dcb_nrows;
00385 win_size->ws_row = dcb->dcb_vcols;
00386 win_size->ws_xpixel = 0;
00387 win_size->ws_ypixel = 0;
00388 break;
00389 }
00390 return 0;
00391 }
00392
00393
00406 int TermInit(NUTDEVICE * dev)
00407 {
00408 TERMDCB *dcb = dev->dev_dcb;
00409
00410
00411
00412
00413 if( dcb->dss_init != NULL) {
00414
00415
00416
00417 if( dcb->dss_init(dev) != 0) {
00418 return -1;
00419 }
00420 }
00421
00422
00423
00424 dcb->dcb_smem = malloc(dcb->dcb_nrows * dcb->dcb_vcols);
00425 if( dcb->dcb_smem == NULL) {
00426 return -1;
00427 }
00428
00429 TermClear(dcb);
00430
00431 return 0;
00432 }
00433
00445 static int TermPut(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
00446 {
00447 int rc;
00448 CONST uint8_t *cp;
00449 uint8_t ch;
00450 TERMDCB *dcb = dev->dev_dcb;
00451
00452
00453
00454
00455 if (buffer == 0)
00456 return 0;
00457
00458
00459
00460
00461 cp = buffer;
00462 for (rc = 0; rc < len; cp++, rc++) {
00463 ch = pflg ? PRG_RDB(cp) : *cp;
00464
00465 if (dcb->dcb_modeflags & LCD_MF_COOKEDMODE) {
00466
00467 if (dcb->dcb_ctlseq == 0) {
00468
00469
00470 if (ch == 10) {
00471 dcb->dcb_col = 0;
00472 TermLinefeed(dcb);
00473 continue;
00474 }
00475
00476
00477 if (ch == 13) {
00478 dcb->dcb_col = 0;
00479 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols);
00480 continue;
00481 }
00482
00483
00484 if (ch == 27) {
00485 dcb->dcb_ctlseq = 1;
00486 continue;
00487 }
00488
00489
00490 if (ch == 8) {
00491 if (dcb->dcb_col) {
00492 dcb->dcb_col--;
00493 TermDeleteChar(dcb, dcb->dcb_col);
00494 }
00495 continue;
00496 }
00497
00498
00499 if (ch == 12) {
00500 TermClear(dcb);
00501 continue;
00502 }
00503 }
00504
00505
00506 if (dcb->dcb_ctlseq == 1) {
00507 dcb->dcb_ctlseq = 0;
00508
00509 switch (ch) {
00510
00511 case '@':
00512 TermInsertSpace(dcb);
00513 break;
00514
00515
00516 case 'A':
00517 TermCursorUp(dcb);
00518 break;
00519
00520
00521 case 'B':
00522 if (++dcb->dcb_row >= dcb->dcb_nrows)
00523 dcb->dcb_row = dcb->dcb_nrows - 1;
00524 else
00525 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
00526 break;
00527
00528
00529 case 'C':
00530 TermCursorRight(dcb);
00531 break;
00532
00533
00534 case 'D':
00535 TermCursorLeft(dcb);
00536 break;
00537
00538
00539 case 'E':
00540 TermClear(dcb);
00541 break;
00542
00543
00544 case 'H':
00545 dcb->dcb_col = 0;
00546 dcb->dcb_row = 0;
00547 (*dcb->dss_cursor_home) ();
00548 break;
00549
00550
00551 case 'I':
00552 TermReverseLinefeed(dcb);
00553 break;
00554
00555
00556 case 'J':
00557 TermEraseEnd(dcb);
00558 break;
00559
00560
00561 case 'K':
00562 TermEraseLineEnd(dcb, dcb->dcb_col);
00563 break;
00564
00565
00566 case 'L':
00567 TermInsertLine(dcb, dcb->dcb_row);
00568 break;
00569
00570
00571 case 'M':
00572 TermDeleteLine(dcb, dcb->dcb_row);
00573 break;
00574
00575
00576 case 'P':
00577 TermDeleteChar(dcb, dcb->dcb_col);
00578 break;
00579
00580
00581 case 'Y':
00582 dcb->dcb_ctlseq = 2;
00583 break;
00584
00585
00586 case 'Z':
00587 TermIdentify(dcb);
00588 break;
00589
00590
00591 case 'e':
00592 dcb->dcb_modeflags |= LCD_MF_CURSORON;
00593 (*dcb->dss_cursor_mode) (1);
00594 break;
00595
00596
00597 case 'f':
00598 dcb->dcb_modeflags &= ~LCD_MF_CURSORON;
00599 (*dcb->dss_cursor_mode) (0);
00600 break;
00601
00602
00603 case 'd':
00604 TermEraseStart(dcb);
00605 break;
00606
00607
00608 case 'o':
00609 TermEraseLineStart(dcb);
00610 break;
00611
00612 case 'i':
00613 dcb->dcb_modeflags |= LCD_MF_INVERTED;
00614 (*dcb->dss_cursor_mode) (3);
00615 break;
00616
00617 case 'n':
00618 dcb->dcb_modeflags &= ~LCD_MF_INVERTED;
00619 (*dcb->dss_cursor_mode) (2);
00620 break;
00621 }
00622 continue;
00623 }
00624
00625
00626 if (dcb->dcb_ctlseq == 2) {
00627 dcb->dcb_ctlseq = 3;
00628 if (ch < 32)
00629 dcb->dcb_row = 0;
00630 else if (ch - 32 >= dcb->dcb_nrows)
00631 dcb->dcb_row = dcb->dcb_nrows - 1;
00632 else
00633 dcb->dcb_row = ch - 32;
00634 continue;
00635 }
00636
00637
00638 if (dcb->dcb_ctlseq == 3) {
00639 dcb->dcb_ctlseq = 0;
00640 if (ch < 32)
00641 dcb->dcb_col = 0;
00642 else if (ch - 32 >= dcb->dcb_vcols)
00643 dcb->dcb_col = dcb->dcb_vcols - 1;
00644 else
00645 dcb->dcb_col = ch - 32;
00646 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
00647 continue;
00648 }
00649 }
00650
00651
00652
00653
00654
00655 (*dcb->dss_write) (ch);
00656
00657 if (dcb->dcb_modeflags & LCD_MF_COOKEDMODE) {
00658
00659 *(dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols + dcb->dcb_col) = ch;
00660
00661
00662 if (++dcb->dcb_col >= dcb->dcb_vcols) {
00663 if( dcb->dcb_modeflags & LCD_MF_AUTOLF) {
00664 dcb->dcb_col = 0;
00665 if( dcb->dcb_row < dcb->dcb_nrows) dcb->dcb_row++;
00666 }
00667 else
00668 dcb->dcb_col = dcb->dcb_vcols - 1;
00669 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
00670 }
00671 }
00672 }
00673 return rc;
00674 }
00675
00727 int TermWrite(NUTFILE * fp, CONST void *buffer, int len)
00728 {
00729 return TermPut(fp->nf_dev, buffer, len, 0);
00730 }
00731
00746 #ifdef __HARVARD_ARCH__
00747 int TermWrite_P(NUTFILE * fp, PGM_P buffer, int len)
00748 {
00749 return TermPut(fp->nf_dev, (CONST char *) buffer, len, 1);
00750 }
00751 #endif
00752
00770 NUTFILE *TermOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00771 {
00772 TERMDCB *dcb = dev->dev_dcb;
00773 NUTFILE *fp = malloc(sizeof(NUTFILE));
00774
00775 if (fp == 0)
00776 return NUTFILE_EOF;
00777
00778 if (mode & _O_BINARY)
00779 dcb->dcb_modeflags &= ~LCD_MF_COOKEDMODE;
00780 else
00781 dcb->dcb_modeflags |= LCD_MF_COOKEDMODE;
00782 fp->nf_next = 0;
00783 fp->nf_dev = dev;
00784 fp->nf_fcb = 0;
00785
00786 return fp;
00787 }
00788
00799 int TermClose(NUTFILE * fp)
00800 {
00801 if (fp && fp != NUTFILE_EOF) {
00802 free(fp);
00803 return 0;
00804 }
00805 return -1;
00806 }
00807