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 dcb->dss_init(dev);
00418 }
00419
00420
00421
00422 dcb->dcb_smem = malloc(dcb->dcb_nrows * dcb->dcb_vcols);
00423 if( dcb->dcb_smem == NULL) {
00424 return -1;
00425 }
00426
00427 TermClear(dcb);
00428
00429 return 0;
00430 }
00431
00443 static int TermPut(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
00444 {
00445 int rc;
00446 CONST uint8_t *cp;
00447 uint8_t ch;
00448 TERMDCB *dcb = dev->dev_dcb;
00449
00450
00451
00452
00453 if (buffer == 0)
00454 return 0;
00455
00456
00457
00458
00459 cp = buffer;
00460 for (rc = 0; rc < len; cp++, rc++) {
00461 ch = pflg ? PRG_RDB(cp) : *cp;
00462
00463 if (dcb->dcb_modeflags & LCD_MF_COOKEDMODE) {
00464
00465 if (dcb->dcb_ctlseq == 0) {
00466
00467
00468 if (ch == 10) {
00469 dcb->dcb_col = 0;
00470 TermLinefeed(dcb);
00471 continue;
00472 }
00473
00474
00475 if (ch == 13) {
00476 dcb->dcb_col = 0;
00477 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols);
00478 continue;
00479 }
00480
00481
00482 if (ch == 27) {
00483 dcb->dcb_ctlseq = 1;
00484 continue;
00485 }
00486
00487
00488 if (ch == 8) {
00489 if (dcb->dcb_col) {
00490 dcb->dcb_col--;
00491 TermDeleteChar(dcb, dcb->dcb_col);
00492 }
00493 continue;
00494 }
00495
00496
00497 if (ch == 12) {
00498 TermClear(dcb);
00499 continue;
00500 }
00501 }
00502
00503
00504 if (dcb->dcb_ctlseq == 1) {
00505 dcb->dcb_ctlseq = 0;
00506
00507 switch (ch) {
00508
00509 case '@':
00510 TermInsertSpace(dcb);
00511 break;
00512
00513
00514 case 'A':
00515 TermCursorUp(dcb);
00516 break;
00517
00518
00519 case 'B':
00520 if (++dcb->dcb_row >= dcb->dcb_nrows)
00521 dcb->dcb_row = dcb->dcb_nrows - 1;
00522 else
00523 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
00524 break;
00525
00526
00527 case 'C':
00528 TermCursorRight(dcb);
00529 break;
00530
00531
00532 case 'D':
00533 TermCursorLeft(dcb);
00534 break;
00535
00536
00537 case 'E':
00538 TermClear(dcb);
00539 break;
00540
00541
00542 case 'H':
00543 dcb->dcb_col = 0;
00544 dcb->dcb_row = 0;
00545 (*dcb->dss_cursor_home) ();
00546 break;
00547
00548
00549 case 'I':
00550 TermReverseLinefeed(dcb);
00551 break;
00552
00553
00554 case 'J':
00555 TermEraseEnd(dcb);
00556 break;
00557
00558
00559 case 'K':
00560 TermEraseLineEnd(dcb, dcb->dcb_col);
00561 break;
00562
00563
00564 case 'L':
00565 TermInsertLine(dcb, dcb->dcb_row);
00566 break;
00567
00568
00569 case 'M':
00570 TermDeleteLine(dcb, dcb->dcb_row);
00571 break;
00572
00573
00574 case 'P':
00575 TermDeleteChar(dcb, dcb->dcb_col);
00576 break;
00577
00578
00579 case 'Y':
00580 dcb->dcb_ctlseq = 2;
00581 break;
00582
00583
00584 case 'Z':
00585 TermIdentify(dcb);
00586 break;
00587
00588
00589 case 'e':
00590 dcb->dcb_modeflags |= LCD_MF_CURSORON;
00591 (*dcb->dss_cursor_mode) (1);
00592 break;
00593
00594
00595 case 'f':
00596 dcb->dcb_modeflags &= ~LCD_MF_CURSORON;
00597 (*dcb->dss_cursor_mode) (0);
00598 break;
00599
00600
00601 case 'd':
00602 TermEraseStart(dcb);
00603 break;
00604
00605
00606 case 'o':
00607 TermEraseLineStart(dcb);
00608 break;
00609
00610 case 'i':
00611 dcb->dcb_modeflags |= LCD_MF_INVERTED;
00612 (*dcb->dss_cursor_mode) (3);
00613 break;
00614
00615 case 'n':
00616 dcb->dcb_modeflags &= ~LCD_MF_INVERTED;
00617 (*dcb->dss_cursor_mode) (2);
00618 break;
00619 }
00620 continue;
00621 }
00622
00623
00624 if (dcb->dcb_ctlseq == 2) {
00625 dcb->dcb_ctlseq = 3;
00626 if (ch < 32)
00627 dcb->dcb_row = 0;
00628 else if (ch - 32 >= dcb->dcb_nrows)
00629 dcb->dcb_row = dcb->dcb_nrows - 1;
00630 else
00631 dcb->dcb_row = ch - 32;
00632 continue;
00633 }
00634
00635
00636 if (dcb->dcb_ctlseq == 3) {
00637 dcb->dcb_ctlseq = 0;
00638 if (ch < 32)
00639 dcb->dcb_col = 0;
00640 else if (ch - 32 >= dcb->dcb_vcols)
00641 dcb->dcb_col = dcb->dcb_vcols - 1;
00642 else
00643 dcb->dcb_col = ch - 32;
00644 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
00645 continue;
00646 }
00647 }
00648
00649
00650
00651
00652
00653 (*dcb->dss_write) (ch);
00654
00655 if (dcb->dcb_modeflags & LCD_MF_COOKEDMODE) {
00656
00657 *(dcb->dcb_smem + dcb->dcb_row * dcb->dcb_vcols + dcb->dcb_col) = ch;
00658
00659
00660 if (++dcb->dcb_col >= dcb->dcb_vcols) {
00661 if( dcb->dcb_modeflags & LCD_MF_AUTOLF) {
00662 dcb->dcb_col = 0;
00663 if( dcb->dcb_row < dcb->dcb_nrows) dcb->dcb_row++;
00664 }
00665 else
00666 dcb->dcb_col = dcb->dcb_vcols - 1;
00667 (*dcb->dss_set_cursor) (dcb->dcb_row * dcb->dcb_ncols + dcb->dcb_col);
00668 }
00669 }
00670 }
00671 return rc;
00672 }
00673
00725 int TermWrite(NUTFILE * fp, CONST void *buffer, int len)
00726 {
00727 return TermPut(fp->nf_dev, buffer, len, 0);
00728 }
00729
00744 #ifdef __HARVARD_ARCH__
00745 int TermWrite_P(NUTFILE * fp, PGM_P buffer, int len)
00746 {
00747 return TermPut(fp->nf_dev, (CONST char *) buffer, len, 1);
00748 }
00749 #endif
00750
00768 NUTFILE *TermOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00769 {
00770 TERMDCB *dcb = dev->dev_dcb;
00771 NUTFILE *fp = malloc(sizeof(NUTFILE));
00772
00773 if (fp == 0)
00774 return NUTFILE_EOF;
00775
00776 if (mode & _O_BINARY)
00777 dcb->dcb_modeflags &= ~LCD_MF_COOKEDMODE;
00778 else
00779 dcb->dcb_modeflags |= LCD_MF_COOKEDMODE;
00780 fp->nf_next = 0;
00781 fp->nf_dev = dev;
00782 fp->nf_fcb = 0;
00783
00784 return fp;
00785 }
00786
00797 int TermClose(NUTFILE * fp)
00798 {
00799 if (fp && fp != NUTFILE_EOF) {
00800 free(fp);
00801 return 0;
00802 }
00803 return -1;
00804 }
00805