mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-10-06 10:59:48 +08:00
The briefs of the libmisc files named a topic, not the content of the file. Four shell briefs named the wrong command. The file main_blksync.c said "RM Shell Command Implementation". The files main_id.c, main_time.c and shellconfig.c named ls and debugrfs. Four string conversion sources named the conversion, for example "Convert String to Unsigned Long". Write every brief in the style of the tree. A source brief starts with "This source file contains". A command brief names the command the file provides. A header brief starts with "This header file provides". Put @file, @ingroup and @brief in this order in every block. Updates #5717. Assisted-by: Claude:claude-opus-5 claude-code Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
649 lines
17 KiB
C
649 lines
17 KiB
C
/**
|
|
* @file
|
|
*
|
|
* @ingroup RTEMSImplMonitor
|
|
*
|
|
* @brief This source file contains the command line editor of the monitor.
|
|
*/
|
|
|
|
/*
|
|
* COPYRIGHT (c) 2000 Chris Johns <chrisj@rtems.org>
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <rtems.h>
|
|
|
|
#include <rtems/monitor.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <inttypes.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
|
|
#ifndef MONITOR_PROMPT
|
|
#define MONITOR_PROMPT "rtems" /* will have '> ' appended */
|
|
#endif
|
|
|
|
/*
|
|
* Some key labels to define special keys.
|
|
*/
|
|
|
|
#define KEYS_EXTENDED ( 0x8000 )
|
|
#define KEYS_NORMAL_MASK ( 0x00ff )
|
|
#define KEYS_INS ( 0 )
|
|
#define KEYS_DEL ( 1 )
|
|
#define KEYS_UARROW ( 2 )
|
|
#define KEYS_DARROW ( 3 )
|
|
#define KEYS_LARROW ( 4 )
|
|
#define KEYS_RARROW ( 5 )
|
|
#define KEYS_HOME ( 6 )
|
|
#define KEYS_END ( 7 )
|
|
#define KEYS_F1 ( 8 )
|
|
#define KEYS_F2 ( 9 )
|
|
#define KEYS_F3 ( 10 )
|
|
#define KEYS_F4 ( 11 )
|
|
#define KEYS_F5 ( 12 )
|
|
#define KEYS_F6 ( 13 )
|
|
#define KEYS_F7 ( 14 )
|
|
#define KEYS_F8 ( 15 )
|
|
#define KEYS_F9 ( 16 )
|
|
#define KEYS_F10 ( 17 )
|
|
|
|
#define RTEMS_COMMAND_BUFFER_SIZE ( 75 )
|
|
|
|
static char monitor_prompt[ 32 ];
|
|
static char buffer[ RTEMS_COMMAND_BUFFER_SIZE ];
|
|
static int pos;
|
|
static int logged_in;
|
|
|
|
/*
|
|
* History data.
|
|
*/
|
|
|
|
#define RTEMS_COMMAND_HISTORIES ( 20 )
|
|
|
|
static char history_buffer[ RTEMS_COMMAND_HISTORIES ]
|
|
[ RTEMS_COMMAND_BUFFER_SIZE ];
|
|
static int history_pos[ RTEMS_COMMAND_HISTORIES ];
|
|
static int history;
|
|
static int history_next;
|
|
|
|
/*
|
|
* Translation tables. Not sure if this is the best way to
|
|
* handle this, how-ever I wish to avoid the overhead of
|
|
* including a more complete and standard environment such
|
|
* as ncurses.
|
|
*/
|
|
|
|
struct translation_table {
|
|
char expecting;
|
|
const struct translation_table *branch;
|
|
unsigned int key;
|
|
};
|
|
|
|
static const struct translation_table trans_two[] = {
|
|
{ '~', 0, KEYS_INS },
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
static const struct translation_table trans_three[] = {
|
|
{ '~', 0, KEYS_DEL },
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
static const struct translation_table trans_tab_csi[] = {
|
|
{ '2', trans_two, 0 },
|
|
{ '3', trans_three, 0 },
|
|
{ 'A', 0, KEYS_UARROW },
|
|
{ 'B', 0, KEYS_DARROW },
|
|
{ 'D', 0, KEYS_LARROW },
|
|
{ 'C', 0, KEYS_RARROW },
|
|
{ 'F', 0, KEYS_END },
|
|
{ 'H', 0, KEYS_HOME },
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
static const struct translation_table trans_tab_O[] = {
|
|
{ '1', 0, KEYS_F1 },
|
|
{ '2', 0, KEYS_F2 },
|
|
{ '3', 0, KEYS_F3 },
|
|
{ '4', 0, KEYS_F4 },
|
|
{ '5', 0, KEYS_F5 },
|
|
{ '6', 0, KEYS_F6 },
|
|
{ '7', 0, KEYS_F7 },
|
|
{ '8', 0, KEYS_F8 },
|
|
{ '9', 0, KEYS_F9 },
|
|
{ ':', 0, KEYS_F10 },
|
|
{ 'P', 0, KEYS_F1 },
|
|
{ 'Q', 0, KEYS_F2 },
|
|
{ 'R', 0, KEYS_F3 },
|
|
{ 'S', 0, KEYS_F4 },
|
|
{ 'T', 0, KEYS_F5 },
|
|
{ 'U', 0, KEYS_F6 },
|
|
{ 'V', 0, KEYS_F7 },
|
|
{ 'W', 0, KEYS_F8 },
|
|
{ 'X', 0, KEYS_F9 },
|
|
{ 'Y', 0, KEYS_F10 },
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
static const struct translation_table trans_tab[] = {
|
|
{ '[', trans_tab_csi, 0 }, /* CSI command sequences */
|
|
{ 'O', trans_tab_O, 0 }, /* O are the fuction keys */
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
/*
|
|
* Perform a basic translation for some ANSI/VT100 key codes.
|
|
* This code could do with a timeout on the ESC as it is
|
|
* now lost from the input stream. It is not* used by the
|
|
* line editor below so considiered not worth the effort.
|
|
*/
|
|
|
|
static unsigned int rtems_monitor_getchar( void )
|
|
{
|
|
const struct translation_table *translation = 0;
|
|
for ( ;; ) {
|
|
char c = getchar();
|
|
if ( c == 27 ) {
|
|
translation = trans_tab;
|
|
} else {
|
|
/*
|
|
* If no translation happing just pass through
|
|
* and return the key.
|
|
*/
|
|
if ( translation ) {
|
|
/*
|
|
* Scan the current table for the key, and if found
|
|
* see if this key is a fork. If so follow it and
|
|
* wait else return the extended key.
|
|
*/
|
|
int index = 0;
|
|
int branched = 0;
|
|
while (
|
|
( translation[ index ].expecting != '\0' ) ||
|
|
( translation[ index ].key != '\0' )
|
|
) {
|
|
if ( translation[ index ].expecting == c ) {
|
|
/*
|
|
* A branch is take if more keys are to come.
|
|
*/
|
|
if ( translation[ index ].branch == 0 ) {
|
|
return KEYS_EXTENDED | translation[ index ].key;
|
|
} else {
|
|
translation = translation[ index ].branch;
|
|
branched = 1;
|
|
break;
|
|
}
|
|
}
|
|
index++;
|
|
}
|
|
/*
|
|
* Who knows what these keys are, just drop them.
|
|
*/
|
|
if ( !branched ) {
|
|
translation = 0;
|
|
}
|
|
} else {
|
|
return c;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The line editor with history.
|
|
*/
|
|
|
|
static int rtems_monitor_line_editor( char *command )
|
|
{
|
|
int repeating = 0;
|
|
|
|
memset( buffer, 0, RTEMS_COMMAND_BUFFER_SIZE );
|
|
history = history_next;
|
|
pos = 0;
|
|
|
|
if ( !logged_in ) {
|
|
fprintf( stdout, "\nMonitor ready, press enter to login.\n\n" );
|
|
} else {
|
|
fprintf( stdout, "%s $ ", monitor_prompt );
|
|
}
|
|
|
|
while ( 1 ) {
|
|
unsigned int extended_key;
|
|
char c;
|
|
|
|
fflush( stdout );
|
|
|
|
extended_key = rtems_monitor_getchar();
|
|
c = extended_key & KEYS_NORMAL_MASK;
|
|
|
|
/*
|
|
* Make the extended_key usable as a boolean.
|
|
*/
|
|
extended_key &= ~KEYS_NORMAL_MASK;
|
|
|
|
if ( !extended_key && !logged_in ) {
|
|
if ( c == '\n' ) {
|
|
logged_in = 1;
|
|
/*
|
|
* The prompt has changed from `>' to `$' to help know
|
|
* which version of the monitor code people are using.
|
|
*/
|
|
fprintf( stdout, "%s $ ", monitor_prompt );
|
|
}
|
|
} else {
|
|
if ( extended_key ) {
|
|
switch ( c ) {
|
|
case KEYS_END:
|
|
fprintf( stdout, "%s", buffer + pos );
|
|
pos = (int) strlen( buffer );
|
|
break;
|
|
|
|
case KEYS_HOME:
|
|
fprintf( stdout, "\r%s $ ", monitor_prompt );
|
|
pos = 0;
|
|
break;
|
|
|
|
case KEYS_LARROW:
|
|
if ( pos > 0 ) {
|
|
pos--;
|
|
putchar( '\b' );
|
|
}
|
|
break;
|
|
|
|
case KEYS_RARROW:
|
|
if (
|
|
( pos < RTEMS_COMMAND_BUFFER_SIZE ) && ( buffer[ pos ] != '\0' )
|
|
) {
|
|
putchar( buffer[ pos ] );
|
|
pos++;
|
|
}
|
|
break;
|
|
|
|
case KEYS_UARROW:
|
|
/*
|
|
* If we are moving up the histories then we need to save the working
|
|
* buffer.
|
|
*/
|
|
if ( history ) {
|
|
int end;
|
|
int bs;
|
|
if ( history == history_next ) {
|
|
memcpy(
|
|
history_buffer[ history_next ],
|
|
buffer,
|
|
RTEMS_COMMAND_BUFFER_SIZE
|
|
);
|
|
history_pos[ history_next ] = pos;
|
|
}
|
|
history--;
|
|
memcpy(
|
|
buffer,
|
|
history_buffer[ history ],
|
|
RTEMS_COMMAND_BUFFER_SIZE
|
|
);
|
|
pos = history_pos[ history ];
|
|
fprintf( stdout, "\r%*c", RTEMS_COMMAND_BUFFER_SIZE, ' ' );
|
|
fprintf( stdout, "\r%s $ %s", monitor_prompt, buffer );
|
|
end = (int) strlen( buffer );
|
|
for ( bs = 0; bs < ( end - pos ); bs++ ) {
|
|
putchar( '\b' );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case KEYS_DARROW:
|
|
if ( history < history_next ) {
|
|
int end;
|
|
int bs;
|
|
history++;
|
|
memcpy(
|
|
buffer,
|
|
history_buffer[ history ],
|
|
RTEMS_COMMAND_BUFFER_SIZE
|
|
);
|
|
pos = history_pos[ history ];
|
|
fprintf( stdout, "\r%*c", RTEMS_COMMAND_BUFFER_SIZE, ' ' );
|
|
fprintf( stdout, "\r%s $ %s", monitor_prompt, buffer );
|
|
end = (int) strlen( buffer );
|
|
for ( bs = 0; bs < ( end - pos ); bs++ ) {
|
|
putchar( '\b' );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case KEYS_DEL:
|
|
if ( buffer[ pos ] != '\0' ) {
|
|
int end;
|
|
int bs;
|
|
memmove(
|
|
&buffer[ pos ],
|
|
&buffer[ pos + 1 ],
|
|
strlen( &buffer[ pos + 1 ] ) + 1
|
|
);
|
|
fprintf( stdout, "\r%s $ %s", monitor_prompt, buffer );
|
|
end = (int) strlen( buffer );
|
|
for ( bs = 0; bs < ( end - pos ); bs++ ) {
|
|
putchar( '\b' );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
switch ( c ) {
|
|
case '\b':
|
|
case '\x7e':
|
|
case '\x7f':
|
|
if ( pos > 0 ) {
|
|
int bs;
|
|
pos--;
|
|
|
|
/*
|
|
* Memory operation used here instead of string
|
|
* method due the src and dest of buffer overlapping.
|
|
*/
|
|
memmove(
|
|
buffer + pos,
|
|
buffer + pos + 1,
|
|
RTEMS_COMMAND_BUFFER_SIZE - pos - 1
|
|
);
|
|
buffer[ RTEMS_COMMAND_BUFFER_SIZE - 1 ] = '\0';
|
|
fprintf( stdout, "\b%s \b", buffer + pos );
|
|
for ( bs = 0; bs < ( (int) strlen( buffer ) - pos ); bs++ ) {
|
|
putchar( '\b' );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case '\n':
|
|
/*
|
|
* Process the command.
|
|
*/
|
|
fprintf( stdout, "\n" );
|
|
repeating = 1;
|
|
/*
|
|
* Only process the history if we have a command and
|
|
*a history.
|
|
*/
|
|
if ( strlen( buffer ) ) {
|
|
if ( history_next && ( history == history_next ) ) {
|
|
/*
|
|
* Do not place the last command into the history
|
|
*if the same.
|
|
*/
|
|
if ( strcmp( history_buffer[ history_next - 1 ], buffer ) ) {
|
|
repeating = 0;
|
|
}
|
|
} else {
|
|
repeating = 0;
|
|
}
|
|
}
|
|
if ( !repeating ) {
|
|
memcpy(
|
|
history_buffer[ history_next ],
|
|
buffer,
|
|
RTEMS_COMMAND_BUFFER_SIZE
|
|
);
|
|
history_pos[ history_next ] = pos;
|
|
if ( history_next < ( RTEMS_COMMAND_HISTORIES - 1 ) ) {
|
|
history_next++;
|
|
} else {
|
|
memmove(
|
|
history_buffer[ 0 ],
|
|
history_buffer[ 1 ],
|
|
RTEMS_COMMAND_BUFFER_SIZE * ( RTEMS_COMMAND_HISTORIES - 1 )
|
|
);
|
|
memmove(
|
|
&history_pos[ 0 ],
|
|
&history_pos[ 1 ],
|
|
sizeof( history_pos[ 0 ] ) * ( RTEMS_COMMAND_HISTORIES - 1 )
|
|
);
|
|
}
|
|
} else {
|
|
#ifdef ENABLE_ENTER_REPEATS
|
|
if ( history_next ) {
|
|
memcpy(
|
|
buffer,
|
|
history_buffer[ history_next - 1 ],
|
|
RTEMS_COMMAND_BUFFER_SIZE
|
|
);
|
|
}
|
|
#endif
|
|
}
|
|
memmove( command, buffer, RTEMS_COMMAND_BUFFER_SIZE );
|
|
return repeating;
|
|
break;
|
|
|
|
default:
|
|
if (
|
|
( pos < ( RTEMS_COMMAND_BUFFER_SIZE - 1 ) ) && ( c >= ' ' ) &&
|
|
( c <= 'z' )
|
|
) {
|
|
int end;
|
|
end = strlen( buffer );
|
|
if ( ( pos < end ) && ( end < RTEMS_COMMAND_BUFFER_SIZE ) ) {
|
|
int ch, bs;
|
|
for ( ch = end; ch > pos; ch-- ) {
|
|
buffer[ ch ] = buffer[ ch - 1 ];
|
|
}
|
|
fprintf( stdout, "%s", buffer + pos );
|
|
for ( bs = 0; bs < ( end - pos + 1 ); bs++ ) {
|
|
putchar( '\b' );
|
|
}
|
|
}
|
|
buffer[ pos++ ] = c;
|
|
if ( pos > end ) {
|
|
buffer[ pos ] = '\0';
|
|
}
|
|
putchar( c );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* make_argv(cp): token-count
|
|
* Break up the command line in 'cp' into global argv[] and argc (return
|
|
* value).
|
|
*/
|
|
|
|
int rtems_monitor_make_argv( char *cp, int *argc_p, char **argv )
|
|
{
|
|
int argc = 0;
|
|
|
|
while (( cp = strtok( cp, " \t\n\r" ) )) {
|
|
argv[ argc++ ] = cp;
|
|
cp = (char *) NULL;
|
|
}
|
|
argv[ argc ] = (char *) NULL; /* end of argv */
|
|
|
|
return *argc_p = argc;
|
|
}
|
|
|
|
/*
|
|
* Read and break up a monitor command
|
|
*
|
|
* We have to loop on the gets call, since it will return NULL under UNIX
|
|
* RTEMS when we get a signal (eg: SIGALRM).
|
|
*/
|
|
|
|
int rtems_monitor_command_read( char *command, int *argc, char **argv )
|
|
{
|
|
char *env_prompt;
|
|
|
|
env_prompt = getenv( "RTEMS_MONITOR_PROMPT" );
|
|
|
|
/*
|
|
* put node number in the prompt if we are multiprocessing
|
|
*/
|
|
if ( rtems_monitor_default_node != rtems_monitor_node ) {
|
|
snprintf(
|
|
monitor_prompt,
|
|
sizeof( monitor_prompt ),
|
|
"%" PRId32 "-%s-%" PRId32 "",
|
|
rtems_monitor_node,
|
|
( env_prompt == NULL ) ? MONITOR_PROMPT : env_prompt,
|
|
rtems_monitor_default_node
|
|
);
|
|
} else {
|
|
snprintf(
|
|
monitor_prompt,
|
|
sizeof( monitor_prompt ),
|
|
"%" PRId32 "-%s",
|
|
rtems_monitor_node,
|
|
( env_prompt == NULL ) ? MONITOR_PROMPT : env_prompt
|
|
);
|
|
}
|
|
|
|
rtems_monitor_line_editor( command );
|
|
|
|
return rtems_monitor_make_argv( command, argc, argv );
|
|
}
|
|
|
|
/*
|
|
* Main monitor command loop
|
|
*/
|
|
|
|
void rtems_monitor_task( rtems_task_argument monitor_flags )
|
|
{
|
|
char command_buffer[ 513 ];
|
|
int argc;
|
|
char *argv[ 64 ];
|
|
bool verbose = false;
|
|
struct termios term;
|
|
|
|
/*
|
|
* Make the stdin stream characte not line based.
|
|
*/
|
|
|
|
if ( tcgetattr( STDIN_FILENO, &term ) < 0 ) {
|
|
fprintf( stdout, "rtems-monitor: cannot get terminal attributes.\n" );
|
|
} else {
|
|
/*
|
|
* No echo, no canonical processing.
|
|
*/
|
|
|
|
term.c_lflag &= ~( ECHO | ICANON | IEXTEN );
|
|
|
|
/*
|
|
* No sigint on BREAK, CR-to-NL off, input parity off,
|
|
* don't strip 8th bit on input, output flow control off
|
|
*/
|
|
|
|
term.c_lflag &= ~( INPCK | ISTRIP | IXON );
|
|
term.c_cc[ VMIN ] = 1;
|
|
term.c_cc[ VTIME ] = 0;
|
|
|
|
if ( tcsetattr( STDIN_FILENO, TCSANOW, &term ) < 0 ) {
|
|
fprintf( stdout, "cannot set terminal attributes\n" );
|
|
}
|
|
}
|
|
|
|
if ( !( monitor_flags & RTEMS_MONITOR_NOSYMLOAD ) ) {
|
|
rtems_monitor_symbols_loadup();
|
|
}
|
|
|
|
if ( monitor_flags & RTEMS_MONITOR_SUSPEND ) {
|
|
(void) rtems_monitor_suspend( RTEMS_NO_TIMEOUT );
|
|
}
|
|
|
|
for ( ;; ) {
|
|
const rtems_monitor_command_entry_t *command;
|
|
|
|
if ( 0 == rtems_monitor_command_read( command_buffer, &argc, argv ) ) {
|
|
continue;
|
|
}
|
|
if (
|
|
argc < 1 || ( command = rtems_monitor_command_lookup( argv[ 0 ] ) ) == 0
|
|
) {
|
|
/* no command */
|
|
fprintf( stdout, "Unrecognised command; try 'help'\n" );
|
|
continue;
|
|
}
|
|
|
|
command->command_function( argc, argv, &command->command_arg, verbose );
|
|
|
|
fflush( stdout );
|
|
}
|
|
}
|
|
|
|
void rtems_monitor_kill( void )
|
|
{
|
|
if ( rtems_monitor_task_id ) {
|
|
rtems_task_delete( rtems_monitor_task_id );
|
|
}
|
|
rtems_monitor_task_id = 0;
|
|
|
|
rtems_monitor_server_kill();
|
|
}
|
|
|
|
void rtems_monitor_init( uint32_t monitor_flags )
|
|
{
|
|
rtems_status_code status;
|
|
|
|
rtems_monitor_kill();
|
|
|
|
status = rtems_task_create(
|
|
RTEMS_MONITOR_NAME,
|
|
1,
|
|
RTEMS_MINIMUM_STACK_SIZE * 2,
|
|
RTEMS_INTERRUPT_LEVEL( 0 ),
|
|
RTEMS_DEFAULT_ATTRIBUTES,
|
|
&rtems_monitor_task_id
|
|
);
|
|
if ( status != RTEMS_SUCCESSFUL ) {
|
|
rtems_error( status, "could not create monitor task" );
|
|
return;
|
|
}
|
|
|
|
rtems_monitor_node = rtems_object_id_get_node( rtems_monitor_task_id );
|
|
rtems_monitor_default_node = rtems_monitor_node;
|
|
|
|
rtems_monitor_server_init( monitor_flags );
|
|
|
|
if ( !( monitor_flags & RTEMS_MONITOR_NOTASK ) ) {
|
|
/*
|
|
* Start the monitor task itself
|
|
*/
|
|
status = rtems_task_start(
|
|
rtems_monitor_task_id,
|
|
rtems_monitor_task,
|
|
monitor_flags
|
|
);
|
|
if ( status != RTEMS_SUCCESSFUL ) {
|
|
rtems_error( status, "could not start monitor" );
|
|
return;
|
|
}
|
|
}
|
|
}
|