3
\$\begingroup\$

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.

\$\endgroup\$
4
  • 3
    \$\begingroup\$ It would only send them when some buffer filled up, which may be never. Xon/Xoff is pretty rare. \$\endgroup\$
    – pjc50
    Commented Jun 11, 2015 at 14:54
  • 1
    \$\begingroup\$ I think you should use the PuTTY in raw mode (without any flow control) in order to see the full data. But since the control codes are usually not printable, it won't display them nicely. Alternatively, for the debugging purposes you can just use some printable character instead. \$\endgroup\$
    – Eugene Sh.
    Commented Jun 11, 2015 at 15:12
  • \$\begingroup\$ @pjc50 thanks for that bit of information. \$\endgroup\$ Commented Jun 11, 2015 at 16:44
  • \$\begingroup\$ @EugeneSh. thanks. So I think what I observed earlier was PuTTY not printing XOn and XOff characters as opposed to some implementation. I changed the flow control to None, and these characters did not get printed, while '1' and '2' did get printed if I used them instead. \$\endgroup\$ Commented Jun 11, 2015 at 16:48

2 Answers 2

3
\$\begingroup\$

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.

\$\endgroup\$
6
  • \$\begingroup\$ Thanks, especially for that ASCII table. Please see my update. Do you have an opinion on what is appropriate. Is there some kind of standard for my scenario? I also need to pick a third character as a delimiter for cases when there there multiple inputs and/or outputs. \$\endgroup\$ Commented Jun 11, 2015 at 16:43
  • 1
    \$\begingroup\$ @SubaThomas STX and ETX are commonly used for "Here is the message" and "message done", so you would add them to a stream to identify "normal text" between blocks of header or other information. They may be useful at some point. If you need to send different bits of data from different sources you can put a "Record Separator" or "Unit Separator" between them. RS is most common. SOH is often used for "attention, here is data" followed by a header, then STX followed by message, followed by ETX a footer and then EOT, or EOT right after the message. \$\endgroup\$
    – Asmyldof
    Commented Jun 11, 2015 at 17:56
  • 1
    \$\begingroup\$ @SubaThomas For your use, as I understand it, the special control cases to send from PC to device that don't really fit anything "should" be handled with DC1 through 4. They are "Device Commands" that you can define as meaning anything you like. They should never be sent by generic drivers, but may cause confusion when using Program A with Device B, of course. But, to be honest, I don't see many people using control characters any more, so any pick would be relatively safe. If you want to at least not confuse mouse drivers and such: Use DC1 ~ 4 in both directions for special stuff. \$\endgroup\$
    – Asmyldof
    Commented Jun 11, 2015 at 17:59
  • 1
    \$\begingroup\$ Thanks again. I have decided to leave it at DC1/XOn/17 and DC3/XOff/19. \$\endgroup\$ Commented Jun 11, 2015 at 18:50
  • 1
    \$\begingroup\$ Yes, that's what I'm planning to do at the moment. Stick with XOn and XOff, and not use any flow control, i.e. set it to None. \$\endgroup\$ Commented Jun 11, 2015 at 19:09
2
\$\begingroup\$

When teletypes were invented, their primary purpose was to output data which was stored on the other end in the form of a paper tape. The XON and XOFF codes were defined to allow for the possibility that someone who e.g. noticed that a teletype was almost out of paper might need to ask the other end to pause while it was serviced. When an ASR33 teletype receives an XON code, it will turn on the paper tape reader and start sending the contents thereof; when it receives an XOFF code, it will turn off the paper tape reader, leaving it positioned to resume the next time it receives an XON.

When teletypes started to be interfaced to computers, the computers honored XON/XOFF by suspending transmission when an XOFF was received and resuming it when XON was received.

When baud rates were increased to the point that teletypes could not consistently keep up with incoming data (many printing mechanisms will take a variable amount of time to print each character, with a worst-case time about double the average-case time) some of them started automatically generating and sending xon/xoff control codes. Despite their being automated, however, the XON/XOFF retains some limitations as a consequence of its having been designed to start and stop remote equipment in response to human interaction. If a remote device fails to receive an XON for some reason, it may wait forever. If the XON was issued by a human that won't pose a problem (the human will notice that nothing is being transmitted and send another XON). If automated equipment just sends one XON and doesn't send another until it has had reason to send another XOFF, however, the remote equipment may wait forever for an XON it's never going to receive.

To deal with that possibility, it may be helpful to have a device which expects data periodically send an XON any time its buffer is empty (1-4x/second or so). Unfortunately, I'm unaware of any pre-built communications libraries that do that automatically. If at least one end of the connection is "manually" generating the xon/xoff on at least one end of the connection, however, that end of the connection can generate XON characters when idle provided that it will always be able to reach an idle state even while it has suspended transmission on behalf of the other end. If device could enter a situation where it can't receive more data until it transmits data, and it can't transmit data until it receives an XON, it may be necessary to add time-out logic to resolve such deadlock.

BTW, if one controls both ends of the communication and wishes to have the line sit quietly when idle (rather than sending several XON characters per second), it may be helpful to have a system send ENQ characters periodically when it is waiting for an XON, and have the remote end respond to an ENQ with either XON or XOFF depending upon whether it is ready for data. Doing that would avoid the possibility of accidental deadlock occurring when one side doesn't see an XON sent by the other, and would also make it possible to detect "systemic" deadlock in cases where each side will want to transmit the data it has before it receives any more.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.