Using stdin and knowning the number of characters before reading

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi.

I am using AVR Studio 4 with avr-gcc complier for the atmega 8535 processor.

 

Also, I have;

#include <stdio.h>

#include <stlib.h>

in my program.

 

My issue is that if they is nothing in the stdin then my program needs to keep looping.  However using getchar() causes a wait for the character. 

I trust there is a standard way of coping with this problem???

 

When I was doing similar with the CodeVisionAVR compilier I was able to refer to a globel variable (implemented by my program) prior to any read operation.

 

Regard JC.......

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One way of dealing with this is to implement a circular receive buffer and set the uart up to interrupt and put the chars in the buffer. You would write a function to tell you if there is anything in the buffer and wire the getchar to retrieve chars from the buffer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

stdio defines fread which calls getchar() from the stdin device. Msdos had a function called kbhit() that returned nonzero if there was a char waiting in the uart. Usually one must 'tell' the runtime the address of  the getchar() routine (get the char from uart0,1,2,3 etc). If you write a kbhit() function you can call that before you call fread() which calls getchar(). This is described in the gcc FDEVSETUPSTREAM macro. I think. If you supply the getchar and putchar routines, you can make them inc and dec numchars, which you can look at to see how many chars are in the interrupt buffer.

 

 

Imagecraft compiler user

Last Edited: Sat. Apr 11, 2015 - 04:23 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi.

I should add to my initial write up.  The UART interface for the get character routine is;

 

int uart_getch(FILE *stream)
{
   unsigned char ch;

   while (!(UCSRA & (1<<RXC)));
   ch=UDR;  

   /* Echo the output back to the terminal */
   //                               uart_putch(ch,stream);      

   return ch;
}

 

 

And this is integrated with;

 

/* Assign I/O stream to UART */
FILE uart_str = FDEV_SETUP_STREAM(uart_putch, uart_getch, _FDEV_SETUP_RW);

int main( void)

{

 /* Define Output/Input Stream */
  stdout = stdin = &uart_str;

:

:

}

 

My expectation is/was that this uses libraries that involve buffering. Tes / No?? 

As such are there library routines that permit me to interrogate the number of characters within the incoming buffer??

or

Do I write my own buffer management as Kartman suggests (above)??

 

Another possible thought I just had is for me to simply test the uart without reading the character (similar to uart_getch() above). ???

 

Regards JC.......

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No buffers! You have to provide the buffer magic.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And to do that you want to implement an RXC interrupt feeding into a ring buffer. You can the add an accessor that can interrogate the unused number  of bytes in the buffer. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are prepared to waste 1 character then you could this:

int	usart0_unbuffered_getchar(FILE *stream)
{
	uint8_t c=0;	//Default return value if no char received

	if (UCSR0A & (1<<RXC0))
		{
		c=UDR0;
		}

	return c;
}

You can use any null character you don't expect to receive, maybe 0xff 0r 0x00 like I'm doing.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi.

For the uart I was able to get for CodeVision compiler, text book buffer management like that indicated below.

 

I there any such presentation for avr-gcc complier????

or

Can you give me any comments before I start to hack the code below???

 

I feel this is essential (to have separate self handling interrupt routines) or else my program will have to wait atleast on the outputting of character data when I would prefer it to be processing the ADC (interrupts).

 

Regards jc......

 

 

--------------------------------------------------------------------------------------------------------------------------------

//  ************************************ USART ************************************

// USART Receiver buffer
#define   RX_BUFFER_SIZE 2 //4          // was 24
char RX_Buffer[RX_BUFFER_SIZE+1];   // character array (buffer)
char RX_Wr_Index;   // index of the next char to be put into the buffer
char RX_Rd_Index;   // index of the next cgar to be fetched from the buffer
char RX_Counter;    // a total count of characters in the buffer
bit  RX_Buffer_Overflow;   // This flag is set on USART Receiver - buffer_Overflow

// USART Transmit buffer
#define   TX_BUFFER_SIZE 80 //90        // was 24
char TX_Buffer[TX_BUFFER_SIZE+1];   // character array (buffer)
char TX_Rd_Index;   // index of the next char to be put into the buffer
char TX_Wr_Index;   // index of the next cgar to be fetched from the buffer
char TX_Counter;    // a total count of characters in the buffer
bit  fPrimedIt;     // This flag is set to start the transmit interrupts
                              // whne the buffer is no longer empty
                                                                   
// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
   char c;
   c = UDR;
   
   RX_Buffer[RX_Wr_Index] = c;  /*put received char in buffer */
   
   if(++RX_Wr_Index > RX_BUFFER_SIZE) /* wrap the pointer */
      RX_Wr_Index = 0;
      
   if(++RX_Counter > RX_BUFFER_SIZE)  /* keep a character count */
   {                                  /* overflow check */
      RX_Counter = RX_BUFFER_SIZE;    /* if too many chars came */
      RX_Buffer_Overflow = 1;         /* in before they could be used */
                                      /* that could cause an error */
                                      
   }
}                                 

// Get a character from the USART Receiver Buffer
char getchar(void)
{
    char c;
    while(RX_Counter == 0)             /* wait for a character ... */
      ;
    c = RX_Buffer[RX_Rd_Index];        /* get one from the buffer */
    
    if(++RX_Rd_Index > RX_BUFFER_SIZE)  /* wrap the pointer */
       RX_Rd_Index = 0;
       
    if(RX_Counter)
       RX_Counter--;
     
    return c;         
}
            
// USART Transmitter interrupt service routine
interrupt [USART_TXC] void usart_tx_isr(void)
{
    if(TX_Counter != 0)
    {
        if(fPrimedIt == 1)
        {                         /* only send a char if one in buffer */
            fPrimedIt = 0;        /* transmission, then don't send the */
            
                                  /* test and wrap the pointer */
            if(++TX_Rd_Index > TX_BUFFER_SIZE)
               TX_Rd_Index = 0;
            
            TX_Counter--;       /* keep track of the counter */
        }
        
        if(TX_Counter != 0)
        {
            UDR = TX_Buffer[TX_Rd_Index];
                                 /* otherwise, send the char out port */
                                 
                                 /* test and wrap the pointer */
            if(++TX_Rd_Index > TX_BUFFER_SIZE)
                TX_Rd_Index = 0;
                
            TX_Counter--;        /* keep track of the counter */    
        }
    }
    UCSRA |= 0x40;               /* clear the TX interrupt flag */
    
}
                                   
// Write a character to the USART Transmitter buffer
void putchar(char c)
{
    char stuffit = 0;
    
    while( TX_Counter > (TX_BUFFER_SIZE-1) )
        ;      /* WAIT!! Buffer is getting full !!  */
    
    if(TX_Counter == 0)          /* if buffer empty, setup for interrupt */
        stuffit = 1;
        
    TX_Buffer[TX_Wr_Index++] = c; /* jam the char in the buffer */
         
    if(TX_Wr_Index > TX_BUFFER_SIZE)    /* wrap the pointer */
        TX_Wr_Index = 0;    
                            /* keep track of the buffered chars */
    TX_Counter++;
    
    if(stuffit == 1)
    {                /* do we have to 'Prime the pump"? */
        fPrimedIt = 1;
        UDR = c;      /* this char starts the TX interrupts */
    }
        
}   

// These define tell the compiler to replace the stdio.h
// version of getchar() and putcahr() with ours..
// That way, all the other stdio.h functions can use them!!
#define   _ALTERNATE_GETCHAR_
#define   _ALTERNATE_PUTCHAR_

//  *******************************************************************************

#include <stdio.h>     // Standard Input/Output functions

---------------------------------------------------------------------------------------------------------------------------------------

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes,   the CV interrupt routines are textbook stuff.    All that you need to do is replace the interrupt syntax for a foreign compiler.

 

You also need to match the <stdio.h> prototypes.   e.g. fputc() and fgetc() for GCC.

 

Yes,   there are several textbook GCC interrupt examples out there.    But you need to find them.

Note that most readers of this site are determined to do stuff in a non-textbook way.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

However using getchar() causes a wait for the character. 

I trust there is a standard way of coping with this problem???

Well, no.  The avr-libc functions do not offer an equivalent of inputpending() or available()  (I don't see that in the codevision code you posted, either.)

As js posted, the easiest thing would be to have the getchar() function (which YOU have to supply, after all) return an unused character value when there is no data.  (Since it returns int, you can use -1, or any of the other characters that aren't actually receiveable on the UART.  (although it may confuse the other stdio functions that call getchar() (like scanf())

(I guess that one thing you get with commercial compilers is more of a "peripheral library" that supports the various AVR peripherals.   avr-gcc and avr-libc doesn't support any peripheral access functions at all.)

 

Or, you don't have to use stdio at all, at which point you can use as rich an API as you could possibly want...

 

Last Edited: Sun. Apr 12, 2015 - 07:23 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes,   the standard CV interrupt implementation has Rx_Counter.    If it is 0 then there are no bytes available.    If there are 5 bytes available,  it holds 5.

 

Bob's kbhit() function is simply (Rx_Counter != 0)

 

Obviously,   the practicality depends on the size of the Ring Buffer.    e.g. a 16-byte ring buffer can't hold a 17 byte string.

 

From memory,   the Arduino Serial.available() method returns the equivalent of Rx_Counter.

 

No,   the standard <stdio.h> functions do not have an available() function.     But it would certainly be useful.    And the OP can add his own available() as shown.

Yes,  the standard getchar() is blocking.    You simply test available() (or Bob uses kbhit()) first.    This obviates any block occurring.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Use js suggestion (post #7).    I normally return "EOF" (0xffff) when there is nothing to read so you can receive all binary 8-bit characters; his function has int defined already as return type.

 

Or check first if there is a character available:

 

if (UCSRA & (1<<RXC))

   character available

else

  no character to read

 

 

Last Edited: Sun. Apr 12, 2015 - 10:18 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Two birds with one stone:

 

http://www.fourwalledcubicle.com...

 

Being written by Dean that's guaranteed quality /reliable code that you can easily slot into an RXC ISR. 

 

And you get both RingBuffer_IsEmpty() and RingBuffer_GetCount() 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Late to the party, but...

 

For the purposes of the original question, might it be easier to replace the original UART receive ISR with one that increments a counter every time a char is received before calling the original ISR?  That way, you don't need to worry about managing your own buffers.  The foreground code keeps track of the last char count and compares it against the current char count.  And you don't really need to worry about locking and race conditions since (by definition) since all you really want to know is if a call to getchar() will block.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Long story short: No, there isn't a "standard" solution, but any given platform will probably/usually have something. But not quite all; there's targets where there is genuinely no way at all to do a "raw" keyboard input that isn't waiting for the user to do something, because computers are diverse and not all computers are directly wired up to their keyboard-like things.