Forums

Serial driver error handling

Started by Chris Carlen June 10, 2008
Hi:

Once again, I am writing a buffered, interrupt-driven driver for the 
serial comm UART (SCI) in the TI TMS320F2812.  The lowest level 
interface to the user will be a function

int SCI_getc(void);

returns the next character received or EOF if nothing is available.

However, if there is an error in the receiver, there appear to be two 
ways to inform the user space:


1.  On the call to SCI_getc() after all valid chars have been removed 
from the buffer, return a special code other than EOF, such as a:

#define SCI_RXERR -2  /* or something like that */

Now if detailed info on the nature of the error were needed in this 
case, a call such as SCI_status() could provide this.  In this case, the 
user mustn't always call SCI_status() after an EOF to find out if it was 
really no char available, or an error.

Since serial reception fundamentally differs from file IO, I find this 
option attractive.


2.  The second option is to return EOF always if there is no char 
available or there is an error, similar to fgetc().  Then the user would 
have to call another function SCI_status() or the like to get a code 
which can be parsed to determine the specific nature of the error.

Since the SCIx_getc() call will frequently return EOF while waiting for 
data, it seems cumbersome to always have to call SCI_status() to see if 
it was due to an error.


What is typically done?


Thanks for input.




-- 
Good day!

____________________________________
CRC
crobcREMOVETHIS@BOGUSsbcglobal.net
NOTE, delete texts: "REMOVETHIS" and
"BOGUS" from email address to reply.
In article <g2n10q0ee4@news4.newsguy.com>, Chris Carlen says...
> Hi: > > Once again, I am writing a buffered, interrupt-driven driver for the > serial comm UART (SCI) in the TI TMS320F2812. The lowest level > interface to the user will be a function > > int SCI_getc(void); > > returns the next character received or EOF if nothing is available. > > However, if there is an error in the receiver, there appear to be two > ways to inform the user space: > > > 1. On the call to SCI_getc() after all valid chars have been removed > from the buffer, return a special code other than EOF, such as a: > > #define SCI_RXERR -2 /* or something like that */ > > Now if detailed info on the nature of the error were needed in this > case, a call such as SCI_status() could provide this. In this case, the > user mustn't always call SCI_status() after an EOF to find out if it was > really no char available, or an error. > > Since serial reception fundamentally differs from file IO, I find this > option attractive.
Note this also requires that your returned value be larger than a char, a failing shared by the C character level input fuctions.
> 2. The second option is to return EOF always if there is no char > available or there is an error, similar to fgetc(). Then the user would > have to call another function SCI_status() or the like to get a code > which can be parsed to determine the specific nature of the error. > > Since the SCIx_getc() call will frequently return EOF while waiting for > data, it seems cumbersome to always have to call SCI_status() to see if > it was due to an error. > > > What is typically done?
Option 3. Ignore them except as needed to clear them from the hardware (and maybe collect stats). Leaving error check up to higher level protocols. Option 3 is certainly common, I won't call it typical. There's often little to be gained by error checking at the individual byte level. Robert ** Posted from http://www.teranews.com **
On Tue, 10 Jun 2008 19:50:34 -0400, Robert Adsett
<sub2@aeolusdevelopment.com> wrote in comp.arch.embedded:

> In article <g2n10q0ee4@news4.newsguy.com>, Chris Carlen says... > > Hi: > > > > Once again, I am writing a buffered, interrupt-driven driver for the > > serial comm UART (SCI) in the TI TMS320F2812. The lowest level > > interface to the user will be a function > > > > int SCI_getc(void); > > > > returns the next character received or EOF if nothing is available. > > > > However, if there is an error in the receiver, there appear to be two > > ways to inform the user space: > > > > > > 1. On the call to SCI_getc() after all valid chars have been removed > > from the buffer, return a special code other than EOF, such as a: > > > > #define SCI_RXERR -2 /* or something like that */ > > > > Now if detailed info on the nature of the error were needed in this > > case, a call such as SCI_status() could provide this. In this case, the > > user mustn't always call SCI_status() after an EOF to find out if it was > > really no char available, or an error. > > > > Since serial reception fundamentally differs from file IO, I find this > > option attractive. > > Note this also requires that your returned value be larger than a char, > a failing shared by the C character level input fuctions.
Well, yes and no. The 2812 does not have 8-bit bytes, CHAR_BIT is 16. sizeof(int) == sizeof(char) == 1. But the SCI is an 8-bit peripheral. All reads from the SCI Rx data register return some value in the low 8 bits, and zeros in the high 8 bits. So one can easily pick patterns above 255 to use for any special purpose indicators. -- Jack Klein Home: http://JK-Technology.Com FAQs for comp.lang.c http://c-faq.com/ comp.lang.c++ http://www.parashift.com/c++-faq-lite/ alt.comp.lang.learn.c-c++ http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
On Tue, 10 Jun 2008 15:59:32 -0700, Chris Carlen
<crcarleREMOVETHIS@BOGUSsbcglobal.net> wrote in comp.arch.embedded:

> Hi: > > Once again, I am writing a buffered, interrupt-driven driver for the > serial comm UART (SCI) in the TI TMS320F2812. The lowest level > interface to the user will be a function > > int SCI_getc(void); > > returns the next character received or EOF if nothing is available.
You may have to decide if EOF is optimum. You are using in a way that is different than in C FILE * operations. Your caller could receive EOF now, and without doing anything he can receive a valid data value if a character has been received since then. That doesn't happen in C streams.
> However, if there is an error in the receiver, there appear to be two > ways to inform the user space: > > > 1. On the call to SCI_getc() after all valid chars have been removed > from the buffer, return a special code other than EOF, such as a: > > #define SCI_RXERR -2 /* or something like that */ > > Now if detailed info on the nature of the error were needed in this > case, a call such as SCI_status() could provide this. In this case, the > user mustn't always call SCI_status() after an EOF to find out if it was > really no char available, or an error. > > Since serial reception fundamentally differs from file IO, I find this > option attractive. > > > 2. The second option is to return EOF always if there is no char > available or there is an error, similar to fgetc(). Then the user would > have to call another function SCI_status() or the like to get a code > which can be parsed to determine the specific nature of the error. > > Since the SCIx_getc() call will frequently return EOF while waiting for > data, it seems cumbersome to always have to call SCI_status() to see if > it was due to an error.
You do realize that the SCI is an 8-bit peripheral on an architecture with 16-bit registers, don't you? No data value read from the UART will ever be outside the range of 0 to 255. That leaves you an enormous number of values to define as various status indicators, rather than data. Consider something like: enum { SCI_NO_DATA = 0x100, SCI_PARITY_ERROR = 0x101, SCI_OVERFLOW_ERROR = 0x102, SCI_FRAMING_ERROR = 0x103, SCI_BREAK_RECEIVED = 0x104 /* continue as needed */ }; This enumeration is defined in a header that includes the prototypes of API functions. Then your user merely has to do: int val = SCI_Get(); if (val < SCI_NO_DATA) { /* do something with data */ } else { /* handle errors, perhaps with a switch on the enum value */ }
> What is typically done? > > > Thanks for input.
-- Jack Klein Home: http://JK-Technology.Com FAQs for comp.lang.c http://c-faq.com/ comp.lang.c++ http://www.parashift.com/c++-faq-lite/ alt.comp.lang.learn.c-c++ http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
In article <2udu44pu3c5bs1n7a0ccr60anbo9jk4m5o@4ax.com>, Jack Klein 
says...
> On Tue, 10 Jun 2008 19:50:34 -0400, Robert Adsett > <sub2@aeolusdevelopment.com> wrote in comp.arch.embedded: > > Note this also requires that your returned value be larger than a char, > > a failing shared by the C character level input fuctions. > > Well, yes and no. The 2812 does not have 8-bit bytes, CHAR_BIT is 16. > sizeof(int) == sizeof(char) == 1.
Missed that part. Robert ** Posted from http://www.teranews.com **
Jack Klein wrote:
> On Tue, 10 Jun 2008 15:59:32 -0700, Chris Carlen > <crcarleREMOVETHIS@BOGUSsbcglobal.net> wrote in comp.arch.embedded: >>int SCI_getc(void); >>returns the next character received or EOF if nothing is available. > > You may have to decide if EOF is optimum. You are using in a way that > is different than in C FILE * operations. Your caller could receive > EOF now, and without doing anything he can receive a valid data value > if a character has been received since then. That doesn't happen in C > streams.
Yes. In discussions with our main programmer here (I am mainly an electronics and laser/optics guy, but also like to do low-level programming) he mentions that most programmers tend to agree that serial IO doesn't fit the C stream model well, mainly since the serial port may have nothing available at times, which doesn't mean that it is the end of file. We also got into a discussion of different models for the operation of a SCI_getc() like function. I was designing my function to not block, but just return EOF as a "nothing available" indicator. It would be up to higher level code (the protocol level) to determine the significance of this. He tends to think the SCI_getc() call *should* block until something is available to return, or timeout and then return an EOF, in which case EOF has a somewhat different significance than in the non-blocking case. I like the non-blocking timeout model since my usage might be listening to human types commands at a terminal, for which it is impossible to define a timeout. What if the guy/gal takes their lunch break in the middle of typing a command?
>>However, if there is an error in the receiver, there appear to be two >>ways to inform the user space: >> >> >>1. On the call to SCI_getc() after all valid chars have been removed >>from the buffer, return a special code other than EOF, such as a: >> >>#define SCI_RXERR -2 /* or something like that */ >> >>Now if detailed info on the nature of the error were needed in this >>case, a call such as SCI_status() could provide this. In this case, the >>user mustn't always call SCI_status() after an EOF to find out if it was >>really no char available, or an error. >> >>Since serial reception fundamentally differs from file IO, I find this >>option attractive. >> >> >>2. The second option is to return EOF always if there is no char >>available or there is an error, similar to fgetc(). Then the user would >>have to call another function SCI_status() or the like to get a code >>which can be parsed to determine the specific nature of the error. >> >>Since the SCIx_getc() call will frequently return EOF while waiting for >>data, it seems cumbersome to always have to call SCI_status() to see if >>it was due to an error. > > You do realize that the SCI is an 8-bit peripheral on an architecture > with 16-bit registers, don't you?
Yes, though actually it has 32 bit registers; but at most 16 bit IO registers, granted. The char type is defined identical to int, so one can't really work with 8 bit bytes, and reads from 8 bit registers automatically "cast" to ints. That is why my first option shown above is to use the upper byte range for an error code. This isn't really afforded by the architecture though. It is simply a choice of how to define the return value of the function. The gist of my question was mainly to determine if the mood among programmers was such that deviations from some standard model are looked down upon, and also to see if there is any sense of standardization of APIs to talk to UARTs at all, at the embedded device level. This doesn't appear to be the case, which encourages me to do something exactly like I mentioned and you detail below...
>No data value read from the UART > will ever be outside the range of 0 to 255. That leaves you an > enormous number of values to define as various status indicators, > rather than data. > > Consider something like: > > enum { > SCI_NO_DATA = 0x100, > SCI_PARITY_ERROR = 0x101, > SCI_OVERFLOW_ERROR = 0x102, > SCI_FRAMING_ERROR = 0x103, > SCI_BREAK_RECEIVED = 0x104 > /* continue as needed */ > }; > > This enumeration is defined in a header that includes the prototypes > of API functions. > > Then your user merely has to do: > > int val = SCI_Get(); > if (val < SCI_NO_DATA) > { > /* do something with data */ > } > else > { > /* handle errors, perhaps with a switch on the enum value */ > } >
Yes, exactly. -- Good day! ____________________________________ CRC crobcREMOVETHIS@BOGUSsbcglobal.net NOTE, delete texts: "REMOVETHIS" and "BOGUS" from email address to reply.
On 2008-06-11, Chris Carlen <crcarleREMOVETHIS@BOGUSsbcglobal.net> wrote:
> > Yes. In discussions with our main programmer here (I am mainly an > electronics and laser/optics guy, but also like to do low-level > programming) he mentions that most programmers tend to agree that serial > IO doesn't fit the C stream model well, mainly since the serial port may > have nothing available at times, which doesn't mean that it is the end > of file. > > We also got into a discussion of different models for the operation of a > SCI_getc() like function. I was designing my function to not block, but > just return EOF as a "nothing available" indicator. It would be up to > higher level code (the protocol level) to determine the significance of > this. > > He tends to think the SCI_getc() call *should* block until something is > available to return, or timeout and then return an EOF, in which case > EOF has a somewhat different significance than in the non-blocking case. > > I like the non-blocking timeout model since my usage might be listening > to human types commands at a terminal, for which it is impossible to > define a timeout. What if the guy/gal takes their lunch break in the > middle of typing a command?
I'd suggest taking a look at how Unix non-blocking I/O works - the ideas there have been well tested with real world experience. There you have two functions for dealing with reading data. read() functions as you would expect, however if there is no data available it returns -1 - not EOF (even though these are the same thing, conceptually there is a difference). errno is set to indicate why -1 was returned, so you have different codes for EOF, no data, hardware error etc. Applying these concepts to your situation that suggests two distinct functions - your SCI_getc() function like you have now, probably in 'non-blocking' trim, and an SCI_poll() function that tells you how many characters are available to be read. Alternatively, SCI_poll() could simply have a boolean sense, telling you if there is any input waiting to be read. This approach has the merit that you can test for the presence of input in a completely different area of code to where you actually read it, so for example you can have such a test in your program main loop and only call your 'process input' stuff when it is actually needed. -- Andrew Smallshaw andrews@sdf.lonestar.org