|
|
||
|
|
||
|
|
||
MicroMonitor also includes support for command-line redirection. Command-line redirection is handy, for example, to log the output of a command to a file. My primary motivation for adding command-line redirection is to support the ability to dump a stack trace output to a file.
I discussed exception handling earlier. In the
next few chapters, I will describe a flash file system and show how to dump an application stack. Consider the case where your system is in the field and taking a strange exception every other blue moon. How do you find the cause for thestrange exception without camping out at the customer site? If the exception handler has the optional ability to execute a specified script (from the file system), then that script, among other things, can issue a stack trace command ( strace ) and redirect the output to a file. If this script has been activated, when the customer calls saying that something appears to have crashed and restarted, you can query the file system for the trace output file and see what caused the exception.
By default all
printf
output
echo hey you >filename
This syntax isnt good for MicroMonitors command-line redirection because I want the output to go to RAM first. So I deviate slightly with two different forms:
echo hey you > buffer, buffer_size[, filename]
This format consists of single right arrow with a one- or two-comma delimited string containing a buffer address followed by the size of the buffer and an optional filename. If the filename is specified, the output of the command is
copied to the buffer (truncated at buffer_size if necessary) and then transferred to TFS as filename . The running buffer pointer is reset back to the base address of buffer . If a filename is omitted, the output of the command is copied to the buffer, and the pointer into the buffer is left at the position following the data (assuming buffer_size is not reached).
echo hey you again >>[filename]
This syntax is used to append the output of the command to the buffer that was created by the > syntax described above. If a filename is included, the content of the buffer is transferred to TFS under the specified
name (in this example), and the running buffer pointer is reset to the base address of the buffer. If a filename is not specified, there is no transfer to a file, and the running pointer is incremented by one to the position just after the data copied (once again, assuming buffer_size is not reached).
To implement this feature, the function putchar() needs an additional call at the top (see Listing 5.7).
Listing 5.7: Adding Redirection to putchar().
|
|
int
putchar(uchar c)
{
RedirectCharacter(c);
if (c == '\n')
rputchar('\r');
rputchar(c);
return((int)c);
}
|
|
The
RedirectCharacter()
function (see Listing 5.8) looks at a state to determine if it does anything at all. The
RedirectCharacter()
function either does nothing or, after checking to see that the running buffer pointer has not reached the end of the buffer, copies the character to the buffer space and
Listing 5.8: RedirectCharacter().
|
|
void
RedirectCharacter(char c)
{
if (RedirectState == REDIRECT_ACTIVE) {
if (RedirectPtr < RedirectEnd)
*RedirectPtr++ = c;
}
}
|
|
I must also modify docommand() so it can recognize the redirection syntax (set RedirectState to REDIRECT_ACTIVE ) and, when appropriate, notify the redirection code that the command has completed (set RedirectState back to REDIRECT_IDLE ). So I must add a few lines to docommand() .
if (RedirectionCheck(cmdcpy) == -1)
return(CMD_LINE_ERROR);
I insert the
echo hi >$APPRAMBASE,100
and know that when
RedirectionCheck()
is called, the content of
$APPRAMBASE
has already been converted to a physical address by the CLI shell-variable processor described previously. At the bottom of
docommand()
, I add another call to
The RedirectionCheck() function (see Listing 5.9) starts by looking through the line for the redirection symbol. If, at the end of the line, RedirectionCheck() hasnt found a right arrow ( > ), it simply returns. If it finds a second arrow, then RedirectState should already be REDIRECT_ACTIVE; any other state indicates an error. If RedirectState is correct, then RedirectionCheck() looks for a filename and stores it away for use later. Finally, when RedirectionCheck() does not find a second arrow, it processes the comma-delimited string after the arrow and establishes pointers and counters appropriately.
Listing 5.9: Parsing Redirection Commands.
|
|
#define REDIRECT_UNINITIALIZED 0
#define REDIRECT_ACTIVE 0x12345678
#define REDIRECT_IDLE 0x87654321
static int RedirectSize, RedirectState;
static char *RedirectBase, *RedirectPtr, *RedirectEnd;
static char RedirectFile[TFSNAMESIZE];
int
RedirectionCheck(char *cmdcpy)
{
int inquote;
char *arrow, *base, *comma, *space;
base = cmdcpy;
arrow = (char *)0;
/* Parse the incoming command line looking for a right arrow.
* This parsing assumes that there will be no negated arrows
* (preceding backslash) after a non-negated arrow is detected.
* Note that a redirection arrow within a double-quote set is
* ignored. This allows a shell variable that contains a right arrow
* to be printed properly if put in double quotes.
* For example...
* set PROMPT "maint> "
* echo $PROMPT # This will generate a redirection syntax error
* echo "$PROMPT" # This won't.
*/
inquote = 0;
while(*cmdcpy) {
if ((*cmdcpy == '"') && ((cmdcpy == base) (*(cmdcpy-1) != '\'))) {
inquote = inquote == 1 ? 0 : 1;
cmdcpy++;
continue;
}
if (inquote == 1) {
cmdcpy++;
continue;
}
if (*cmdcpy == '>') {
arrow = cmdcpy;
if (*(arrow-1) == '\') {
strcpy(arrow-1,arrow);
cmdcpy = arrow+1;
arrow = (char *)0;
continue;
}
break;
}
cmdcpy++;
}
if (arrow == (char *)0)
return(0);
/* Remove the remaining text from the command line because it is to
* be used only by the redirection mechanism.
*/
*arrow = 0;
/* Now parse the text after the first non-negated arrow. */
if (*(arrow+1) == '>') {
if (RedirectState == REDIRECT_UNINITIALIZED) {
printf("Redirection not initialized\n");
return(-1);
}
arrow += 2;
while(isspace(*arrow))
arrow++;
if (*arrow != 0)
strncpy(RedirectFile,arrow,TFSNAMESIZE);
}
else {
RedirectPtr = RedirectBase = (char *)strtoul(arrow+1,&comma,0);
if (*comma == ',') {
RedirectSize = (int)strtol(comma+1,&comma,0);
if (RedirectSize <= 0) {
printf("Redirection size error: %d\n",RedirectSize);
return(-1);
}
RedirectEnd = RedirectBase + RedirectSize;
if (*comma == ',') {
space = strpbrk(comma," \t\r\n");
if (space)
*space = 0;
strncpy(RedirectFile,comma+1,TFSNAMESIZE);
}
else
RedirectFile[0] = 0;
}
else {
printf("Redirection syntax error\n");
return(-1);
}
}
RedirectState = REDIRECT_ACTIVE;
return(0);
}
|
|
Finally, docommand() informs the redirection code that the command completed by calling RedirectionCmdDone() (see Listing 5.10).
Listing 5.10: RedirectionCmdDone().
|
|
void
RedirectionCmdDone(void)
{
if (RedirectState != REDIRECT_UNINITIALIZED) {
RedirectState = REDIRECT_IDLE;
if (RedirectFile[0]) {
tfsadd(RedirectFile,0,0,(uchar *)RedirectBase,
(int)(RedirectPtr-RedirectBase));
RedirectFile[0] = 0;
RedirectPtr = RedirectBase;
}
}
}
|
|
If the state has been previously initialized (by RedirectionCheck() ) this function checks for the presence of the redirection filename. The redirection filename is only present if the filename was specified as part of the command. Assuming the redirection filename is set, the buffer is transferred to a file using the flash file system call tfsadd() , which simply transfers a block of memory to a file in the flash file system.
Although in some
|
|
||
|
|
||
|
|
||

Embedded Linux Primer: A Practical Real-World Approach (2nd Edition)

An Embedded Software Primer

Embedded Systems Building Blocks, Second Edition: Complete and Ready-to-Use Modules in C

ARM System Developer's Guide: Designing and Optimizing System Software (The Morgan Kaufmann Series in Computer Architecture and Design)