Reading multiple variables in UDP packet

Hi all,

Back again, new question.
I'm trying to read my UDP packet as best as possible, but I'm not sure how to do it.

So I am receiving a packet which contains a table numer (variable tableID) and a state (available/idle/ordered/off/ping)

the tableID is set in the declaration (default is 0) since the user has to set a ID to the device in the EEPROM.
For my test I adress the tableID myself to 101

int address = 0;
byte tableID;

I still need to write a struct for the state, but I'm waiting a little longer since I'm still adding states..
For now I have used the code beneath for each state

So far I've tested with simply capturing the string which works fine:
The string I'm sending through PacketSender simply ASCII "101_available"

      if ( !strcmp(packetBuffer, "101_available")) {
        modeAvailable();
      }

I think you can guess what I want to do, I want to read and compare the variable tableID "101" to my tableID and then read the "available"as state

If the tableID which is send matches my device's tableID then execute code.

Can anyone help me?

the UDP datagram could contain a structure transmitted as a series of bytes, e.g.

struct UDPpacket {
    byte tableID;
    char available[50];
}
packet;

horace:
the UDP datagram could contain a structure transmitted as a series of bytes, e.g.

struct UDPpacket {

byte tableID;
    char available[50];
}
packet;

So I'm a bit in doubt, on my side, as socket, to read the "UDPpacket" from the host;
to capture:

if (packetBuffer, UDPpacket) {
        modeAvailable();
      }

to declare:

struct UDPpacket {
    byte tableID;
    char state[50];
}
packet;

state will be declared in a different struct with all states.
Now I'm only not sure how to verify that the "tableID" is correct and the "state" as well.

I need to see if I can write a piece of code to run from my computer to test this.

PC C program to send A UDP datagram containing a struct to Arduino

// udp-client.cpp - simple UDP datagram client
//   send datagram to server

#ifdef __WIN32
  #include <winsock.h>          // for windows
  #define socklen_t int
#else
  #include <arpa/inet.h>        // for UNIX
  #include <netdb.h>
  #define errno h_errno
#endif
#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cstdlib>

// extra 3 for cr, lf and \0
#define MAX_LINE 100
#define LINE_ARRAY_SIZE (MAX_LINE+3)
#define NEWLINE "\n"

using namespace std;

// test structure to transmit
struct UDPpacket {
    byte tableID;
    char state[50];
}
packet={101,"101_available"};

int main()
{
  int socketDescriptor;
  int numRead;
  unsigned short int serverPort;
  struct sockaddr_in serverAddress;
  struct hostent *hostInfo;
  struct timeval timeVal;
  fd_set readSet;
  char buf[LINE_ARRAY_SIZE], c;
    // ** added for windows
    WSAData wsaData;
    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
      { perror("WSAStartup()"); system("pause"); return 255; }

  cout << "Enter server host name or IP address: ";

  memset(buf, 0x0, LINE_ARRAY_SIZE);  // Zero out the buffer.
  cin.get(buf, MAX_LINE, '\n');

  // gethostbyname() takes a host name or ip address in "numbers and
  // dots" notation, and returns a pointer to a hostent structure,
  // which we'll need later.  It's not important for us what this
  // structure is actually composed of.
  hostInfo = gethostbyname(buf);
  if (hostInfo == NULL)
    { cout << "problem interpreting host: " << buf; perror("gethostbyname() ");  system("pause");  exit(1); }

  cout << "Enter server port number: ";
  cin >> serverPort;
  cin.get(c); // dispose of the newline

  // Create a socket.  "AF_INET" means it will use the IPv4 protocol.
  // "SOCK_STREAM" means it will be a reliable connection (i.e., TCP,
  // for UDP use SOCK_DGRAM), and I'm not sure what the 0 for the last
  // parameter means, but it seems to work.
  socketDescriptor = socket(AF_INET, SOCK_DGRAM, 0);
  if (socketDescriptor < 0)
    { perror("cannot create socket ");  system("pause");  exit(1); }

  // Set some fields in the serverAddress structure.
  serverAddress.sin_family = hostInfo->h_addrtype;
  memcpy((char *) &serverAddress.sin_addr.s_addr,
         hostInfo->h_addr_list[0], hostInfo->h_length);
  serverAddress.sin_port = htons(serverPort);

  {
    // Send the line to the server.
    if (sendto(socketDescriptor, (const char *) &packet, sizeof(packet), 0,
               (struct sockaddr *) &serverAddress,
               sizeof(serverAddress)) < 0) {
      close(socketDescriptor);
      perror("sendto()  ");  system("pause");  exit(1);
    }

    // wait until answer comes back, for up to 1 second
    FD_ZERO(&readSet);
    FD_SET(socketDescriptor, &readSet);
    timeVal.tv_sec = 1;
    timeVal.tv_usec = 0;

    if (select(socketDescriptor+1, &readSet, NULL, NULL, &timeVal)) {
      // Read the modified line back from the server.
      memset(buf, 0x0, LINE_ARRAY_SIZE);  // Zero out the buffer.
      numRead = recv(socketDescriptor, buf, MAX_LINE, 0);
      if (numRead < 0) {
        cerr << "didn't get response from server?\n";
        close(socketDescriptor);
        perror("recv()  ");  system("pause");  exit(1);
        }

      cout << "Modified: " << buf << "\n";
    }
    else {
      cout << "** Server did not respond in 1 second.\n";
    }

  }

  close(socketDescriptor);
  return 0;
}

Arduino program to receive the struct

// UDP_struct - receive structure from remote UDP device

#include <SPI.h>         // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <EthernetUdp.h>         // UDP library from: bjoern@cs.stanford.edu 12/30/2008

// Enter a MAC address and IP address for your controller below.
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 177);         // IP address of this Arduino to match current network
unsigned int localPort = 999;       //  UDP port number being used
EthernetUDP Udp;    // An EthernetUDP instance to let us send and receive packets over UDP

// test structure
struct UDPpacket {
    byte tableID;
    char state[50];
}
packet;

void setup() {
  Ethernet.begin(mac, ip);     // start the Ethernet and UDP:
  Udp.begin(localPort);
  Serial.begin(115200);
}

void loop() {
  int inByte ;
    // if there's data available, read acknowledgement packet
    int packetSize = Udp.parsePacket();
    if (packetSize) {
      Serial.print("Received packet of size ");
      Serial.print(packetSize);
      Serial.print(" From ");
      IPAddress remote = Udp.remoteIP();   // display IP of remote PC
      for (int i = 0; i < 4; i++) {
        Serial.print(remote[i], DEC);
        if (i < 3) {
          Serial.print(".");
        }
      }
      Serial.print(", port ");
      Serial.println(Udp.remotePort());      // display remote port
      // buffers for receiving data
      char packetBuffer[UDP_TX_PACKET_MAX_SIZE]={0};  //buffer to hold incoming packet,
      // read the packet into packetBufffer and display contents
      Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
      memcpy((void *) &packet, packetBuffer, sizeof(packet));
      Serial.print("Contents: ");
      Serial.print("ID "); Serial.println(packet.tableID);
      Serial.print("state "); Serial.println(packet.state);
  }
}

the PC displays

Enter server host name or IP address: 192.168.1.177
Enter server port number: 999
** Server did not respond in 1 second.

the arduino displays

Received packet of size 51 From 192.168.1.96, port 60911
Contents: ID 101
state 101_available

horace:
PC C program to send A UDP datagram containing a struct to Arduino

// udp-client.cpp - simple UDP datagram client

//  send datagram to server

#ifdef __WIN32
  #include <winsock.h>          // for windows
  #define socklen_t int
#else
  #include <arpa/inet.h>        // for UNIX
  #include <netdb.h>
  #define errno h_errno
#endif
#include <stdio.h>
#include <unistd.h>
#include
#include
#include
#include

// extra 3 for cr, lf and \0
#define MAX_LINE 100
#define LINE_ARRAY_SIZE (MAX_LINE+3)
#define NEWLINE “\n”

using namespace std;

// test structure to transmit
struct UDPpacket {
    byte tableID;
    char state[50];
}
packet={101,“101_available”};

int main()
{
  int socketDescriptor;
  int numRead;
  unsigned short int serverPort;
  struct sockaddr_in serverAddress;
  struct hostent *hostInfo;
  struct timeval timeVal;
  fd_set readSet;
  char buf[LINE_ARRAY_SIZE], c;
    // ** added for windows
    WSAData wsaData;
    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
      { perror(“WSAStartup()”); system(“pause”); return 255; }

cout << "Enter server host name or IP address: ";

memset(buf, 0x0, LINE_ARRAY_SIZE);  // Zero out the buffer.
  cin.get(buf, MAX_LINE, ‘\n’);

// gethostbyname() takes a host name or ip address in “numbers and
  // dots” notation, and returns a pointer to a hostent structure,
  // which we’ll need later.  It’s not important for us what this
  // structure is actually composed of.
  hostInfo = gethostbyname(buf);
  if (hostInfo == NULL)
    { cout << "problem interpreting host: " << buf; perror("gethostbyname() ");  system(“pause”);  exit(1); }

cout << "Enter server port number: ";
  cin >> serverPort;
  cin.get(c); // dispose of the newline

// Create a socket.  “AF_INET” means it will use the IPv4 protocol.
  // “SOCK_STREAM” means it will be a reliable connection (i.e., TCP,
  // for UDP use SOCK_DGRAM), and I’m not sure what the 0 for the last
  // parameter means, but it seems to work.
  socketDescriptor = socket(AF_INET, SOCK_DGRAM, 0);
  if (socketDescriptor < 0)
    { perror("cannot create socket ");  system(“pause”);  exit(1); }

// Set some fields in the serverAddress structure.
  serverAddress.sin_family = hostInfo->h_addrtype;
  memcpy((char *) &serverAddress.sin_addr.s_addr,
        hostInfo->h_addr_list[0], hostInfo->h_length);
  serverAddress.sin_port = htons(serverPort);

{
    // Send the line to the server.
    if (sendto(socketDescriptor, (const char *) &packet, sizeof(packet), 0,
              (struct sockaddr *) &serverAddress,
              sizeof(serverAddress)) < 0) {
      close(socketDescriptor);
      perror("sendto()  ");  system(“pause”);  exit(1);
    }

// wait until answer comes back, for up to 1 second
    FD_ZERO(&readSet);
    FD_SET(socketDescriptor, &readSet);
    timeVal.tv_sec = 1;
    timeVal.tv_usec = 0;

if (select(socketDescriptor+1, &readSet, NULL, NULL, &timeVal)) {
      // Read the modified line back from the server.
      memset(buf, 0x0, LINE_ARRAY_SIZE);  // Zero out the buffer.
      numRead = recv(socketDescriptor, buf, MAX_LINE, 0);
      if (numRead < 0) {
        cerr << “didn’t get response from server?\n”;
        close(socketDescriptor);
        perror("recv()  ");  system(“pause”);  exit(1);
        }

cout << "Modified: " << buf << “\n”;
    }
    else {
      cout << “** Server did not respond in 1 second.\n”;
    }

}

close(socketDescriptor);
  return 0;
}



Arduino program to receive the struct


// UDP_struct - receive structure from remote UDP device

#include <SPI.h>        // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <EthernetUdp.h>        // UDP library from: bjoern@cs.stanford.edu 12/30/2008

// Enter a MAC address and IP address for your controller below.
byte mac = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 177);        // IP address of this Arduino to match current network
unsigned int localPort = 999;      //  UDP port number being used
EthernetUDP Udp;    // An EthernetUDP instance to let us send and receive packets over UDP

// test structure
struct UDPpacket {
    byte tableID;
    char state[50];
}
packet;

void setup() {
  Ethernet.begin(mac, ip);    // start the Ethernet and UDP:
  Udp.begin(localPort);
  Serial.begin(115200);
}

void loop() {
  int inByte ;
    // if there’s data available, read acknowledgement packet
    int packetSize = Udp.parsePacket();
    if (packetSize) {
      Serial.print(“Received packet of size “);
      Serial.print(packetSize);
      Serial.print(” From “);
      IPAddress remote = Udp.remoteIP();  // display IP of remote PC
      for (int i = 0; i < 4; i++) {
        Serial.print(remote[i], DEC);
        if (i < 3) {
          Serial.print(”.”);
        }
      }
      Serial.print(", port ");
      Serial.println(Udp.remotePort());      // display remote port
      // buffers for receiving data
      char packetBuffer[UDP_TX_PACKET_MAX_SIZE]={0};  //buffer to hold incoming packet,
      // read the packet into packetBufffer and display contents
      Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
      memcpy((void *) &packet, packetBuffer, sizeof(packet));
      Serial.print("Contents: ");
      Serial.print("ID "); Serial.println(packet.tableID);
      Serial.print("state "); Serial.println(packet.state);
  }
}



the PC displays


Enter server host name or IP address: 192.168.1.177
Enter server port number: 999
** Server did not respond in 1 second.



the arduino displays


Received packet of size 51 From 192.168.1.96, port 60911
Contents: ID 101
state 101_available

Hi Horace,

Sorry for my late response…! I noticed your reply quickly, and worked on it right away, it took some time since I’ve decided to change my workflow, instead of finishing the device, I’ve built an windows app which allows me to debug the device even better, so that’s why my response took some time. :slight_smile:
The windows app is useful since the client will use this as well

Thank you for your great, extensive explanation with code.
It is very useful for me, since I get the logic now.

I’ve added karma to your profile :slight_smile: