Reply by George Neuner February 1, 20092009-02-01
On Wed, 28 Jan 2009 16:18:43 -0600, "eeboy" <jason@jasonorsborn.com>
wrote:

>I guess I am ignorant on streams. What is the difference between a buffer >and a stream and how do I implement a stream?
"stream" differentiates from "block". In block I/O all reads/writes have the same length - think of how a file is stored on disk. Stream I/O allows read and writes of variable length. Buffering, per se, has nothing to do with either type of I/O ... it is an optimization that is applicable to both forms. C's I/O model is stream based. It's unlikely that you have to implement anything unless your chip is very new. If you can read/write/ioctl the device then you're all set. George
Reply by January 31, 20092009-01-31
eeboy wrote:

> I guess I am ignorant on streams. What is the difference between a buffer > and a stream
What is the difference between a reservoir and a pipeline?
> and how do I implement a stream?
You don't. You use it.
Reply by CBFalconer January 28, 20092009-01-28
eeboy wrote:
>> eeboy wrote: >> >> ... snip ... >> >>> Regarding the deciphering of arguments. The functions atoi,atof, >>> atol would really come in handy here ,but from what I have picked >>> up in the recent months, including stdlib.h is not recommended in >>> embedded apps? Comments? >> >> The following code is well suited to embedded operation, since it >> is purely portable standard C, and it deals with streams. This >> eliminates the need for various buffers. I have also released it >> for free use anywhere. The only area I am unhappy with is the >> conversion of signs in rdxint, which I want to be universal. The >> code can easily be mounted in a library. > > I guess I am ignorant on streams. What is the difference between > a buffer and a stream and how do I implement a stream?
You don't, the C system does. The natural form for file i/o in C is a stream. Just open the file with fopen, read it with getc, fgets, etc. and the system does its own buffering. -- [mail]: Chuck F (cbfalconer at maineline dot net) [page]: <http://cbfalconer.home.att.net> Try the download section.
Reply by eeboy January 28, 20092009-01-28
>eeboy wrote: >> >... snip ... >> >> Regarding the deciphering of arguments. The functions atoi,atof, >> atol would really come in handy here ,but from what I have picked >> up in the recent months, including stdlib.h is not recommended in >> embedded apps? Comments? > >The following code is well suited to embedded operation, since it >is purely portable standard C, and it deals with streams. This >eliminates the need for various buffers. I have also released it >for free use anywhere. The only area I am unhappy with is the >conversion of signs in rdxint, which I want to be universal. The >code can easily be mounted in a library. >
I guess I am ignorant on streams. What is the difference between a buffer and a stream and how do I implement a stream?
Reply by eeboy January 28, 20092009-01-28
>Falk Willberg wrote: > >Third, strtok is a nuisance to use, because it doesn't detect >missing tokens (i.e. successive delimiters). Therefore I have >build tknsplit, whose code follows, and is written in standard C >(thus portable) and is put in the public domain. >
Thanks! tknsplit will work quite nicely for parsing out commands.
Reply by CBFalconer January 25, 20092009-01-25
Falk Willberg wrote:
> eeboy schrieb: > > > I am attempting to write a command line interface for my embedded > > application (LM3S1439 based). I would like some advice on how to best > > approach it. >
... snip ...
> > NAME > strtok, strtok_r - extract tokens from strings > > SYNOPSIS > #include <string.h> > > char *strtok(char *str, const char *delim); > > char *strtok_r(char *str, const char *delim, char **saveptr); > > DESCRIPTION > The strtok() function parses a string into a sequence of tokens.
... snip ... Three things. First, the description of functions in the C standard is much more accurate than various help manuals. Second, strtok_r does not exist in standard C, so you can't count on it. Even if it exists in your system, there is no guarantee it follows the above description. Third, strtok is a nuisance to use, because it doesn't detect missing tokens (i.e. successive delimiters). Therefore I have build tknsplit, whose code follows, and is written in standard C (thus portable) and is put in the public domain. /* ------- file tknsplit.c ----------*/ #include "tknsplit.h" /* copy over the next tkn from an input string, after skipping leading blanks (or other whitespace?). The tkn is terminated by the first appearance of tknchar, or by the end of the source string. The caller must supply sufficient space in tkn to receive any tkn, Otherwise tkns will be truncated. Returns: a pointer past the terminating tknchar. This will happily return an infinity of empty tkns if called with src pointing to the end of a string. Tokens will never include a copy of tknchar. A better name would be "strtkn", except that is reserved for the system namespace. Change to that at your risk. released to Public Domain, by C.B. Falconer. Published 2006-02-20. Attribution appreciated. Revised 2006-06-13 2007-05-26 (name) */ const char *tknsplit(const char *src, /* Source of tkns */ char tknchar, /* tkn delimiting char */ char *tkn, /* receiver of parsed tkn */ size_t lgh) /* length tkn can receive */ /* not including final '\0' */ { if (src) { while (' ' == *src) src++; while (*src && (tknchar != *src)) { if (lgh) { *tkn++ = *src; --lgh; } src++; } if (*src && (tknchar == *src)) src++; } *tkn = '\0'; return src; } /* tknsplit */ #ifdef TESTING #include <stdio.h> #define ABRsize 6 /* length of acceptable tkn abbreviations */ /* ---------------- */ static void showtkn(int i, char *tok) { putchar(i + '1'); putchar(':'); puts(tok); } /* showtkn */ /* ---------------- */ int main(void) { char teststring[] = "This is a test, ,, abbrev, more"; const char *t, *s = teststring; int i; char tkn[ABRsize + 1]; puts(teststring); t = s; for (i = 0; i < 4; i++) { t = tknsplit(t, ',', tkn, ABRsize); showtkn(i, tkn); } puts("\nHow to detect 'no more tkns' while truncating"); t = s; i = 0; while (*t) { t = tknsplit(t, ',', tkn, 3); showtkn(i, tkn); i++; } puts("\nUsing blanks as tkn delimiters"); t = s; i = 0; while (*t) { t = tknsplit(t, ' ', tkn, ABRsize); showtkn(i, tkn); i++; } return 0; } /* main */ #endif /* ------- end file tknsplit.c ----------*/ /* ------- file tknsplit.h ----------*/ #ifndef H_tknsplit_h # define H_tknsplit_h # ifdef __cplusplus extern "C" { # endif #include <stddef.h> /* copy over the next tkn from an input string, after skipping leading blanks (or other whitespace?). The tkn is terminated by the first appearance of tknchar, or by the end of the source string. The caller must supply sufficient space in tkn to receive any tkn, Otherwise tkns will be truncated. Returns: a pointer past the terminating tknchar. This will happily return an infinity of empty tkns if called with src pointing to the end of a string. Tokens will never include a copy of tknchar. released to Public Domain, by C.B. Falconer. Published 2006-02-20. Attribution appreciated. revised 2007-05-26 (name) */ const char *tknsplit(const char *src, /* Source of tkns */ char tknchar, /* tkn delimiting char */ char *tkn, /* receiver of parsed tkn */ size_t lgh); /* length tkn can receive */ /* not including final '\0' */ # ifdef __cplusplus } # endif #endif /* ------- end file tknsplit.h ----------*/ -- [mail]: Chuck F (cbfalconer at maineline dot net) [page]: <http://cbfalconer.home.att.net> Try the download section.
Reply by Falk Willberg January 25, 20092009-01-25
eeboy schrieb:
> I am attempting to write a command line interface for my embedded > application (LM3S1439 based). I would like some advice on how to best > approach it. > > Some of my specifications would be: > > -the CLI should communicate with any terminal emulator. > -the backspace key should work as intended > -other controls like arrow keys etc not necessary and should be ignored > -the enter key delimits the command entry > -command names vary in length > -command arguments vary in number > -multiple argument types (ex: cmr -p=4 -f=true -z=22.5)
NAME strtok, strtok_r - extract tokens from strings SYNOPSIS #include <string.h> char *strtok(char *str, const char *delim); char *strtok_r(char *str, const char *delim, char **saveptr); DESCRIPTION The strtok() function parses a string into a sequence of tokens. On the first call to strtok() the string to be parsed should be specified in str. In each subsequent call that should parse the same string, str should be NULL. The delim argument specifies a set of characters that delimit the tokens in the parsed string. The caller may specify different strings in delim in successive calls that parse the same string. Falk
Reply by rickman January 24, 20092009-01-24
On Jan 24, 4:37=A0pm, "eeboy" <ja...@jasonorsborn.com> wrote:
> I am attempting to write a command line interface for my embedded > application (LM3S1439 based). I would like some advice on how to best > approach it. > > Some of my specifications would be: > > -the CLI should communicate with any terminal emulator. > -the backspace key should work as intended > -other controls like arrow keys etc not necessary and should be ignored > -the enter key delimits the command entry > -command names vary in length > -command arguments vary in number > -multiple argument types (ex: =A0cmr -p=3D4 -f=3Dtrue -z=3D22.5) > -binary transfer mode (ymodem transfer?) > -new commands implemented with ease (subjective, I know, but the point is > it should be extensible/flexible) > > At the moment I have the UART receive interrupt grabbing chars from the > input buffer examining them for a few control characters which I wish to > observe (BS,CR,LF), as well as dumping chars I am not concerned about > (other ASCII control chars) and stuffing the remaining chars into a comma=
nd
> buffer. This all works quite well via several terminal emulators. > > The idea was that once a CR or LF was detected the command buffer would b=
e
> evaluated/compared against an array of structures which contained the nam=
e
> (string) of the command as well as a pointer to the appropriate function =
to
> be called. The function would be called and supplied the number of > arguments and the pointer to the argument string. > > I think that makes sense. Any suggestions on how best to structure this? > This could get messy very quickly if not done right. > > To further complicate issues I have the requirement to receive binary > data. How do I best handle this transfer? I was thinking I could have a > global flag that could be set as COMMAND or BINARY. If set as COMMAND the=
n
> the incoming data would be processed as above. If not, then the data woul=
d
> be passed without interpretation to a buffer called out by the function > requesting the binary transfer. Reasonable? > > Regarding the deciphering of arguments. The functions atoi,atof, atol > would really come in handy here ,but from what I have picked up in the > recent months, including stdlib.h is not recommended in embedded apps? > Comments?
You seem to be focused on the C language. If you take a look at the Forth language, you will find that it already does some 70% or more of what you are asking for. If you make a few adjustments to your command line syntax, it will do as much as 100% of what you want in terms of parsing your command line. For example, you wrote cmr -p=3D4 - f=3Dtrue -z=3D22.5. Forth typically requires that the words it natively recognizes be separated by spaces. So you might change your syntax to cmr -p=3D 4 -f=3D true -z=3D 22.5, then it will be very simple to write som= e code to parse this line. Even better might be to reverse the order of parameters, such as 4 -p=3D true -f=3D 22.5 -z=3D cmr, but this is not necessary, it just simplifies the code a bit. You can get Forth from both Forth, Inc and MPE (MicroProcessor Engineering, Ltd). The low water mark of price is about $500, IIRC. I'm not certain they directly support the ARM CM3, but I expect they might be willing to work with you on that. I know the CM3 is the new market for ARM and will only be increasing market share. Rick
Reply by CBFalconer January 24, 20092009-01-24
eeboy wrote:
>
... snip ...
> > Regarding the deciphering of arguments. The functions atoi,atof, > atol would really come in handy here ,but from what I have picked > up in the recent months, including stdlib.h is not recommended in > embedded apps? Comments?
The following code is well suited to embedded operation, since it is purely portable standard C, and it deals with streams. This eliminates the need for various buffers. I have also released it for free use anywhere. The only area I am unhappy with is the conversion of signs in rdxint, which I want to be universal. The code can easily be mounted in a library. /* ------------------------------------------------- * * File txtinput.c * * ------------------------------------------------- */ #include <limits.h> /* xxxx_MAX, xxxx_MIN */ #include <ctype.h> /* isdigit, isblank, isspace */ #include <stdio.h> /* FILE, getc, ungetc */ #include "txtinput.h" /* For licensing restrictions (GPL) see readme.txt in: * <http://cbfalconer.home.att.net/download/txtio.zip> * * These stream input routines are written so that simple * conditionals can be used: * * if (readxint(&myint, stdin)) { * do_error_recovery; normally_abort_to_somewhere; * } * else { * do_normal_things; usually_much_longer_than_bad_case; * } * * They allow overflow detection, and permit other routines to * detect the character that terminated a numerical field. No * string storage is required, thus there is no limitation on * the length of input fields. For example, a number entered * with a string of 1000 leading zeroes will not annoy these. * * The numerical input routines *NEVER* absorb a terminating * char (including '\n'). Thus a sequence such as: * * err = readxint(&myint, stdin); * flushln(stdin); * * will always consume complete lines, and after execution of * readxint a further getc (or fgetc) will return the character * that terminated the numeric field. * * They are also re-entrant, subject to the limitations of file * systems. e.g interrupting readxint(v, stdin) operation with * a call to readxwd(wd, stdin) would not be well defined, if * the same stdin is being used for both calls. If ungetc is * interruptible the run-time system is broken. * * Originally issued 2002-10-07 * * Revised 2006-01-15 so that unsigned entry overflow (readxwd) uses the normal C modulo (UINT_MAX + 1) operation. readxwd still rejects an initial sign as an error. * * Modified to allow free use - C.B. Falconer 2008-01-16 */ /* ------------------------------------------------------------- * Skip to non-blank on f, and return that char. or EOF The next * char that getc(f) will return is unknown. Local use only. */ static int ignoreblks(FILE *f) { int ch; do { ch = getc(f); } while ((' ' == ch) || ('\t' == ch)); /* while (isblank(ch)); */ /* for C99 */ return ch; } /* ignoreblks */ /*-------------------------------------------------------------- * Skip all blanks on f. At completion getc(f) will return * a non-blank character, which may be \n or EOF * * Skipblks returns the char that getc will next return, or EOF. */ int skipblks(FILE *f) { return ungetc(ignoreblks(f), f); } /* skipblks */ /*-------------------------------------------------------------- * Skip all whitespace on f, including \n, \f, \v, \r. At * completion getc(f) will return a non-blank character, which * may be EOF * * Skipwhite returns the char that getc will next return, or EOF. */ int skipwhite(FILE *f) { int ch; do { ch = getc(f); } while (isspace(ch)); return ungetc(ch, f); } /* skipwhite */ /*-------------------------------------------------------------- * Read an unsigned value. Signal error for overflow or no * valid number found. Returns 1 for error, 0 for noerror, EOF * for EOF encountered before parsing a value. * * Skip all leading blanks on f. At completion getc(f) will * return the character terminating the number, which may be \n * or EOF among others. Barring EOF it will NOT be a digit. The * combination of error, 0 result, and the next getc returning * \n indicates that no numerical value was found on the line. * * If the user wants to skip all leading white space including * \n, \f, \v, \r, he should first call "skipwhite(f);" * * Peculiarity: This specifically forbids a leading '+' or '-'. */ int readxwd(unsigned int *wd, FILE *f) { unsigned int value, digit; int status; int ch; #define UWARNLVL (UINT_MAX / 10U) #define UWARNDIG (UINT_MAX - UWARNLVL * 10U) value = 0; /* default */ status = 1; /* default error */ ch = ignoreblks(f); if (EOF == ch) status = EOF; else if (isdigit(ch)) status = 0; /* digit, no error */ while (isdigit(ch)) { digit = ch - '0'; if ((value > UWARNLVL) || ((UWARNLVL == value) && (digit > UWARNDIG))) { status = 1; /* overflow */ value -= UWARNLVL; } value = 10 * value + digit; ch = getc(f); } /* while (ch is a digit) */ *wd = value; ungetc(ch, f); return status; } /* readxwd */ /*-------------------------------------------------------------- * Read a signed value. Signal error for overflow or no valid * number found. Returns true for error, false for noerror. On * overflow either INT_MAX or INT_MIN is returned in *val. * * Skip all leading blanks on f. At completion getc(f) will * return the character terminating the number, which may be \n * or EOF among others. Barring EOF it will NOT be a digit. The * combination of error, 0 result, and the next getc returning * \n indicates that no numerical value was found on the line. * * If the user wants to skip all leading white space including * \n, \f, \v, \r, he should first call "skipwhite(f);" * * Peculiarity: an isolated leading '+' or '-' NOT immediately * followed by a digit will return error and a value of 0, when * the next getc will return that following non-digit. This is * caused by the single level ungetc available. * * This module needs further work. CBF 2008-01-16 */ int readxint(int *val, FILE *f) { unsigned int value; int status, negative; int ch; *val = value = 0; /* default */ status = 1; /* default error */ negative = 0; ch = ignoreblks(f); if (EOF != ch) { if (('+' == ch) || ('-' == ch)) { negative = ('-' == ch); ch = ignoreblks(f); /* absorb any sign */ } if (isdigit(ch)) { /* digit, no error */ ungetc(ch, f); status = readxwd(&value, f); ch = getc(f); /* This terminated readxwd */ } if (0 == status) { /* got initial digit and no readxwd overflow */ if (!negative && (value <= INT_MAX)) *val = value; else if (negative && (value < UINT_MAX) && ((value - 1) <= -(1 + INT_MIN))) *val = -value; else { /* overflow */ status = 1; /* do whatever the native system does */ if (negative) *val = -value; else *val = value; } } else if (negative) *val = -value; else *val = value; } ungetc(ch, f); return status; } /* readxint */ /*----------------------------------------------------- * Flush input through an end-of-line marker inclusive. */ void flushln(FILE *f) { int ch; do { ch = getc(f); } while (('\n' != ch) && (EOF != ch)); } /* flushln */ /* End of txtinput.c */ *********** The following is the .h file *********** #ifndef H_txtinput_h #define H_txtinput_h # ifdef __cplusplus extern "C" { # endif #include <stdio.h> /* For licensing restrictions (GPL) see readme.txt in: * <http://cbfalconer.home.att.net/download/txtio.zip> * * These stream input routines are written so that simple * conditionals can be used: * * if (readxint(&myint, stdin)) { * do_error_recovery; normally_abort_to_somewhere; * } * else { * do_normal_things; usually_much_longer_than_bad_case; * } * * They allow overflow detection, and permit other routines to * detect the character that terminated a numerical field. No * string storage is required, thus there is no limitation on * the length of input fields. For example, a number entered * with a string of 1000 leading zeroes will not annoy these. * * The numerical input routines *NEVER* absorb a terminating * char (including '\n'). Thus a sequence such as: * * err = readxint(&myint, stdin); * flushln(stdin); * * will always consume complete lines, and after execution of * readxint a further getc (or fgetc) will return the character * that terminated the numeric field. * * They are also re-entrant, subject to the limitations of file * systems. e.g interrupting readxint(v, stdin) operation with * a call to readxwd(wd, stdin) would not be well defined, if * the same stdin is being used for both calls. If ungetc is * interruptible the run-time system is broken. * Revised 2006-01-15 so that unsigned entry overflow (readxwd) uses the normal C modulo (UINT_MAX + 1) operation. readxwd still rejects an initial sign as an error. * * Modified to allow free use - C.B. Falconer 2008-01-16 */ /*-------------------------------------------------------------- * Skip all blanks on f. At completion getc(f) will return * a non-blank character, which may be \n or EOF * * Skipblks returns the char that getc will next return, or EOF. */ int skipblks(FILE *f); /*-------------------------------------------------------------- * Skip all whitespace on f, including \n, \f, \v, \r. At * completion getc(f) will return a non-blank character, which * may be EOF * * Skipblks returns the char that getc will next return, or EOF. */ int skipwhite(FILE *f); /*-------------------------------------------------------------- * Read an unsigned value. Signal error for overflow or no * valid number found. Returns 1 for error, 0 for noerror, EOF * for EOF encountered before parsing a value. * * Skip all leading blanks on f. At completion getc(f) will * return the character terminating the number, which may be \n * or EOF among others. Barring EOF it will NOT be a digit. The * combination of error, 0 result, and the next getc returning * \n indicates that no numerical value was found on the line. * * If the user wants to skip all leading white space including * \n, \f, \v, \r, he should first call "skipwhite(f);" * * Peculiarity: This specifically forbids a leading '+' or '-'. */ int readxwd(unsigned int *wd, FILE *f); /*-------------------------------------------------------------- * Read a signed value. Signal error for overflow or no valid * number found. Returns true for error, false for noerror. On * overflow either INT_MAX or INT_MIN is returned in *val. * * Skip all leading blanks on f. At completion getc(f) will * return the character terminating the number, which may be \n * or EOF among others. Barring EOF it will NOT be a digit. The * combination of error, 0 result, and the next getc returning * \n indicates that no numerical value was found on the line. * * If the user wants to skip all leading white space including * \n, \f, \v, \r, he should first call "skipwhite(f);" * * Peculiarity: an isolated leading '+' or '-' NOT immediately * followed by a digit will return error and a value of 0, when * the next getc will return that following non-digit. This is * caused by the single level ungetc available. */ int readxint(int *val, FILE *f); /*-------------------------------------------------------------- * Flush input through an end-of-line marker inclusive. */ void flushln(FILE *f); # ifdef __cplusplus } # endif #endif /* End of txtinput.h */ -- [mail]: Chuck F (cbfalconer at maineline dot net) [page]: <http://cbfalconer.home.att.net> Try the download section.
Reply by eeboy January 24, 20092009-01-24
I am attempting to write a command line interface for my embedded
application (LM3S1439 based). I would like some advice on how to best
approach it.

Some of my specifications would be:

-the CLI should communicate with any terminal emulator.
-the backspace key should work as intended
-other controls like arrow keys etc not necessary and should be ignored
-the enter key delimits the command entry
-command names vary in length
-command arguments vary in number
-multiple argument types (ex:  cmr -p=4 -f=true -z=22.5)
-binary transfer mode (ymodem transfer?)
-new commands implemented with ease (subjective, I know, but the point is
it should be extensible/flexible)

At the moment I have the UART receive interrupt grabbing chars from the
input buffer examining them for a few control characters which I wish to
observe (BS,CR,LF), as well as dumping chars I am not concerned about
(other ASCII control chars) and stuffing the remaining chars into a command
buffer. This all works quite well via several terminal emulators.

The idea was that once a CR or LF was detected the command buffer would be
evaluated/compared against an array of structures which contained the name
(string) of the command as well as a pointer to the appropriate function to
be called. The function would be called and supplied the number of
arguments and the pointer to the argument string.

I think that makes sense. Any suggestions on how best to structure this?
This could get messy very quickly if not done right.

To further complicate issues I have the requirement to receive binary
data. How do I best handle this transfer? I was thinking I could have a
global flag that could be set as COMMAND or BINARY. If set as COMMAND then
the incoming data would be processed as above. If not, then the data would
be passed without interpretation to a buffer called out by the function
requesting the binary transfer. Reasonable?

Regarding the deciphering of arguments. The functions atoi,atof, atol
would really come in handy here ,but from what I have picked up in the
recent months, including stdlib.h is not recommended in embedded apps?
Comments?

Thanks!