Electronic – Serial XOnXOff handshaking

atmegamicrocontrollerserial

I have the following code running on an atmega328 (ArduinoUno).

#include <stdint.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <util/delay.h>

volatile bool receiveQ = true;
volatile bool transmitQ = true;

ISR(USART_RX_vect)
{
    uint8_t byte = UDR0;
    if( !receiveQ && byte != 19)
    {
        return;
    }
    switch ( byte)
    {
        case 19:
            receiveQ = true;
            transmitQ = false;
            break;
            
        case 17:
            receiveQ = false;
            transmitQ = true;
            break;
        
        // process incoming data
        default:
            break;
    }
}
void transmitByte(uint8_t byte)
{
    while( !(UCSR0A & 1 << UDRE0));
    UDR0 = byte;
}
void transmitString(char *pstr)
{
    while( *pstr != 0)
    {
        transmitByte(*pstr);
        pstr++;
    }
}
int main(void)
{
    UBRR0H = 0;
    UBRR0L = 103;
    UCSR0C |= 1 << UCSZ01 | 1 << UCSZ00;
    UCSR0B |= 1 << RXEN0 | 1 << TXEN0 | 1 << RXCIE0;
    sei();
    while( 1)
    {
        if( transmitQ)
        {
            transmitByte(19);
            transmitString("data");
            transmitByte(17);
            transmitQ = false;
        };
        _delay_ms(1000);
    }
    return 0;
}

I want it to implement XOnXOff handshaking, and my question is if I am doing it correctly.

When I set up communication with PuTTY, I first see "data" that is sent by the Arduino. I then send XOff (Ctrl+S), some data, and XOn (Ctrl+Q), following which the Arduino sends the next "data". And I can keep doing this again and again.

enter image description here

The reason I am wondering if I'm doing this correctly is because I have to manually send the XOff and XOn bytes from PuTTY when transmitting data, although I have set the flow control to be XOnXOff.

enter image description here

However, PuTTY strips the XOff and XOn bytes and only gives "data" when it is receiving data.

Update

The secnario is for real-time feedback control. During each time period, the serial input to the atmega328 is the reference signal. (If no new data is received it uses the previous data.) The serial output from the atmega328 is the sensor value (which is also used by the controller.) I am using the XOn and XOff characters to signal when to start sending the data and when transmission is complete.

Best Answer

As @pjc50 says in a comment, Xon/Xoff is flow control, not block-control.

If a receive buffer is full, the device with that buffer sends "Xoff" to the other device to make it stop talking for a while. So your putty will send "Xon" when initiating, then only send "Xoff" when the port's buffer is full, after which it sends "Xon" again when there's room for new data. It's likely your Atmel is much slower in handling data than your PC, so as an effect it is unlikely the PC will ever decide to send Xon/Xoff to the Atmel on its own.

That said, I do sometimes write logger firmware that "pumps" out data at 1MBit+ and then windows specifically will start whimpering. I have never tried whether it then sends Xon/Xoff, as I often then migrate to direct USB communication, becuase I need the stream, not some "chopped" simile. In Linux, however, I have not had any buffer issues up to 5Mbit on serial interfaces.

EDIT:

As a side note: I have seen many worse things in the world than using Xon/Xoff for handshaking rather than flow control, so comparatively you wouldn't be that bad. But semantically you should use other special characters for block-handshaking procedures. Such as SOH, STX, ETX, EOT, ENQ, ACK, NAK, SO, SI, CAN, EM.

You are also allowed in Ascii to use DC1 through DC4 for whatever you like.

See the Ascii Control Table for more fun names and numbers.