Using a timeout

Technical questions regarding the XTC tools and programming with XMOS.
DaveBest
Member++
Posts: 25
Joined: Mon Jan 18, 2010 3:36 pm

Using a timeout

Post by DaveBest »

Greetings,

Attention. Somewhat long post ahead ;)

I try to send "lengthy" datapackets (~80 - 1500 Bytes) over Software UART between two XC boards.

Right now I use the following functions for sending and receiving:

Code: Select all

/** UART receive a character
  **/
unsigned char uart_getch()
{
   unsigned data = 0, time;
   int i;
   unsigned char buffer;

   UART_RX_PORT when pinseq( 0) :> int _ @ time;
   
   time += bit_time + (bit_time >> 1);
   
   // sample each bit in the middle.
   for (i = 0; i < 8; i += 1)
   {
      UART_RX_PORT @ time :> >> data;
      time += bit_time;
   }

   // reshuffle the data.
   buffer = (unsigned char) (data >> 24);
    
   return buffer;
}
and

Code: Select all

/** UART transmit a character.
 *  This is blocking call for now.
 */
void uart_putch(unsigned char buffer)
{
   unsigned time, data;
   
   data = buffer;
   
   // get current time from port with force out.
   UART_TX_PORT <: 1 @ time;
   // Start bit.
   UART_TX_PORT <: 0;
   // Data bits.
   for (int i = 0; i < 8; i += 1)
   {
      time += bit_time;
      UART_TX_PORT @ time <: >> data;         
   }
   // Stop bit
   time += bit_time;
   UART_TX_PORT @ time <: 1;
   time += bit_time;
   UART_TX_PORT @ time <: 1; 
}
To ensure that a packet is definitely received, i implemented a command sequence whereby i send a command byte and try to read the response before performing the next steps. If the response is not correct, the whole sequence starts again.

I can't use XON/XOFF because these packets are in binary and can contain any value in its bytes.

As my putch-function doesn't care about external pin values, it transmits even if there is no recipient. The getch-function has to wait for the start bit, while blocking the thread till a start bit occurs.
While sending without a care, I can't make sure that my data is received or if the supposed receiver is even ready to receive and my whole thread could hang, waiting for the response to a command that was never received at the other end.(busy, turned off,...)

Turning on the module that is receiving the packets via UART first is fine, as it is waiting for the start bit condition to occour. Turning on the UART-"sender" second is fine too, as it happily outputs its commands and waits for the responses of the "receiver".
The other way around is not looking quite as fine. The sender is turned on and starts to send and waits till the end of life, the universe and everything, because the receiver never got the command and doesn't know what to do and decides to wait for the command it already missed and won't be sent again because there was no response to it yet.

So the obvious solution is to use a timer and implement some timeout handling. Timer work fine in selects, waiting for channel communications.
So using something like

Code: Select all

select
{
    case temp = uart_getch():
// something
           break;
    case tmr when timerafter(timeoutx) :> int:
//  some other thing
           break;
}
is out of question.

The only other way i can think of right now is to somehow return from my uart_getch() function and checking if a timeout occured, using a timer while waiting for the start bit to go low.

Sorry for all the rambling, seems the wheather got to my and i can't get this out of my head.

Dave


Heater
Respected Member
Posts: 296
Joined: Thu Dec 10, 2009 10:33 pm

Post by Heater »

If it it was me I would make the receiver uart_getch() into a thread call it uart_rx_thread() or whatever.

The thread would take a channel end parameter, this channel being used to deliver received bytes to the application.

This thread would wait forever for a start bit, when it finds one it clocks in the rest of the bits as your code does now. When all the bits are collected the complete byte is output from the thread via the channel end. It then loops around waiting for the next start bit.

Perhaps rewrite uart_getch() such that it reads from the channel of incoming bytes. Here you can use select to create the timeout.

Perhaps uart_getch() should actually return an int rather than a byte then a value of -1 could indicate a time out.


Edit: Think of it like a real UART in a chip. That chip sits waiting for start bits regardless of weather you read the buffer full status from it or read the char from it's registers. The thread I am proposing is the software implementation of that concurrent activity. And the channel is the xcore equivalent of the I/O bus and interrupt mechanism of a real UART.
DaveBest
Member++
Posts: 25
Joined: Mon Jan 18, 2010 3:36 pm

Post by DaveBest »

Thanks for the quick reply and the ideas you gave.

@using a separate thread instead of a function:
sounds doable but increases threads and chanends, as the whole send operation already runs as a single thread and there are other threads running too, and when push comes to shove, such small threads may need to be cut off.
But i'll keep it in mind as it is really the simplest solution as a select could be used at its best and a timer could be used without much ado.

Right now i only got the 1-Bit ports for RX and TX to read and write data. The whole sending and receiving operation is handled by threads which call the functions to read and send, in good hopes, that no problems arise.

Returning ints would make returning errors easier but seems like a waste as i would have to cast the rest of the data for its appropriate buffers as unsigned chars or would do a lot of data mangling and reshaping.


Right now i updated my getch function and handling to include a timing select and timeout flags.

Code: Select all

...
static unsigned char outoccured = 0;
static unsigned int timeout = 10000000; //test
...
unsigned char uart_getch()
{
   unsigned data = 0, time,tt;
   int i;
   unsigned char buffer;

   timer tmr;
   tmr :> tt;
   select
   {
   		case UART_RX_PORT when pinseq( 0) :> int _ @ time:
   			outoccured = 0; // no timeout
   			break;
   		case tmr when timerafter(tt+timeout) :> int:
   			outoccured = 1; // timeout !
   			return 0;
   }

   time += bit_time + (bit_time >> 1);
   // sample each bit in the middle.
   for (i = 0; i < 8; i += 1)
   {
      UART_RX_PORT @ time :> >> data;
      time += bit_time;
   }
   // reshuffle the data.
   buffer = (unsigned char) (data >> 24);   
   return buffer;
}
...
void uart_transmit(chanend uart)
{
...
// get data
...
    while (1)
    {
        // SEND RX DATA OVER UART
	uart_putch(0xF1); // send start command
	if (uart_getch() != 0xF1) // or timeout returned 0
	{
		wait(bit_time/2);
		errors++;
		continue; // return to start of loop and try again
	}
...
        uart_putch(0xF4); // Endkommando
	if ((uart_getch() != temp) && (outoccured == 1)) // may be 0, check flag
	{
		outoccured = 0; reset flag
		wait(bit_time/2);
		errors++;
		continue; // return to start of loop and try again
	}
...
uart_getch() now returns 0 and sets a timeout flag. Command handling has to check if expected value is returned and when a 0 is a possible value to check the flag if it wasn't a timeout.

It is not broken yet but I wil try to put on some testing.

Dave
Heater
Respected Member
Posts: 296
Joined: Thu Dec 10, 2009 10:33 pm

Post by Heater »

There is a potential problem with waiting for the start bit in uart_getch() like that.

uart_getch() is called from your application. So if the application does not eat the character and do all the processing required on it before the next start bit arrives you are going to be dropping characters. Or worse receiving junk characters.

Now it may be at waste to use a thread for a UART but it does mean that the tread can look for start bits as fast as possible. You can also implement a little buffer in the rx thread and do parity checking etc.

Having a thread could improve through put as the rx thread can be clocking in bits whilst the application is crunching on the last bytes(s) read.
DaveBest
Member++
Posts: 25
Joined: Mon Jan 18, 2010 3:36 pm

Post by DaveBest »

You raise some valid concerns.

After some light testing it seems to work right now, but i wouldn't risk my life on it.
I will try to implement a thread solution later today.
It is working on a 9600 Baud rate, so there should be time for handling this.
It is a software UART on both ends, so it possibly will be raised to a higher rate later on.
If i detect no data in my given timeout frame, somethings amiss and i stop waiting for the start bit and assume a timeout happened and start over.
Receiving junk characters and missing start bits could be a real problem as i am possibly transmitting quite a large amount of data and only perform some cursory amount of checksum calculating (first and last 5 bytes of a packet), while using several "handshakes" to discern if my "receiver" is really receiving and responsive.

Whether i call the function or select from the rx thread, I will have to wait for the timeout as i have to strictly follow my communication protocol:
- accumulate data in sender and send to uart thread
- perform "handshake" and wait for receiver to answer correctly or restart
- send data length followed by another "handshake" (answer correct or restart)
- send data
- perform third "handshake" and start calculation checksum
- ask for checksum and acknowledge end or deny and restart

The receiver only needs to read the answers to the handshakes and checksum, if a timeout occurs, "uhoh!" start anew.

No other communication shall occur so both sides follow this stringent chain, if it doesn't work as expected: start from the beginning.


Time to think some more about this.

Dave
Heater
Respected Member
Posts: 296
Joined: Thu Dec 10, 2009 10:33 pm

Post by Heater »

You might want to think about a more robust and proven protocol for your application, for example the "Simple Serial Protocol" http://www.utias-sfl.net/docs/ssp2.1e.pdf.