1 //==========================================================================
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
12 // Copyright (C) 2002, 2003, 2005 Gary Thomas
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
45 // Contributors: gthomas,hmt,jlarmour
50 // This code is part of RedBoot (tm).
52 //####DESCRIPTIONEND####
54 //==========================================================================
58 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
59 // GDB interface functions
60 extern void ungetDebugChar(char c);
64 do_channel(int argc, char *argv[]);
66 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
67 RedBoot_cmd("channel",
68 "Display/switch console channel",
69 "[-1|<channel number>]",
73 RedBoot_cmd("channel",
74 "Display/switch console channel",
81 do_channel(int argc, char *argv[])
83 int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
86 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
87 if (strcmp( argv[1], "-1") == 0) {
88 console_selected = false;
94 if ( !parse_num( argv[1], &chan, NULL, NULL) ) {
95 diag_printf("** Error: invalid channel '%s'\n", argv[1]);
97 if (chan < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) {
98 CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);
99 CYGACC_CALL_IF_SET_DEBUG_COMM(chan);
104 diag_printf("**Error: bad channel number '%s'\n", argv[1]);
111 diag_printf("Current console channel id: ");
112 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
113 if (!console_selected)
117 diag_printf("%d\n", cur);
122 mon_write_char(char c)
124 hal_virtual_comm_table_t *__chan;
126 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
127 if (!console_selected) {
128 int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
130 // Send output to all channels
131 for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++) {
132 CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
133 __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
134 CYGACC_COMM_IF_PUTC(*__chan, c);
136 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
140 __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
142 CYGACC_COMM_IF_PUTC(*__chan, c);
144 __chan = CYGACC_CALL_IF_DEBUG_PROCS();
145 CYGACC_COMM_IF_PUTC(*__chan, c);
151 mon_read_char(char *c)
153 hal_virtual_comm_table_t *__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
156 *c = CYGACC_COMM_IF_GETC(*__chan);
158 __chan = CYGACC_CALL_IF_DEBUG_PROCS();
159 *c = CYGACC_COMM_IF_GETC(*__chan);
163 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
164 static int _mon_timeout;
168 mon_read_char_with_timeout(char *c)
171 hal_virtual_comm_table_t *__chan;
173 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
174 if (!console_selected) {
175 int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
177 // Try input from all channels
179 while (tot < _mon_timeout) {
180 for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++, tot++) {
181 CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
182 __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
183 res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c);
185 // Input available on this channel, make it be the console
187 // Don't chose this unless real data have arrived
188 console_selected = true;
189 CYGACC_CALL_IF_SET_DEBUG_COMM(i);
190 // Disable interrupts on all channels but this one
191 for (j = 0; j < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; j++) {
193 CYGACC_CALL_IF_SET_CONSOLE_COMM(j);
194 __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
195 CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_DISABLE);
198 CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
204 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
208 __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
210 res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c);
212 __chan = CYGACC_CALL_IF_DEBUG_PROCS();
213 res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c);
220 mon_set_read_char_timeout(int ms)
222 hal_virtual_comm_table_t *__chan;
224 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
225 if (!console_selected) {
226 int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
228 // Set timeout to minimum on each channel; total amounts to desired value
231 for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++) {
232 CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
233 if ((__chan = CYGACC_CALL_IF_CONSOLE_PROCS()) != 0) {
234 CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms);
237 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
241 if ((__chan = CYGACC_CALL_IF_CONSOLE_PROCS()) != 0) {
242 CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms);
244 if ((__chan = CYGACC_CALL_IF_DEBUG_PROCS()) != 0) {
245 CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms);
251 // Test for ^C on the console. CAUTION! discards all console input
254 _rb_break(int timeout)
257 mon_set_read_char_timeout(timeout);
258 if (mon_read_char_with_timeout(&c)) {
259 if (c == 0x03) { // Test for ^C
266 #ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
267 #define __STRINGIFY(x) #x
268 #define _STRINGIFY(x) __STRINGIFY(x)
269 #define _STARTUP_STR _STRINGIFY(CYG_HAL_STARTUP) "}"
272 // Read a character from script.
273 // Return true if script character found, false if not.
276 getc_script(char *cp)
278 static bool newline = true;
281 while (script && *script) {
282 if (newline && *script == '{') {
286 // skip if it isn't for this startup type
287 if (strncmp(script, _STARTUP_STR, strlen(_STARTUP_STR)))
291 while (*script && *script++ != '}')
294 // skip script line if neccessary
296 while (*script && *script++ != '\n')
315 #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
316 #define _CL_NUM_LINES CYGNUM_REDBOOT_CMD_LINE_EDITING // Number of lines to keep
317 static char _cl_lines[_CL_NUM_LINES][CYGPKG_REDBOOT_MAX_CMD_LINE];
318 static int _cl_index = -1; // Last known command line
319 static int _cl_max_index = -1; // Last command in buffers
321 #ifdef CYGBLD_REDBOOT_CMD_LINE_HISTORY
322 static void expand_history(char *);
327 // Read a line of input from the user
329 // _GETS_OK: 'n' valid characters received
330 // _GETS_GDB: '$' (GDB lead-in)
331 // _GETS_TIMEOUT: No input before timeout
332 // _GETS_CTRLC: ^C typed
334 // if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
335 // Command line history support
336 // ^P - Select previous line from history
337 // ^N - Select next line from history
338 // ^A - Move insertion [cursor] to start of line
339 // ^E - Move cursor to end of line
340 // ^B - Move cursor back [previous character]
341 // ^F - Move cursor forward [next character]
342 // "standard" arrow keys work as well
347 // home ^[[H/^[1~ == ^A
348 // end ^[[F/^[OF == ^E
352 _rb_gets_preloaded(char *buf, int buflen, int timeout)
354 char *ip = buf; // Insertion point
355 char *eol = buf; // End of line
358 static char last_ch = '\0';
360 #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
361 int _index = _cl_index; // Last saved line
363 #ifdef CYGSEM_REDBOOT_CMD_LINE_ANSI_SEQUENCES
364 int ansi_state = 0; // Used to drive ANSI parser
365 char ansi_char = '\0';
369 // Display current buffer data
371 mon_write_char(*eol++);
376 #ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
381 if ((timeout > 0) && (eol == buf)) {
382 #define MIN_TIMEOUT 50
383 _timeout = timeout > MIN_TIMEOUT ? MIN_TIMEOUT : timeout;
384 mon_set_read_char_timeout(_timeout);
385 while (timeout > 0) {
386 res = mon_read_char_with_timeout(&c);
396 return _GETS_TIMEOUT; // Input timed out
402 #define CTRL(c) ((c)&0x1F)
403 #ifdef CYGSEM_REDBOOT_CMD_LINE_ANSI_SEQUENCES
404 // Special handling of ANSI keyboard sequences (arrows, etc)
406 // Leadin for ANSI keyboard sequence
410 switch (ansi_state) {
412 // No ANSI sequence in progress
415 // ESC seen, look for '['
418 } else if (c == 'O') {
421 // Handle bad sequences?
426 // ESC+[ seen, process key
448 ansi_char = CTRL('A');
452 ansi_char = CTRL('D');
456 // Handle bad sequences?
461 // Sequences like ^[[1~ == ^H
466 // Handle bad sequences?
471 // Sequences like ^[OF == ^E
476 // Handle bad sequences?
483 #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
485 // Fetch the previous line into the buffer
487 // Erase the previous line [crude]
489 mon_write_char('\b');
491 mon_write_char('\b');
494 strcpy(buf, _cl_lines[_index]);
496 mon_write_char(*ip++);
499 // Move to previous line
502 _index = _cl_max_index;
505 mon_write_char(0x07); // Audible bell on most devices
509 // Fetch the next line into the buffer
511 if (++_index > _cl_max_index) _index = 0;
512 // Erase the previous line [crude]
514 mon_write_char('\b');
516 mon_write_char('\b');
519 strcpy(buf, _cl_lines[_index]);
521 mon_write_char(*ip++);
525 mon_write_char(0x07); // Audible bell on most devices
529 // Move insertion point backwards
531 mon_write_char('\b');
536 // Move insertion point forwards
538 mon_write_char(*ip++);
542 // Move insertion point to end of line
544 mon_write_char(*ip++);
548 // Move insertion point to beginning of line
551 while (xp-- != buf) {
552 mon_write_char('\b');
558 // Kill to the end of line
561 while (xp++ != eol) {
565 mon_write_char('\b');
571 // Erase the character under the cursor
577 mon_write_char(*xp++);
579 mon_write_char(' '); // Erases last character
580 mon_write_char('\b');
582 mon_write_char('\b');
586 #endif // CYGNUM_REDBOOT_CMD_LINE_EDITING
587 case CTRL('C'): // ^C
588 // Abort current input
590 *buf = '\0'; // Nothing useful in buffer
594 // If previous character was the "other" end-of-line, ignore this one
595 if (((c == '\n') && (last_ch == '\r')) ||
596 ((c == '\r') && (last_ch == '\n'))) {
602 mon_write_char('\r');
603 mon_write_char('\n');
606 #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
608 // History handling - only when enabled
609 #ifdef CYGBLD_REDBOOT_CMD_LINE_HISTORY
613 if (++_cl_index == _CL_NUM_LINES) _cl_index = 0;
614 if (_cl_index > _cl_max_index) _cl_max_index = _cl_index;
615 strcpy(_cl_lines[_cl_index], buf);
623 #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
626 mon_write_char('\b');
628 while (xp != (eol-1)) {
630 mon_write_char(*xp++);
632 mon_write_char(' '); // Erases last character
633 mon_write_char('\b');
635 mon_write_char('\b');
639 mon_write_char('\b');
641 mon_write_char('\b');
648 mon_write_char('\b');
650 mon_write_char('\b');
657 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
658 case '+': // fall through
660 if (ip == buf || last_ch != '\\')
662 // Give up and try GDB protocol
663 ungetDebugChar(c); // Push back character so stubs will see it
666 if (last_ch == '\\') {
667 #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
672 mon_write_char('\b');
678 ip--; // Save \$ as $
684 #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
685 // If the insertion point is not at the end of line, make space for it
699 // Advance both pointers
702 #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
704 // Just insert the character
708 mon_write_char(*xp++);
711 mon_write_char('\b');
717 if (ip == buf + buflen - 1) { // Buffer full
725 _rb_gets(char *buf, int buflen, int timeout)
727 *buf = '\0'; // Empty buffer
728 return _rb_gets_preloaded(buf, buflen, timeout);
732 _verify_action(int timeout, char *fmt, va_list ap)
736 #ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
737 // Don't ask if we're executing a script
738 if (script && *script)
742 diag_vprintf(fmt, ap);
743 diag_printf(" - continue (y/n)? ");
744 if ((ret = _rb_gets(ans, sizeof(ans), timeout)) > 0) {
745 return ((ans[0] == 'y') || (ans[0] == 'Y'));
747 if (ret == _GETS_TIMEOUT) {
748 diag_printf(" ** Timed out!\n");
750 return 0; // Timed out or ^C
755 verify_action(char *fmt, ...)
760 return _verify_action(0, fmt, ap);
764 verify_action_with_timeout(int timeout, char *fmt, ...)
769 return _verify_action(timeout, fmt, ap);
773 #ifdef CYGBLD_REDBOOT_CMD_LINE_HISTORY
774 // parse for history index number. Return number or -1 if not
777 parse_history_index(char *s)
781 while ('0' <= *s && *s <= '9')
782 val = (val * 10) + (*s++ - '0');
790 // Check input line to see if it needs history expansion. If so,
791 // try to find matching command and replace buffer as appropriate.
793 expand_history(char *buf)
795 int ncmds = _cl_max_index + 1;
798 if (buf[0] != '!' || buf[1] == '\0')
802 if (!strcmp(buf, "!!")) {
803 strcpy(buf, _cl_lines[_cl_index]);
806 if ((index = parse_history_index(buf + 1)) >= 0) {
807 if (index <= _cl_max_index) {
808 strcpy(buf, _cl_lines[index]);
812 len = strlen(buf + 1);
813 for (i = 0, index = _cl_index; i < ncmds; i++) {
814 if (!strncmp(_cl_lines[index], buf+1, len)) {
815 strcpy(buf, _cl_lines[index]);
819 index = _cl_max_index;
823 diag_printf("%s: event not found\n", buf);
828 do_history(int argc, char *argv[])
830 int ncmds = _cl_max_index + 1;
833 if (_cl_index == _cl_max_index) {
834 // history has not wrapped around
835 for (i = 0; i < ncmds; i++)
836 diag_printf("%3d %s\n", i, _cl_lines[i]);
838 for (i = 0, index = _cl_index + 1; i < ncmds; i++) {
839 diag_printf("%3d %s\n", i, _cl_lines[index++]);
840 if (index > _cl_max_index)
846 RedBoot_cmd("history",
847 "Display command history",
851 #endif // CYGBLD_REDBOOT_CMD_LINE_HISTORY