TCP, UDP, UDP+

What 

In the overview, we spoke about TCP vs UDP. If we look at our Design Requirements, it states that we want Acknowledgments when messages are received. TCP sends acknowledgments but our previous section had us using UDP. The acknowledgment part of TCP is a bit complex and we don't need the full usage of it for our system. UDP is already implemented in the WiFiEsp library and building a system on top of that is a good learning experience. So that is why we are going to add simple acknowledgments to our use of UDP to created what I'm calling, UDP+.

What are acknowledgments anyway?

When a packet is sent from one device to another and you'd like to know if it got there, you would send an acknowledgment back. It's a special packet that is sent back to the source when a packet is received. TCP uses two of these. Device A sends a packet. Device B sends an acknowledgment that it received that packet. Then Device A sends an acknowledgment that it received Device B's acknowledgment. UDP sends a packet. That's it. All done. Our UDP+ will just send one acknowledgment packet.

Transmissions and Timeouts 

Not everything works out the first time. If the sender of a TCP packet doesn't hear back with an acknowledgment, or ACK packet, it will transmit it's data. If it still doesn't hear back it will transmit its data again. How long it waits before transmitting another packet is called its Timeout. It could try 2, 5, or any number of times to transmit data before it quits. That depends on what kind of system you are building.

Serial Sending 

While it might seem complex to take anything written into the Serial Monitor and capture it for use. The following code is all we need. When we write into the Serial Monitor and press enter, any characters are written into the serial port. The function Serial.available() returns 0 unless there is information in the serial port. Then it returns the number of bytes of information. If you wrote the word cat and pressed enter, the function would return a 3 . We are using the if statement of Serial.available() > 0 to trigger whenever this is information added. The Serial.readString() captures all the characters in the serial port and stores them in the variable called message . That variable is a string and for many purposes that would be fine. If wanted to write into the Serial Monitor and display that on an LED Display then we could with how it is. But since we are sending the message via UDP it must be converted from a string in to a char array. That last time does that. It operates on the message variable, and makes a copy as a char array called messageToSend .

Download file Copy to clipboard
1
2
3
4
5
6
7
    if (Serial.available() > 0) {
       //Store text in message
       message = Serial.readString();
       Serial.println("Sending message");
       .....
       message.toCharArray(messageToSend, sizeof messageToSend);
    }

ACK Implementation 

You can see in the diagrams above that when data is received an ACK packet should be sent immediately. In the first code block below we are checking to see if what the Arduino received, String(packetBuffer) , is equal to what an ACK packet looks like, String(ReplyBuffer) . If it does then the state is updated to SUCCESS because we received an ACK packet and the message got to its destination. If the data recieved was not an ACK packet then the state is set to RECEIVED because we received a real message. When that happens, you can see that first thing we do is to send an ACK packet back. ReplyBuffer store the ACK packet.

First Code block

Download file Copy to clipboard
1
2
3
4
5
6
7
8
9
    //If the packets are an "ACK" message
    if (String(packetBuffer) == String(ReplyBuffer) && waitForACK) {
      // Update current state
      currentState = SUCCESS;
    }
    else {
      //If the packet are a text message
      currentState = RECEIVED;
    }

Second Code Block

Download file Copy to clipboard
1
2
3
4
5
6
7
8
9
    // Instructions for RECEIVED state
    case RECEIVED:
      //Send "ACK" message
      sendData(ReplyBuffer, stationIP, sendingPort);
      Serial.println("Incoming Message");
      // Update current state
      currentState = SHOW;
      //End of case
      break;