00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "terminal.h"
00024 #include "lock.h"
00025 #include "heap.h"
00026 #include <common/string.h>
00027 #include <common/mem.h>
00028 #include "device.h"
00029 #include "system.h"
00030 #include "dbgterm.h"
00031
00032 #if (__CONFIG_COMPILE_TERMINAL && __CONFIG_COMPILE_STRING)
00033
00047 #define __SK_BASE 0x1000
00048 #define __SK_UNKNOWN 0xFFFF
00049 #define __SK_ESCAPE __SK_BASE
00050 #define __SK_UPARROW __SK_BASE + 1
00051 #define __SK_DOWNARROW __SK_BASE + 2
00052 #define __SK_RIGHTARROW __SK_BASE + 3
00053 #define __SK_LEFTARROW __SK_BASE + 4
00054 #define __SK_BREAK __SK_BASE + 5
00055 #define __SK_INS __SK_BASE + 6
00056 #define __SK_HOME __SK_BASE + 7
00057 #define __SK_PGUP __SK_BASE + 8
00058 #define __SK_DEL __SK_BASE + 9
00059 #define __SK_END __SK_BASE + 10
00060 #define __SK_PGDN __SK_BASE + 11
00061 #define __SK_F1 __SK_BASE + 12
00062 #define __SK_F2 __SK_BASE + 13
00063 #define __SK_F3 __SK_BASE + 14
00064 #define __SK_F4 __SK_BASE + 15
00065 #define __SK_F5 __SK_BASE + 16
00066 #define __SK_F6 __SK_BASE + 17
00067 #define __SK_F7 __SK_BASE + 18
00068 #define __SK_F8 __SK_BASE + 19
00069 #define __SK_F9 __SK_BASE + 20
00070 #define __SK_F10 __SK_BASE + 21
00071 #define __SK_F11 __SK_BASE + 22
00072 #define __SK_F12 __SK_BASE + 23
00073 #define __TERMINAL_PROMPT "milos> "
00074
00084 __CONST __STRING __terminalESC[] = {0x1b, 0x5b};
00085 __CONST __STRING __terminalBackspace[] = {0x1b, 0x5b, '1', 'D', 0x1b, 0x5b, '0', 'K', 0x00};
00086 __CONST __STRING __terminalClearScreen[] = {0x1b, 0x5b, '2', 'J', 0x00};
00087 __CONST __STRING __terminalShowCursor[] = {0x1b, 0x5b, '?', '2', '5', 'h', 0x00};
00088 __CONST __STRING __terminalHideCursor[] = {0x1b, 0x5b, '?', '2', '5', 'l', 0x00};
00089
00090 #if __CONFIG_COMPILE_DBGTERM
00091
00092 __TERMINALCMD __dbgCommands[] = {
00093 { "heap", __dbgTerminalIn, __NULL},
00094 { "locks", __dbgTerminalIn, __NULL},
00095 { "threads", __dbgTerminalIn, __NULL},
00096 { "reset", __dbgTerminalIn, __NULL},
00097 { "uptime", __dbgTerminalIn, __NULL},
00098 { "devices", __dbgTerminalIn, __NULL},
00099 { "defrag", __dbgTerminalIn, __NULL},
00100
00101 #if __CONFIG_COMPILE_FAT
00102 { "dir", __dbgTerminalIn, __NULL},
00103 #endif
00104
00105 #if __CONFIG_COMPILE_NET
00106 { "ping", __dbgTerminalIn, __NULL},
00107 { "arp", __dbgTerminalIn, __NULL},
00108 { "netif", __dbgTerminalIn, __NULL}
00109 #endif
00110 };
00111
00112 #endif
00113
00131 __STATIC __VOID __terminalBack(__PTERMINAL term, u8 qty)
00132 {
00133 __STRING num[4];
00134 __STRING buf[sizeof(num) + 5];
00135 u8 len;
00136
00137 __strFmt(num, "%u", qty);
00138 len = __strLen(num);
00139
00140 buf[0] = __terminalESC[0];
00141 buf[1] = __terminalESC[1];
00142 __memCpy(buf+2, num, len);
00143 buf[2+len] = 'D';
00144 buf[3+len] = 0x00;
00145
00146 __terminalWrite(term, buf);
00147 }
00148
00157 __STATIC __VOID __terminalFoward(__PTERMINAL term, u8 qty)
00158 {
00159 __STRING num[4];
00160 __STRING buf[sizeof(num) + 5];
00161 u8 len;
00162
00163 __strFmt(num, "%u", qty);
00164 len = __strLen(num);
00165
00166 buf[0] = __terminalESC[0];
00167 buf[1] = __terminalESC[1];
00168 __memCpy(buf+2, num, len);
00169 buf[2+len] = 'C';
00170 buf[3+len] = 0x00;
00171
00172 __terminalWrite(term, buf);
00173 }
00174
00183 __STATIC __VOID __terminalShowPrompt(__PTERMINAL term)
00184 {
00185 if (__lockOwn(term->lock, 1000))
00186 {
00187 __deviceWrite(term->dv_out, term->prompt, __strLen(term->prompt));
00188 __deviceFlush(term->dv_out);
00189 __lockRelease(term->lock);
00190 }
00191 }
00192
00204 __STATIC u16 __terminalParseEscaped(__PTERMINAL term)
00205 {
00206 u8 a = 0;
00207 u8 b = 0;
00208 u8 c = 0;
00209 u8 d = 0;
00210
00211
00212 if (__deviceRead(term->dv_in, &a, 1) == 1)
00213 {
00214
00215 if (a != 0x5b)
00216 {
00217 return a;
00218 }
00219 } else
00220 {
00221 return __SK_ESCAPE;
00222 }
00223
00224
00225 if (__deviceRead(term->dv_in, &b, 1) == 1)
00226 {
00227 switch (b) {
00228
00229 case 0x41:
00230 return __SK_UPARROW;
00231 case 0x42:
00232 return __SK_DOWNARROW;
00233 case 0x43:
00234 return __SK_RIGHTARROW;
00235 case 0x44:
00236 return __SK_LEFTARROW;
00237
00238
00239 case 0x50:
00240 return __SK_BREAK;
00241
00242
00243
00244 case 0x5b:
00245 case 0x31:
00246 case 0x32:
00247 case 0x33:
00248 case 0x35:
00249 case 0x36:
00250 case 0x37:
00251 break;
00252 default:
00253 return __SK_UNKNOWN;
00254 }
00255
00256 if (__deviceRead(term->dv_in, &c, 1) == 1)
00257 {
00258
00259 if (c == 0x7e) {
00260 switch (b) {
00261 case 0x31:
00262 return __SK_HOME;
00263 case 0x32:
00264 return __SK_INS;
00265 case 0x33:
00266 return __SK_DEL;
00267 case 0x34:
00268 return __SK_END;
00269 case 0x35:
00270 return __SK_PGUP;
00271 case 0x36:
00272 return __SK_PGDN;
00273 default:
00274 return __SK_UNKNOWN;
00275 }
00276 }
00277
00278 if (b != 0x31 && b != 0x32) return __SK_UNKNOWN;
00279
00280
00281 if (__deviceRead(term->dv_in, &d, 1) == 1)
00282 {
00283 if (d != 0x7e) return __SK_UNKNOWN;
00284
00285 switch (b) {
00286 case 0x31:
00287 switch (c) {
00288 case 0x31:
00289 return __SK_F1;
00290 case 0x32:
00291 return __SK_F2;
00292 case 0x33:
00293 return __SK_F3;
00294 case 0x34:
00295 return __SK_F4;
00296 case 0x35:
00297 return __SK_F5;
00298 case 0x37:
00299 return __SK_F6;
00300 case 0x38:
00301 return __SK_F7;
00302 case 0x39:
00303 return __SK_F8;
00304 }
00305 return __SK_UNKNOWN;
00306
00307 case 0x32:
00308 switch (c) {
00309 case 0x30:
00310 return __SK_F9;
00311 case 0x31:
00312 return __SK_F10;
00313 case 0x33:
00314 return __SK_F11;
00315 case 0x34:
00316 return __SK_F12;
00317 }
00318 return __SK_UNKNOWN;
00319
00320 default:
00321 return __SK_UNKNOWN;
00322 }
00323 }
00324 }
00325 }
00326
00327 return __SK_UNKNOWN;
00328 }
00329
00339 __STATIC __BOOL __terminalParseSpecial(__PTERMINAL term, u16 code) {
00340
00341 if (code == __SK_UNKNOWN) return __FALSE;
00342
00343 switch (code)
00344 {
00345 case __SK_LEFTARROW: if (term->cursor)
00346 {
00347 __terminalBack(term, 1);
00348
00349 term->cursor--;
00350 }
00351 break;
00352
00353 case __SK_RIGHTARROW: if (__strLen(term->rx_line) > term->cursor)
00354 {
00355 __terminalFoward(term, '1');
00356
00357
00358 term->cursor++;
00359 }
00360 break;
00361
00362 case __SK_UPARROW:
00363 break;
00364
00365 case __SK_END:
00366 __terminalWrite(term, __terminalHideCursor);
00367
00368
00369 __terminalBack(term, term->cursor);
00370
00371 term->cursor = 0;
00372
00373
00374 __terminalWrite(term, __terminalShowCursor);
00375 break;
00376
00377 case __SK_HOME: if (term->cursor == __strLen(term->rx_line)) break;
00378
00379
00380 __terminalWrite(term, __terminalHideCursor);
00381
00382
00383 __terminalFoward(term, __strLen(term->rx_line) - term->cursor);
00384
00385 term->cursor = __strLen(term->rx_line);
00386
00387
00388 __terminalWrite(term, __terminalShowCursor);
00389 break;
00390 }
00391
00392 return __FALSE;
00393
00394 }
00395
00405 __STATIC __VOID __terminalWriteChar(__PTERMINAL term, u8 c)
00406 {
00407 if (!(term->flags & __TERMINAL_STARTED)) return;
00408
00409 if (__lockOwn(term->lock, 1000)) {
00410 __deviceWrite(term->dv_out, &c, 1);
00411 __deviceFlush(term->dv_out);
00412 __lockRelease(term->lock);
00413 }
00414 }
00415
00425 __STATIC __BOOL __terminalReadLine(__PTERMINAL term)
00426 {
00427 u16 size = 0;
00428 u8 c = 0;
00429 u8 ret = 0;
00430 u8 echo;
00431 u8 save;
00432 u8 i = 0;
00433 u8 print = 0;
00434
00435 for (;;)
00436 {
00437 size = __deviceSize(term->dv_in, __DEV_RXSIZE);
00438 while (size > 0)
00439 {
00440 if (__deviceRead(term->dv_in, &c, 1) == 1)
00441 {
00442 size--;
00443
00444 echo = __FALSE;
00445 save = __TRUE;
00446 ret = __FALSE;
00447
00448
00449 switch (c) {
00450
00451
00452 case 0x1b:
00453 save = __FALSE;
00454 echo = __terminalParseSpecial(term, __terminalParseEscaped(term));
00455
00456
00457 size = __deviceSize(term->dv_in, __DEV_RXSIZE);
00458 break;
00459
00460
00461 case 0x09:
00462 save = __FALSE;
00463 echo = __FALSE;
00464 break;
00465
00466
00467 case 0x08:
00468 save = __FALSE;
00469 echo = __FALSE;
00470
00471 if (!term->rxoffs) break;
00472 if (!term->cursor) break;
00473
00474
00475 if (term->cursor < term->rxoffs)
00476 {
00477 for (i = term->cursor; i < term->rxoffs; i++)
00478 {
00479 term->rx_line[i-1] = term->rx_line[i];
00480 }
00481
00482 print = __TRUE;
00483 }
00484
00485 term->rxoffs--;
00486 term->cursor--;
00487
00488 term->rx_line[term->rxoffs] = 0;
00489
00490 if (print)
00491 {
00492
00493 __terminalWrite(term, __terminalHideCursor);
00494
00495
00496 __terminalWrite(term, __terminalBackspace);
00497
00498
00499 __terminalWrite(term, term->rx_line + term->cursor);
00500
00501
00502 __terminalBack(term, term->rxoffs - term->cursor);
00503
00504
00505 __terminalWrite(term, __terminalShowCursor);
00506 } else
00507 {
00508
00509 __terminalWrite(term, __terminalBackspace);
00510 }
00511 break;
00512
00513
00514 case 0x0D:
00515 save = __FALSE;
00516 echo = __FALSE;
00517
00518
00519 __terminalWrite(term, "\r\n");
00520 ret = __TRUE;
00521 break;
00522
00523
00524 case 0x0A:
00525 save = __FALSE;
00526 break;
00527
00528 default:
00529 echo = __TRUE;
00530 break;
00531 }
00532
00533
00534 if (save) {
00535
00536 if (term->rxoffs < term->linelen-1)
00537 {
00538 print = __FALSE;
00539
00540
00541 if (term->cursor < term->rxoffs)
00542 {
00543 for (i = term->linelen - 1; i > term->cursor; i--)
00544 {
00545 term->rx_line[i] = term->rx_line[i-1];
00546 }
00547
00548 print = __TRUE;
00549 }
00550
00551 term->rx_line[term->cursor] = c;
00552
00553
00554 term->rxoffs++;
00555
00556
00557 term->cursor++;
00558
00559
00560 term->rx_line[term->linelen - 1] = 0;
00561
00562 if (print)
00563 {
00564
00565 __terminalWrite(term, __terminalHideCursor);
00566
00567 __terminalWrite(term, term->rx_line + term->cursor - 1);
00568
00569
00570 __terminalBack(term, term->rxoffs - term->cursor);
00571
00572
00573 __terminalWrite(term, __terminalShowCursor);
00574 echo = __FALSE;
00575 }
00576 } else
00577 {
00578 echo = __FALSE;
00579 }
00580 }
00581
00582
00583 if (echo && (term->flags & __TERMINAL_ECHO_ENABLED))
00584 {
00585 __terminalWriteChar(term, c);
00586 }
00587
00588
00589 if (ret)
00590 {
00591 term->rxoffs = 0;
00592 term->cursor = 0;
00593 return __TRUE;
00594 }
00595 }
00596 }
00597
00598 __threadSleep(1);
00599 }
00600
00601 return __FALSE;
00602 }
00603
00611 __VOID __terminalThread(__VOID)
00612 {
00613 __PTERMINALCMD commands;
00614 __PSTRING str;
00615 __BOOL bKnown = __FALSE;
00616 __PTERMINAL term = __threadGetParameter();
00617
00618 __terminalWriteLine(term, "\r\n\r\n");
00619
00620 __terminalWriteLine(term, "\r\nMilos v3 - Terminal Ready\r\n");
00621 __terminalShowPrompt(term);
00622
00623 for (;;)
00624 {
00625 __memSet(term->rx_line, 0, term->linelen);
00626 if (__terminalReadLine(term))
00627 {
00628 if (__strLen(term->rx_line))
00629 {
00630
00631 commands = term->cmds;
00632 bKnown = __FALSE;
00633
00634
00635 str = __strChr(term->rx_line, 0x20);
00636
00637 while (commands && !bKnown)
00638 {
00639 if (str)
00640 {
00641 if (__strnCmp(term->rx_line, commands->cmd, (u16) (str - term->rx_line)) == 0)
00642 {
00643 if (commands->func) (commands->func) (term, term->rx_line, str);
00644 bKnown = __TRUE;
00645 }
00646
00647 } else {
00648
00649 if (__strCmp(term->rx_line, commands->cmd) == 0)
00650 {
00651 if (commands->func) (commands->func) (term, term->rx_line, __NULL);
00652 bKnown = __TRUE;
00653 }
00654 }
00655
00656 commands = commands->next;
00657 }
00658
00659
00660 if (bKnown == __FALSE)
00661 {
00662 __terminalWriteLine(term, "Unknown Command\r\n");
00663 }
00664 }
00665
00666 __terminalShowPrompt(term);
00667 }
00668
00669 __threadSleep(1);
00670 }
00671 }
00672
00681 __BOOL __terminalStart(__PTERMINAL term)
00682 {
00683
00684 if (term->flags & __TERMINAL_STARTED) return __FALSE;
00685
00686
00687 if (!term->dv_in && !term->dv_out) return __FALSE;
00688
00689
00690 if (term->dv_in)
00691 {
00692 if (!term->dv_in->dv_initd || !term->dv_in->dv_opcnt) return __FALSE;
00693 }
00694
00695 if (term->dv_out)
00696 {
00697 if (!term->dv_out->dv_initd || !term->dv_out->dv_opcnt) return __FALSE;
00698 }
00699
00700 term->flags |= __TERMINAL_STARTED;
00701
00702
00703 if (term->dv_in)
00704 {
00705 __threadCreate(term->name, __terminalThread, __CONFIG_PRIO_TERMTHREAD, 1024, 1, term);
00706 }
00707
00708 return __TRUE;
00709 }
00710
00724 __VOID __terminalWriteLine(__PTERMINAL term, __CONST __PSTRING str, ...)
00725 {
00726 __PSTRING args = ((__PSTRING) &str) + sizeof(__PSTRING);
00727 __terminalOut(term, __TRUE, str, args);
00728 }
00729
00743 __VOID __terminalWrite(__PTERMINAL term, __CONST __PSTRING str, ...)
00744 {
00745 __PSTRING args = ((__PSTRING) &str) + sizeof(__PSTRING);
00746 __terminalOut(term, __FALSE, str, args);
00747 }
00748
00749 __VOID __terminalOut(__PTERMINAL term, __BOOL crlf, __CONST __PSTRING str, __PSTRING args)
00750 {
00751 if (!(term->flags & __TERMINAL_STARTED)) return;
00752
00753 if (__strLen(str) >= term->linelen) return;
00754
00755 if (__lockOwn(term->lock, 1000))
00756 {
00757 if (args)
00758 {
00759 __strFmtEx(term->tx_line, str, args);
00760 } else {
00761 __strCpy(term->tx_line, str);
00762 }
00763
00764 __deviceWrite(term->dv_out, term->tx_line, __strLen(term->tx_line));
00765
00766 if (crlf)
00767 {
00768 __deviceWrite(term->dv_out, "\r\n", 2);
00769 }
00770
00771 __deviceFlush(term->dv_out);
00772 __lockRelease(term->lock);
00773 }
00774 }
00775
00776
00799 __PTERMINAL __terminalCreate(__PSTRING name, __PDEVICE in, __PDEVICE out, u16 linelen, __PSTRING prompt, u8 flags)
00800 {
00801 __PTERMINAL term;
00802
00803 if (!name) return __NULL;
00804
00805
00806 if (!in && !out) return __NULL;
00807
00808
00809 term = __heapAllocZero(sizeof(__TERMINAL));
00810 if (!term) return __NULL;
00811
00812
00813 if (!linelen) linelen = __TERMINAL_DEF_LINELEN;
00814
00815
00816 term->rx_line = __heapAllocZero(linelen);
00817 if (!term->rx_line)
00818 {
00819 __heapFree(term);
00820 return __NULL;
00821 }
00822
00823
00824 term->tx_line = __heapAllocZero(linelen);
00825 if (!term->tx_line)
00826 {
00827 __heapFree(term);
00828 __heapFree(term->rx_line);
00829 return __NULL;
00830 }
00831
00832
00833
00834 if (out)
00835 {
00836 term->lock = __lockCreate();
00837 if (!term->lock)
00838 {
00839 __heapFree(term);
00840 __heapFree(term->rx_line);
00841 __heapFree(term->tx_line);
00842 return __NULL;
00843 }
00844 }
00845
00846 term->linelen = linelen;
00847 term->name = name;
00848 term->dv_in = in;
00849 term->dv_out = out;
00850 term->flags = flags;
00851
00852 if (!prompt)
00853 {
00854 term->prompt = __TERMINAL_PROMPT;
00855 } else {
00856 term->prompt = prompt;
00857 }
00858
00859 #if __CONFIG_COMPILE_DBGTERM
00860
00861 if (flags & __TERMINAL_DEBUG_COMMANDS)
00862 {
00863 __terminalAddCommand(term, __dbgCommands, sizeof(__dbgCommands) / sizeof(__TERMINALCMD));
00864 }
00865
00866 #endif
00867
00868 return term;
00869 }
00870
00892 __VOID __terminalAddCommand(__PTERMINAL term, __PTERMINALCMD cmd, u8 count)
00893 {
00894 u8 i;
00895
00896 if (!term || !cmd || !count) return;
00897
00898 for (i = 0; i < count; i++)
00899 {
00900 cmd[i].next = term->cmds;
00901 term->cmds = &cmd[i];
00902 }
00903 }
00904
00917 __VOID __terminalCreateCommand(__PTERMINAL term, __PSTRING cmd, __TERMINALRXCMD* func)
00918 {
00919 __PTERMINALCMD ptr;
00920
00921 if (!term) return;
00922
00923 ptr = __heapAllocZero(sizeof(__TERMINALCMD));
00924 if (!ptr) return;
00925
00926 ptr->cmd = cmd;
00927 ptr->func = func;
00928 ptr->next = __NULL;
00929
00930 __terminalAddCommand(term, ptr, 1);
00931 }
00932
00945 #endif // __CONFIG_COMPILE_TERMINAL
00946