//==========================================================================
|
//==========================================================================
|
//
|
//
|
// io.c
|
// io.c
|
//
|
//
|
// RedBoot I/O support
|
// RedBoot I/O support
|
//
|
//
|
//==========================================================================
|
//==========================================================================
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
// -------------------------------------------
|
// -------------------------------------------
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
// Copyright (C) 2002 Gary Thomas
|
// Copyright (C) 2002 Gary Thomas
|
//
|
//
|
// eCos is free software; you can redistribute it and/or modify it under
|
// eCos is free software; you can redistribute it and/or modify it under
|
// the terms of the GNU General Public License as published by the Free
|
// the terms of the GNU General Public License as published by the Free
|
// Software Foundation; either version 2 or (at your option) any later version.
|
// Software Foundation; either version 2 or (at your option) any later version.
|
//
|
//
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License along
|
// You should have received a copy of the GNU General Public License along
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
//
|
//
|
// As a special exception, if other files instantiate templates or use macros
|
// As a special exception, if other files instantiate templates or use macros
|
// or inline functions from this file, or you compile this file and link it
|
// or inline functions from this file, or you compile this file and link it
|
// with other works to produce a work based on this file, this file does not
|
// with other works to produce a work based on this file, this file does not
|
// by itself cause the resulting work to be covered by the GNU General Public
|
// by itself cause the resulting work to be covered by the GNU General Public
|
// License. However the source code for this file must still be made available
|
// License. However the source code for this file must still be made available
|
// in accordance with section (3) of the GNU General Public License.
|
// in accordance with section (3) of the GNU General Public License.
|
//
|
//
|
// This exception does not invalidate any other reasons why a work based on
|
// This exception does not invalidate any other reasons why a work based on
|
// this file might be covered by the GNU General Public License.
|
// this file might be covered by the GNU General Public License.
|
//
|
//
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
// at http://sources.redhat.com/ecos/ecos-license/
|
// at http://sources.redhat.com/ecos/ecos-license/
|
// -------------------------------------------
|
// -------------------------------------------
|
//####ECOSGPLCOPYRIGHTEND####
|
//####ECOSGPLCOPYRIGHTEND####
|
//==========================================================================
|
//==========================================================================
|
//#####DESCRIPTIONBEGIN####
|
//#####DESCRIPTIONBEGIN####
|
//
|
//
|
// Author(s): gthomas
|
// Author(s): gthomas
|
// Contributors: gthomas,hmt,jlarmour
|
// Contributors: gthomas,hmt,jlarmour
|
// Date: 2000-07-14
|
// Date: 2000-07-14
|
// Purpose:
|
// Purpose:
|
// Description:
|
// Description:
|
//
|
//
|
// This code is part of RedBoot (tm).
|
// This code is part of RedBoot (tm).
|
//
|
//
|
//####DESCRIPTIONEND####
|
//####DESCRIPTIONEND####
|
//
|
//
|
//==========================================================================
|
//==========================================================================
|
|
|
#include "redboot.h"
|
#include "redboot.h"
|
|
|
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
|
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
|
// GDB interface functions
|
// GDB interface functions
|
extern void ungetDebugChar(char c);
|
extern void ungetDebugChar(char c);
|
#endif
|
#endif
|
|
|
static void
|
static void
|
do_channel(int argc, char *argv[]);
|
do_channel(int argc, char *argv[]);
|
|
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
RedBoot_cmd("channel",
|
RedBoot_cmd("channel",
|
"Display/switch console channel",
|
"Display/switch console channel",
|
"[-1|<channel number>]",
|
"[-1|<channel number>]",
|
do_channel
|
do_channel
|
);
|
);
|
#else
|
#else
|
RedBoot_cmd("channel",
|
RedBoot_cmd("channel",
|
"Display/switch console channel",
|
"Display/switch console channel",
|
"[<channel number>]",
|
"[<channel number>]",
|
do_channel
|
do_channel
|
);
|
);
|
#endif
|
#endif
|
|
|
static void
|
static void
|
do_channel(int argc, char *argv[])
|
do_channel(int argc, char *argv[])
|
{
|
{
|
int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
|
int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
|
|
|
if (argc == 2) {
|
if (argc == 2) {
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
if (strcmp( argv[1], "-1") == 0) {
|
if (strcmp( argv[1], "-1") == 0) {
|
console_selected = false;
|
console_selected = false;
|
console_echo = true;
|
console_echo = true;
|
} else
|
} else
|
#endif
|
#endif
|
{
|
{
|
unsigned long chan;
|
unsigned long chan;
|
if ( !parse_num( argv[1], &chan, NULL, NULL) ) {
|
if ( !parse_num( argv[1], &chan, NULL, NULL) ) {
|
diag_printf("** Error: invalid channel '%s'\n", argv[1]);
|
diag_printf("** Error: invalid channel '%s'\n", argv[1]);
|
} else {
|
} else {
|
if (chan < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) {
|
if (chan < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) {
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);
|
CYGACC_CALL_IF_SET_DEBUG_COMM(chan);
|
CYGACC_CALL_IF_SET_DEBUG_COMM(chan);
|
if (chan != cur)
|
if (chan != cur)
|
console_echo = true;
|
console_echo = true;
|
}
|
}
|
else {
|
else {
|
diag_printf("**Error: bad channel number '%s'\n", argv[1]);
|
diag_printf("**Error: bad channel number '%s'\n", argv[1]);
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
/* else display */
|
/* else display */
|
else {
|
else {
|
diag_printf("Current console channel id: ");
|
diag_printf("Current console channel id: ");
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
if (!console_selected)
|
if (!console_selected)
|
diag_printf("-1\n");
|
diag_printf("-1\n");
|
else
|
else
|
#endif
|
#endif
|
diag_printf("%d\n", cur);
|
diag_printf("%d\n", cur);
|
}
|
}
|
}
|
}
|
|
|
void
|
void
|
mon_write_char(char c)
|
mon_write_char(char c)
|
{
|
{
|
hal_virtual_comm_table_t *__chan;
|
hal_virtual_comm_table_t *__chan;
|
|
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
if (!console_selected) {
|
if (!console_selected) {
|
int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
|
int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
|
int i;
|
int i;
|
// Send output to all channels
|
// Send output to all channels
|
for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++) {
|
for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++) {
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
|
__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
|
__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
|
CYGACC_COMM_IF_PUTC(*__chan, c);
|
CYGACC_COMM_IF_PUTC(*__chan, c);
|
}
|
}
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
|
} else
|
} else
|
#endif
|
#endif
|
{
|
{
|
__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
|
__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
|
if (__chan)
|
if (__chan)
|
CYGACC_COMM_IF_PUTC(*__chan, c);
|
CYGACC_COMM_IF_PUTC(*__chan, c);
|
else {
|
else {
|
__chan = CYGACC_CALL_IF_DEBUG_PROCS();
|
__chan = CYGACC_CALL_IF_DEBUG_PROCS();
|
CYGACC_COMM_IF_PUTC(*__chan, c);
|
CYGACC_COMM_IF_PUTC(*__chan, c);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
static void
|
static void
|
mon_read_char(char *c)
|
mon_read_char(char *c)
|
{
|
{
|
hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
|
hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
|
|
|
if (__chan)
|
if (__chan)
|
*c = CYGACC_COMM_IF_GETC(*__chan);
|
*c = CYGACC_COMM_IF_GETC(*__chan);
|
else {
|
else {
|
__chan = CYGACC_CALL_IF_DEBUG_PROCS();
|
__chan = CYGACC_CALL_IF_DEBUG_PROCS();
|
*c = CYGACC_COMM_IF_GETC(*__chan);
|
*c = CYGACC_COMM_IF_GETC(*__chan);
|
}
|
}
|
}
|
}
|
|
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
static int _mon_timeout;
|
static int _mon_timeout;
|
#endif
|
#endif
|
|
|
static bool
|
static bool
|
mon_read_char_with_timeout(char *c)
|
mon_read_char_with_timeout(char *c)
|
{
|
{
|
bool res = false;
|
bool res = false;
|
hal_virtual_comm_table_t *__chan;
|
hal_virtual_comm_table_t *__chan;
|
|
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
if (!console_selected) {
|
if (!console_selected) {
|
int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
|
int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
|
int i, j, tot;
|
int i, j, tot;
|
// Try input from all channels
|
// Try input from all channels
|
tot = 0;
|
tot = 0;
|
while (tot < _mon_timeout) {
|
while (tot < _mon_timeout) {
|
for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++, tot++) {
|
for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++, tot++) {
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
|
__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
|
__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
|
res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c);
|
res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c);
|
if (res) {
|
if (res) {
|
// Input available on this channel, make it be the console
|
// Input available on this channel, make it be the console
|
if (*c != '\0') {
|
if (*c != '\0') {
|
// Don't chose this unless real data have arrived
|
// Don't chose this unless real data have arrived
|
console_selected = true;
|
console_selected = true;
|
CYGACC_CALL_IF_SET_DEBUG_COMM(i);
|
CYGACC_CALL_IF_SET_DEBUG_COMM(i);
|
// Disable interrupts on all channels but this one
|
// Disable interrupts on all channels but this one
|
for (j = 0; j < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; j++) {
|
for (j = 0; j < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; j++) {
|
if (i != j) {
|
if (i != j) {
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(j);
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(j);
|
__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
|
__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
|
CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_DISABLE);
|
CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_DISABLE);
|
}
|
}
|
}
|
}
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
|
return res;
|
return res;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
|
} else
|
} else
|
#endif
|
#endif
|
{
|
{
|
__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
|
__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
|
if (__chan)
|
if (__chan)
|
res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c);
|
res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c);
|
else {
|
else {
|
__chan = CYGACC_CALL_IF_DEBUG_PROCS();
|
__chan = CYGACC_CALL_IF_DEBUG_PROCS();
|
res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c);
|
res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c);
|
}
|
}
|
}
|
}
|
return res;
|
return res;
|
}
|
}
|
|
|
static void
|
static void
|
mon_set_read_char_timeout(int ms)
|
mon_set_read_char_timeout(int ms)
|
{
|
{
|
hal_virtual_comm_table_t *__chan;
|
hal_virtual_comm_table_t *__chan;
|
|
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
|
if (!console_selected) {
|
if (!console_selected) {
|
int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
|
int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
|
int i;
|
int i;
|
// Set timeout to minimum on each channel; total amounts to desired value
|
// Set timeout to minimum on each channel; total amounts to desired value
|
_mon_timeout = ms;
|
_mon_timeout = ms;
|
ms = 1;
|
ms = 1;
|
for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++) {
|
for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++) {
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
|
if ((__chan = CYGACC_CALL_IF_CONSOLE_PROCS()) != 0) {
|
if ((__chan = CYGACC_CALL_IF_CONSOLE_PROCS()) != 0) {
|
CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms);
|
CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms);
|
}
|
}
|
}
|
}
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
|
CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
|
} else
|
} else
|
#endif
|
#endif
|
{
|
{
|
if ((__chan = CYGACC_CALL_IF_CONSOLE_PROCS()) != 0) {
|
if ((__chan = CYGACC_CALL_IF_CONSOLE_PROCS()) != 0) {
|
CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms);
|
CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms);
|
}
|
}
|
if ((__chan = CYGACC_CALL_IF_DEBUG_PROCS()) != 0) {
|
if ((__chan = CYGACC_CALL_IF_DEBUG_PROCS()) != 0) {
|
CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms);
|
CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
|
#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
|
#define __STRINGIFY(x) #x
|
#define __STRINGIFY(x) #x
|
#define _STRINGIFY(x) __STRINGIFY(x)
|
#define _STRINGIFY(x) __STRINGIFY(x)
|
#define _STARTUP_STR _STRINGIFY(CYG_HAL_STARTUP) "}"
|
#define _STARTUP_STR _STRINGIFY(CYG_HAL_STARTUP) "}"
|
|
|
//
|
//
|
// Read a character from script.
|
// Read a character from script.
|
// Return true if script character found, false if not.
|
// Return true if script character found, false if not.
|
//
|
//
|
static int
|
static int
|
getc_script(char *cp)
|
getc_script(char *cp)
|
{
|
{
|
static bool newline = true;
|
static bool newline = true;
|
bool skip;
|
bool skip;
|
|
|
while (script && *script) {
|
while (script && *script) {
|
if (newline && *script == '{') {
|
if (newline && *script == '{') {
|
skip = false;
|
skip = false;
|
++script;
|
++script;
|
|
|
// skip if it isn't for this startup type
|
// skip if it isn't for this startup type
|
if (strncmp(script, _STARTUP_STR, strlen(_STARTUP_STR)))
|
if (strncmp(script, _STARTUP_STR, strlen(_STARTUP_STR)))
|
skip = true;
|
skip = true;
|
|
|
// skip past "{...}"
|
// skip past "{...}"
|
while (*script && *script++ != '}')
|
while (*script && *script++ != '}')
|
;
|
;
|
|
|
// skip script line if neccessary
|
// skip script line if neccessary
|
if (skip) {
|
if (skip) {
|
while (*script && *script++ != '\n')
|
while (*script && *script++ != '\n')
|
;
|
;
|
} else
|
} else
|
newline = false;
|
newline = false;
|
|
|
} else {
|
} else {
|
*cp = *script++;
|
*cp = *script++;
|
if (*cp == '\n') {
|
if (*cp == '\n') {
|
newline = true;
|
newline = true;
|
} else {
|
} else {
|
newline = false;
|
newline = false;
|
}
|
}
|
return true;
|
return true;
|
}
|
}
|
}
|
}
|
return false;
|
return false;
|
}
|
}
|
#endif
|
#endif
|
|
|
//
|
//
|
// Read a line of input from the user
|
// Read a line of input from the user
|
// Return:
|
// Return:
|
// _GETS_OK: 'n' valid characters received
|
// _GETS_OK: 'n' valid characters received
|
// _GETS_GDB: '$' (GDB lead-in)
|
// _GETS_GDB: '$' (GDB lead-in)
|
// _GETS_TIMEOUT: No input before timeout
|
// _GETS_TIMEOUT: No input before timeout
|
// _GETS_CTRLC: ^C typed
|
// _GETS_CTRLC: ^C typed
|
//
|
//
|
int
|
int
|
_rb_gets_preloaded(char *buf, int buflen, int timeout)
|
_rb_gets_preloaded(char *buf, int buflen, int timeout)
|
{
|
{
|
char *ip = buf; // Insertion point
|
char *ip = buf; // Insertion point
|
char *eol = buf; // End of line
|
char *eol = buf; // End of line
|
char c;
|
char c;
|
bool res = false;
|
bool res = false;
|
static char last_ch = '\0';
|
static char last_ch = '\0';
|
int _timeout;
|
int _timeout;
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
//
|
//
|
// Command line history support
|
// Command line history support
|
// ^P - Select previous line from history
|
// ^P - Select previous line from history
|
// ^N - Select next line from history
|
// ^N - Select next line from history
|
// ^A - Move insertion [cursor] to start of line
|
// ^A - Move insertion [cursor] to start of line
|
// ^E - Move cursor to end of line
|
// ^E - Move cursor to end of line
|
// ^B - Move cursor back [previous character]
|
// ^B - Move cursor back [previous character]
|
// ^F - Move cursor forward [next character]
|
// ^F - Move cursor forward [next character]
|
//
|
//
|
#define _CL_NUM_LINES CYGNUM_REDBOOT_CMD_LINE_EDITING // Number of lines to keep
|
#define _CL_NUM_LINES CYGNUM_REDBOOT_CMD_LINE_EDITING // Number of lines to keep
|
static char _cl_lines[_CL_NUM_LINES][CYGPKG_REDBOOT_MAX_CMD_LINE];
|
static char _cl_lines[_CL_NUM_LINES][CYGPKG_REDBOOT_MAX_CMD_LINE];
|
static int _cl_index = -1; // Last known command line
|
static int _cl_index = -1; // Last known command line
|
static int _cl_max_index = -1; // Last command in buffers
|
static int _cl_max_index = -1; // Last command in buffers
|
int _index = _cl_index; // Last saved line
|
int _index = _cl_index; // Last saved line
|
char *xp;
|
char *xp;
|
#endif
|
#endif
|
|
|
// Display current buffer data
|
// Display current buffer data
|
while (*eol) {
|
while (*eol) {
|
mon_write_char(*eol++);
|
mon_write_char(*eol++);
|
}
|
}
|
ip = eol;
|
ip = eol;
|
|
|
while (true) {
|
while (true) {
|
#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
|
#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
|
if (getc_script(&c))
|
if (getc_script(&c))
|
do_idle(false);
|
do_idle(false);
|
else
|
else
|
#endif
|
#endif
|
if ((timeout > 0) && (eol == buf)) {
|
if ((timeout > 0) && (eol == buf)) {
|
#define MIN_TIMEOUT 50
|
#define MIN_TIMEOUT 50
|
_timeout = timeout > MIN_TIMEOUT ? MIN_TIMEOUT : timeout;
|
_timeout = timeout > MIN_TIMEOUT ? MIN_TIMEOUT : timeout;
|
mon_set_read_char_timeout(_timeout);
|
mon_set_read_char_timeout(_timeout);
|
while (timeout > 0) {
|
while (timeout > 0) {
|
res = mon_read_char_with_timeout(&c);
|
res = mon_read_char_with_timeout(&c);
|
if (res) {
|
if (res) {
|
// Got a character
|
// Got a character
|
do_idle(false);
|
do_idle(false);
|
break;
|
break;
|
}
|
}
|
timeout -= _timeout;
|
timeout -= _timeout;
|
}
|
}
|
if (res == false) {
|
if (res == false) {
|
do_idle(true);
|
do_idle(true);
|
return _GETS_TIMEOUT; // Input timed out
|
return _GETS_TIMEOUT; // Input timed out
|
}
|
}
|
} else {
|
} else {
|
mon_read_char(&c);
|
mon_read_char(&c);
|
}
|
}
|
*eol = '\0';
|
*eol = '\0';
|
switch (c) {
|
switch (c) {
|
#define CTRL(c) ((c)&0x1F)
|
#define CTRL(c) ((c)&0x1F)
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
case CTRL('P'):
|
case CTRL('P'):
|
// Fetch the previous line into the buffer
|
// Fetch the previous line into the buffer
|
if (_index >= 0) {
|
if (_index >= 0) {
|
// Erase the previous line [crude]
|
// Erase the previous line [crude]
|
while (ip != buf) {
|
while (ip != buf) {
|
mon_write_char('\b');
|
mon_write_char('\b');
|
mon_write_char(' ');
|
mon_write_char(' ');
|
mon_write_char('\b');
|
mon_write_char('\b');
|
ip--;
|
ip--;
|
}
|
}
|
strcpy(buf, _cl_lines[_index]);
|
strcpy(buf, _cl_lines[_index]);
|
while (*ip) {
|
while (*ip) {
|
mon_write_char(*ip++);
|
mon_write_char(*ip++);
|
}
|
}
|
eol = ip;
|
eol = ip;
|
// Move to previous line
|
// Move to previous line
|
_index--;
|
_index--;
|
if (_index < 0) {
|
if (_index < 0) {
|
_index = _cl_max_index;
|
_index = _cl_max_index;
|
}
|
}
|
} else {
|
} else {
|
mon_write_char(0x07); // Audible bell on most devices
|
mon_write_char(0x07); // Audible bell on most devices
|
}
|
}
|
break;
|
break;
|
case CTRL('N'):
|
case CTRL('N'):
|
// Fetch the next line into the buffer
|
// Fetch the next line into the buffer
|
if (_index >= 0) {
|
if (_index >= 0) {
|
if (++_index > _cl_max_index) _index = 0;
|
if (++_index > _cl_max_index) _index = 0;
|
// Erase the previous line [crude]
|
// Erase the previous line [crude]
|
while (ip != buf) {
|
while (ip != buf) {
|
mon_write_char('\b');
|
mon_write_char('\b');
|
mon_write_char(' ');
|
mon_write_char(' ');
|
mon_write_char('\b');
|
mon_write_char('\b');
|
ip--;
|
ip--;
|
}
|
}
|
strcpy(buf, _cl_lines[_index]);
|
strcpy(buf, _cl_lines[_index]);
|
while (*ip) {
|
while (*ip) {
|
mon_write_char(*ip++);
|
mon_write_char(*ip++);
|
}
|
}
|
eol = ip;
|
eol = ip;
|
} else {
|
} else {
|
mon_write_char(0x07); // Audible bell on most devices
|
mon_write_char(0x07); // Audible bell on most devices
|
}
|
}
|
break;
|
break;
|
case CTRL('B'):
|
case CTRL('B'):
|
// Move insertion point backwards
|
// Move insertion point backwards
|
if (ip != buf) {
|
if (ip != buf) {
|
mon_write_char('\b');
|
mon_write_char('\b');
|
ip--;
|
ip--;
|
}
|
}
|
break;
|
break;
|
case CTRL('F'):
|
case CTRL('F'):
|
// Move insertion point forwards
|
// Move insertion point forwards
|
if (ip != eol) {
|
if (ip != eol) {
|
mon_write_char(*ip++);
|
mon_write_char(*ip++);
|
}
|
}
|
break;
|
break;
|
case CTRL('E'):
|
case CTRL('E'):
|
// Move insertion point to end of line
|
// Move insertion point to end of line
|
while (ip != eol) {
|
while (ip != eol) {
|
mon_write_char(*ip++);
|
mon_write_char(*ip++);
|
}
|
}
|
break;
|
break;
|
case CTRL('A'):
|
case CTRL('A'):
|
// Move insertion point to beginning of line
|
// Move insertion point to beginning of line
|
if (ip != buf) {
|
if (ip != buf) {
|
xp = eol;
|
xp = eol;
|
while (xp-- != buf) {
|
while (xp-- != buf) {
|
mon_write_char('\b');
|
mon_write_char('\b');
|
}
|
}
|
}
|
}
|
ip = buf;
|
ip = buf;
|
break;
|
break;
|
case CTRL('K'):
|
case CTRL('K'):
|
// Kill to the end of line
|
// Kill to the end of line
|
if (ip != eol) {
|
if (ip != eol) {
|
xp = ip;
|
xp = ip;
|
while (xp++ != eol) {
|
while (xp++ != eol) {
|
mon_write_char(' ');
|
mon_write_char(' ');
|
}
|
}
|
while (--xp != ip) {
|
while (--xp != ip) {
|
mon_write_char('\b');
|
mon_write_char('\b');
|
}
|
}
|
eol = ip;
|
eol = ip;
|
}
|
}
|
break;
|
break;
|
case CTRL('D'):
|
case CTRL('D'):
|
// Erase the character under the cursor
|
// Erase the character under the cursor
|
if (ip != eol) {
|
if (ip != eol) {
|
xp = ip;
|
xp = ip;
|
eol--;
|
eol--;
|
while (xp != eol) {
|
while (xp != eol) {
|
*xp = *(xp+1);
|
*xp = *(xp+1);
|
mon_write_char(*xp++);
|
mon_write_char(*xp++);
|
}
|
}
|
mon_write_char(' '); // Erases last character
|
mon_write_char(' '); // Erases last character
|
mon_write_char('\b');
|
mon_write_char('\b');
|
while (xp-- != ip) {
|
while (xp-- != ip) {
|
mon_write_char('\b');
|
mon_write_char('\b');
|
}
|
}
|
}
|
}
|
break;
|
break;
|
#endif // CYGNUM_REDBOOT_CMD_LINE_EDITING
|
#endif // CYGNUM_REDBOOT_CMD_LINE_EDITING
|
case CTRL('C'): // ^C
|
case CTRL('C'): // ^C
|
// Abort current input
|
// Abort current input
|
diag_printf("^C\n");
|
diag_printf("^C\n");
|
*buf = '\0'; // Nothing useful in buffer
|
*buf = '\0'; // Nothing useful in buffer
|
return _GETS_CTRLC;
|
return _GETS_CTRLC;
|
case '\n':
|
case '\n':
|
case '\r':
|
case '\r':
|
// If previous character was the "other" end-of-line, ignore this one
|
// If previous character was the "other" end-of-line, ignore this one
|
if (((c == '\n') && (last_ch == '\r')) ||
|
if (((c == '\n') && (last_ch == '\r')) ||
|
((c == '\r') && (last_ch == '\n'))) {
|
((c == '\r') && (last_ch == '\n'))) {
|
c = '\0';
|
c = '\0';
|
break;
|
break;
|
}
|
}
|
// End of line
|
// End of line
|
if (console_echo) {
|
if (console_echo) {
|
mon_write_char('\r');
|
mon_write_char('\r');
|
mon_write_char('\n');
|
mon_write_char('\n');
|
}
|
}
|
last_ch = c;
|
last_ch = c;
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
if (cmd_history && (buf != eol)) {
|
if (cmd_history && (buf != eol)) {
|
// Save current line - only when enabled
|
// Save current line - only when enabled
|
if (++_cl_index == _CL_NUM_LINES) _cl_index = 0;
|
if (++_cl_index == _CL_NUM_LINES) _cl_index = 0;
|
if (_cl_index > _cl_max_index) _cl_max_index = _cl_index;
|
if (_cl_index > _cl_max_index) _cl_max_index = _cl_index;
|
strcpy(_cl_lines[_cl_index], buf);
|
strcpy(_cl_lines[_cl_index], buf);
|
}
|
}
|
#endif
|
#endif
|
return _GETS_OK;
|
return _GETS_OK;
|
case '\b':
|
case '\b':
|
case 0x7F: // DEL
|
case 0x7F: // DEL
|
if (ip != buf) {
|
if (ip != buf) {
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
if (ip != eol) {
|
if (ip != eol) {
|
ip--;
|
ip--;
|
mon_write_char('\b');
|
mon_write_char('\b');
|
xp = ip;
|
xp = ip;
|
while (xp != (eol-1)) {
|
while (xp != (eol-1)) {
|
*xp = *(xp+1);
|
*xp = *(xp+1);
|
mon_write_char(*xp++);
|
mon_write_char(*xp++);
|
}
|
}
|
mon_write_char(' '); // Erases last character
|
mon_write_char(' '); // Erases last character
|
mon_write_char('\b');
|
mon_write_char('\b');
|
while (xp-- != ip) {
|
while (xp-- != ip) {
|
mon_write_char('\b');
|
mon_write_char('\b');
|
}
|
}
|
} else {
|
} else {
|
if (console_echo) {
|
if (console_echo) {
|
mon_write_char('\b');
|
mon_write_char('\b');
|
mon_write_char(' ');
|
mon_write_char(' ');
|
mon_write_char('\b');
|
mon_write_char('\b');
|
}
|
}
|
ip--;
|
ip--;
|
}
|
}
|
eol--;
|
eol--;
|
#else
|
#else
|
if (console_echo) {
|
if (console_echo) {
|
mon_write_char('\b');
|
mon_write_char('\b');
|
mon_write_char(' ');
|
mon_write_char(' ');
|
mon_write_char('\b');
|
mon_write_char('\b');
|
}
|
}
|
ip--;
|
ip--;
|
eol--;
|
eol--;
|
#endif
|
#endif
|
}
|
}
|
break;
|
break;
|
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
|
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
|
case '+': // fall through
|
case '+': // fall through
|
case '$':
|
case '$':
|
if (ip == buf || last_ch != '\\')
|
if (ip == buf || last_ch != '\\')
|
{
|
{
|
// Give up and try GDB protocol
|
// Give up and try GDB protocol
|
ungetDebugChar(c); // Push back character so stubs will see it
|
ungetDebugChar(c); // Push back character so stubs will see it
|
return _GETS_GDB;
|
return _GETS_GDB;
|
}
|
}
|
if (last_ch == '\\') {
|
if (last_ch == '\\') {
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
if (ip == eol) {
|
if (ip == eol) {
|
// Just save \$ as $
|
// Just save \$ as $
|
eol = --ip;
|
eol = --ip;
|
} else {
|
} else {
|
mon_write_char('\b');
|
mon_write_char('\b');
|
*--ip = c;
|
*--ip = c;
|
mon_write_char(c);
|
mon_write_char(c);
|
break;
|
break;
|
}
|
}
|
#else
|
#else
|
ip--; // Save \$ as $
|
ip--; // Save \$ as $
|
#endif
|
#endif
|
}
|
}
|
// else fall through
|
// else fall through
|
#endif
|
#endif
|
default:
|
default:
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
// If the insertion point is not at the end of line, make space for it
|
// If the insertion point is not at the end of line, make space for it
|
if (ip != eol) {
|
if (ip != eol) {
|
xp = eol;
|
xp = eol;
|
*++eol = '\0';
|
*++eol = '\0';
|
while (xp != ip) {
|
while (xp != ip) {
|
*xp = *(xp-1);
|
*xp = *(xp-1);
|
xp--;
|
xp--;
|
}
|
}
|
}
|
}
|
#endif
|
#endif
|
if (console_echo) {
|
if (console_echo) {
|
mon_write_char(c);
|
mon_write_char(c);
|
}
|
}
|
if (ip == eol) {
|
if (ip == eol) {
|
// Advance both pointers
|
// Advance both pointers
|
*ip++ = c;
|
*ip++ = c;
|
eol = ip;
|
eol = ip;
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
|
} else {
|
} else {
|
// Just insert the character
|
// Just insert the character
|
*ip++ = c;
|
*ip++ = c;
|
xp = ip;
|
xp = ip;
|
while (xp != eol) {
|
while (xp != eol) {
|
mon_write_char(*xp++);
|
mon_write_char(*xp++);
|
}
|
}
|
while (xp-- != ip) {
|
while (xp-- != ip) {
|
mon_write_char('\b');
|
mon_write_char('\b');
|
}
|
}
|
#endif
|
#endif
|
}
|
}
|
}
|
}
|
last_ch = c;
|
last_ch = c;
|
if (ip == buf + buflen - 1) { // Buffer full
|
if (ip == buf + buflen - 1) { // Buffer full
|
*ip = '\0';
|
*ip = '\0';
|
return buflen;
|
return buflen;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
int
|
int
|
_rb_gets(char *buf, int buflen, int timeout)
|
_rb_gets(char *buf, int buflen, int timeout)
|
{
|
{
|
*buf = '\0'; // Empty buffer
|
*buf = '\0'; // Empty buffer
|
return _rb_gets_preloaded(buf, buflen, timeout);
|
return _rb_gets_preloaded(buf, buflen, timeout);
|
}
|
}
|
|
|
static bool
|
static bool
|
_verify_action(int timeout, char *fmt, va_list ap)
|
_verify_action(int timeout, char *fmt, va_list ap)
|
{
|
{
|
char ans[8];
|
char ans[8];
|
int ret;
|
int ret;
|
#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
|
#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
|
// Don't ask if we're executing a script
|
// Don't ask if we're executing a script
|
if (script && *script)
|
if (script && *script)
|
return 1;
|
return 1;
|
#endif
|
#endif
|
|
|
diag_vprintf(fmt, ap);
|
diag_vprintf(fmt, ap);
|
diag_printf(" - continue (y/n)? ");
|
diag_printf(" - continue (y/n)? ");
|
if ((ret = _rb_gets(ans, sizeof(ans), timeout)) > 0) {
|
if ((ret = _rb_gets(ans, sizeof(ans), timeout)) > 0) {
|
return ((ans[0] == 'y') || (ans[0] == 'Y'));
|
return ((ans[0] == 'y') || (ans[0] == 'Y'));
|
} else {
|
} else {
|
if (ret == _GETS_TIMEOUT) {
|
if (ret == _GETS_TIMEOUT) {
|
diag_printf(" ** Timed out!\n");
|
diag_printf(" ** Timed out!\n");
|
}
|
}
|
return 0; // Timed out or ^C
|
return 0; // Timed out or ^C
|
}
|
}
|
}
|
}
|
|
|
bool
|
bool
|
verify_action(char *fmt, ...)
|
verify_action(char *fmt, ...)
|
{
|
{
|
va_list ap;
|
va_list ap;
|
|
|
va_start(ap, fmt);
|
va_start(ap, fmt);
|
return _verify_action(0, fmt, ap);
|
return _verify_action(0, fmt, ap);
|
}
|
}
|
|
|
bool
|
bool
|
verify_action_with_timeout(int timeout, char *fmt, ...)
|
verify_action_with_timeout(int timeout, char *fmt, ...)
|
{
|
{
|
va_list ap;
|
va_list ap;
|
|
|
va_start(ap, fmt);
|
va_start(ap, fmt);
|
return _verify_action(timeout, fmt, ap);
|
return _verify_action(timeout, fmt, ap);
|
}
|
}
|
|
|