UDP Send/Receive failing with credentials

Hi,

I am doing my baby steps in ethernet communication. I am using Teensy 4.1 and QNEthernet library. I took an example which is named "BroadcastChat" in the library examples, I did not change anything in this code.

My initial hope was that I would be able to send text from serial monitor and receive it via Microsoft UDP Send/Receive app and the opposite way. That was my idea on testing (hardware is already tested, got my cables and everything else wired right)

However, after around 15 seconds after powering teensy up, I get the last line in the terminal '' Failed to get IP address from DHCP " I guess it is somehow related to the constant declared at the top of the code, but I dont know how exactly and I dont know what is cause of/how to solve it? Any ideas or observations?

// SPDX-FileCopyrightText: (c) 2023 Shawn Silverman <shawn@pobox.com>
// SPDX-License-Identifier: MIT

// BroadcastChat is a simple chat application that broadcasts and
// receives text messages over UDP.
//
// This file is part of the QNEthernet library.

#include <QNEthernet.h>

using namespace qindesign::network;

// --------------------------------------------------------------------------
//  Configuration
// --------------------------------------------------------------------------

constexpr uint32_t kDHCPTimeout = 15'000;  // 15 seconds

constexpr uint16_t kPort = 5190;  // Chat port

// --------------------------------------------------------------------------
//  Program State
// --------------------------------------------------------------------------

// UDP port.
EthernetUDP udp;

// --------------------------------------------------------------------------
//  Main Program
// --------------------------------------------------------------------------

// Forward declarations (not really needed in the Arduino environment)
static void printPrompt();
static void receivePacket();
static void sendLine();

// Program setup.
void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 4000) {
    // Wait for Serial
  }
  printf("Starting...\r\n");

  uint8_t mac[6];
  Ethernet.macAddress(mac);  // This is informative; it retrieves, not sets
  printf("MAC = %02x:%02x:%02x:%02x:%02x:%02x\r\n",
         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

  Ethernet.onLinkState([](bool state) {
    printf("[Ethernet] Link %s\r\n", state ? "ON" : "OFF");
  });

  printf("Starting Ethernet with DHCP...\r\n");
  if (!Ethernet.begin()) {
    printf("Failed to start Ethernet\r\n");
    return;
  }
  if (!Ethernet.waitForLocalIP(kDHCPTimeout)) {
    printf("Failed to get IP address from DHCP\r\n");
    return;
  }

  IPAddress ip = Ethernet.localIP();
  printf("    Local IP     = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);
  ip = Ethernet.subnetMask();
  printf("    Subnet mask  = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);
  ip = Ethernet.broadcastIP();
  printf("    Broadcast IP = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);
  ip = Ethernet.gatewayIP();
  printf("    Gateway      = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);
  ip = Ethernet.dnsServerIP();
  printf("    DNS          = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);

  // Start UDP listening on the port
  udp.begin(kPort);

  printPrompt();
}

// Main program loop.
void loop() {
  receivePacket();
  sendLine();
}

// --------------------------------------------------------------------------
//  Internal Functions
// --------------------------------------------------------------------------

// Control character names.
static const String kCtrlNames[]{
  "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
  "BS",  "HT",  "LF",  "VT",  "FF",  "CR",  "SO",  "SI",
  "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
  "CAN", "EM",  "SUB", "ESC", "FS",  "GS",  "RS",  "US",
};

// Receives and prints chat packets.
static void receivePacket() {
  int size = udp.parsePacket();
  if (size < 0) {
    return;
  }

  // Get the packet data and remote address
  const uint8_t *data = udp.data();
  IPAddress ip = udp.remoteIP();

  printf("[%u.%u.%u.%u][%d] ", ip[0], ip[1], ip[2], ip[3], size);

  // Print each character
  for (int i = 0; i < size; i++) {
    uint8_t b = data[i];
    if (b < 0x20) {
      printf("<%s>", kCtrlNames[b].c_str());
    } else if (b < 0x7f) {
      putchar(data[i]);
    } else {
      printf("<%02xh>", data[i]);
    }
  }
  printf("\r\n");
}

// Tries to read a line from the console and returns whether
// a complete line was read. This is CR/CRLF/LF EOL-aware.
static bool readLine(String &line) {
  static bool inCR = false;  // Keeps track of CR state

  while (Serial.available() > 0) {
    int c;
    switch (c = Serial.read()) {
      case '\r':
        inCR = true;
        return true;

      case '\n':
        if (inCR) {
          // Ignore the LF
          inCR = false;
          break;
        }
        return true;

      default:
        if (c < 0) {
          return false;
        }
        inCR = false;
        line.append(static_cast<char>(c));
    }
  }

  return false;
}

// Prints the chat prompt.
static void printPrompt() {
  printf("chat> ");
  fflush(stdout);  // printf may be line-buffered, so ensure there's output
}

// Reads from the console and sends packets.
static void sendLine() {
  static String line;

  // Read from the console and send lines
  if (readLine(line)) {
    if (!udp.send(Ethernet.broadcastIP(), kPort,
                  reinterpret_cast<const uint8_t *>(line.c_str()),
                  line.length())) {
      printf("[Error sending]\r\n");
    }
    line = "";
    printPrompt();
  }
}

So do you have a DHCP server on the network you are using?

A diagram of how you have all this connected would help ...

My wiring is too simple to draw:

I have my teensy 4.1 dev board connected to a PC via standard micro-USB cable, and since teensy 4.1 dev boards have integrated ethernet PHYs, I have RJ45 connector as break-out board connecting the teensy with my pc

About the DHCP:

I am doing all this at my work where I just plug my PC to a wall RJ45 socket. Ethernet cables are routed all over the building and I do not have access to a physical router nor do I know the network architecture beyond my computer. So no, I have not setup a dedicated DHCP server. If it is inevitable, could you suggest the easiest solution to my situation? Are there any alternatives? Can I get the job done without DHCP and use static IP instead? If yes, can you guide my, how should I edit the code? At the end of the day, UDP communication is the only thing that matters for me... Thank you once again

If it's that simple, it'll be no trouble to draw - and far clearer that trying to describe it in text.

So you've just plugged the ethernet port of your Teensy straight into the ethernet port of your PC?

I don't think a PC will provide a DHCP server on that.

That should be possible - the teensy and/or library documentation should describe how to set up a sketch with a static IP address ...

I found out that it is possible to run a DHCP server on a PC using third party app. If I manage to start a DHCP server using my PC, is there anything else keeping me from the working UDP communication? Of course I will do lots of tests, but since this is my first UDP application, I want to plan a few steps a head? Can you think of anything else that I would need to do to achieve the mentioned result?

I'm not clear if you are connecting the ethernet board to the network or directly to the PC

If to the network then it should have a DHCP server available. Be aware that a company network might be configured to only supply IP addresses to authorised devices.

If directly to your PC then you need to set a static IP address on your PC and the ethernet card, same subnet, different IP address.

1 Like

Teensy 4.1 is directly connected to the PC. The whole idea is to establish UDP communication just between those two devices no matter the actual network (WAN) condition.

About static IP... Do I set a static IP and Subnet only for teensy or both teensy and PC? Can you provide me a brief pseudo code based on the library example I used? I kind of get the idea of static IP, but it seems so tricky untill it does not work, I just want to achieve the simplest data transfer, from there, Ill handle it by myself...

Yes, the PC and Teensy both need an IP address. On the PC set it against the ethernet adapter that you are using. If you are connected to a network at the same time, perhaps over WiFi, make sure you use a subnet for the connection to the Teensy that is different to the subnet used for connection to the network.

I'm not familiar with the Teensy or ethernet library so can't provide an example, sorry. My response was based on my understanding of how networks work, which is the same regardless of what kind of device you use. Hopefully someone else can help with the device specific questions.

Is there any rule how should I changed the subnet mask? My network`s mask is 255.255.254.0 so I can do like 255.255.254.1 and thats enough? It might look like a stupid question, but I already encountered some tricky places in this project, just want to be sure... If I change my subnet mask on both PC and teensy, does that mean that I wont be able to communicate with rest of the network I am attached to untill I change my mask back again? When I try to enter anything but 255.255.254.0 it gives me error
Capture
)

Ah, misunderstanding.

Suppose the IP address you have from the network, perhaps over WiFi, is 192.168.1.30 then you must not use the subnet 192.168.1.0/24, but you can use, for example 192.168.2.0/24

The subnet mask will be 255.255.255.0 in both cases.

To be clear, all the above assumes that you have 2 (or more) connections to your PC, one to a network and ultimately the internet, the other to your Teensy.

I note that in a previous reply you were thinking about running a DHCP server on your PC. Be really careful with this because if you connect your PC to a network and have a DHCP server running on it then it could or will respond to DHCP requests from other devices connected to the network, which will cause problems for those devices and their users. If you really want to use a DHCP server on your PC then you have to be sure it's on a different subnet to the network that you are connected to, and preferably only associated with the ethernet port you are connecting your Teensy to. But really, if you don't know what you are doing don't use a DHCP server.

Alright, I have set static IPs on the different subnet than my internet network for both teensy and PC
Capture

After light code adjustment (I manually entered all the teensy addresses) my code looks like that:

// SPDX-FileCopyrightText: (c) 2023 Shawn Silverman <shawn@pobox.com>
// SPDX-License-Identifier: MIT

// BroadcastChat is a simple chat application that broadcasts and
// receives text messages over UDP.
//
// This file is part of the QNEthernet library.

#include <QNEthernet.h>

using namespace qindesign::network;

// --------------------------------------------------------------------------
//  Configuration
// --------------------------------------------------------------------------

//constexpr uint32_t kDHCPTimeout = 10'000;  // 10 seconds

constexpr uint16_t kPort = 5190;  // Chat port

// --------------------------------------------------------------------------
//  Program State
// --------------------------------------------------------------------------

// UDP port.
EthernetUDP udp;

// --------------------------------------------------------------------------
//  Main Program
// --------------------------------------------------------------------------

// Forward declarations (not really needed in the Arduino environment)
static void printPrompt();
static void receivePacket();
static void sendLine();

// Program setup.
void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 4000) {
    // Wait for Serial
  }
  printf("Starting...\r\n");

  uint8_t mac[6];
  Ethernet.macAddress(mac);  // This is informative; it retrieves, not sets
  printf("MAC = %02x:%02x:%02x:%02x:%02x:%02x\r\n",
         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

  Ethernet.onLinkState([](bool state) {
    printf("[Ethernet] Link %s\r\n", state ? "ON" : "OFF");
  });

  printf("Starting Ethernet with DHCP...\r\n");
  if (!Ethernet.begin()) {
    printf("Failed to start Ethernet\r\n");
    return;
  }
 
  /*
  if (!Ethernet.waitForLocalIP(kDHCPTimeout)) {
    printf("Failed to get IP address from DHCP\r\n");
    return;
  }
 */
  //IPAddress ip =Ethernet.localIP();

  IPAddress ip = {10, 10, 15, 110};
  printf("    Local IP     = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);
  ip = {255, 255, 255, 0};                     //Ethernet.subnetMask();
  printf("    Subnet mask  = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);
  ip = {255, 255, 255, 255};                   //Ethernet.broadcastIP();
  printf("    Broadcast IP = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);
  ip = {10, 10, 10, 254};                      //Ethernet.gatewayIP();
  printf("    Gateway      = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);
  ip = {10, 10, 10, 244};                      //Ethernet.dnsServerIP();
  printf("    DNS          = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);

  // Start UDP listening on the port
  udp.begin(kPort);

  printPrompt();
}

// Main program loop.
void loop() {
  receivePacket();
  sendLine();
}

// --------------------------------------------------------------------------
//  Internal Functions
// --------------------------------------------------------------------------

// Control character names.
static const String kCtrlNames[]{
  "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
  "BS",  "HT",  "LF",  "VT",  "FF",  "CR",  "SO",  "SI",
  "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
  "CAN", "EM",  "SUB", "ESC", "FS",  "GS",  "RS",  "US",
};

// Receives and prints chat packets.
static void receivePacket() {
  int size = udp.parsePacket();
  if (size < 0) {
    return;
  }

  // Get the packet data and remote address
  const uint8_t *data = udp.data();
  IPAddress ip = udp.remoteIP();

  printf("[%u.%u.%u.%u][%d] ", ip[0], ip[1], ip[2], ip[3], size);

  // Print each character
  for (int i = 0; i < size; i++) {
    uint8_t b = data[i];
    if (b < 0x20) {
      printf("<%s>", kCtrlNames[b].c_str());
    } else if (b < 0x7f) {
      putchar(data[i]);
    } else {
      printf("<%02xh>", data[i]);
    }
  }
  printf("\r\n");
}

// Tries to read a line from the console and returns whether
// a complete line was read. This is CR/CRLF/LF EOL-aware.
static bool readLine(String &line) {
  static bool inCR = false;  // Keeps track of CR state

  while (Serial.available() > 0) {
    int c;
    switch (c = Serial.read()) {
      case '\r':
        inCR = true;
        return true;

      case '\n':
        if (inCR) {
          // Ignore the LF
          inCR = false;
          break;
        }
        return true;

      default:
        if (c < 0) {
          return false;
        }
        inCR = false;
        line.append(static_cast<char>(c));
    }
  }

  return false;
}

// Prints the chat prompt.
static void printPrompt() {
  printf("chat> ");
  fflush(stdout);  // printf may be line-buffered, so ensure there's output
}

// Reads from the console and sends packets.
static void sendLine() {
  static String line;

  // Read from the console and send lines
  if (readLine(line)) {
    if (!udp.send(Ethernet.broadcastIP(), kPort,
                  reinterpret_cast<const uint8_t *>(line.c_str()),
                  line.length())) {
      printf("[Error sending]\r\n");
    }
    line = "";
    printPrompt();
  }
}

However, I am still getting the same error when I enter anything in the monitor
Capture1
Did I miss something else?

Do keep in mind that I don't know the library you are using and might be misunderstanding your code. There are others here who will understand it and I hope they will join in.

You appear to be trying to set the IP address of the Teensy to be the same as the IP address of Ethernet 2, it must be different but in the same subnet.

The IP address you have set on Ethernet 2 is on the same subnet as the IP address on Ethernet (1). It must be a different subnet. Perhaps try 10.10.16.110 on Ethernet 2, which is a different subnet.

Although I am not familiar with the ethernet library you are using it appears that you are still using DHCP to set the IP address on the Teensy, this will fail. You need to find out how to set a static IP address on the Teensy, perhaps use 10.10.16.111 for example.

In case you are still not clear:
Ethernet (1) dynamic IP address obtained by DHCP from the network you are connected to. From your screenshot this is 10.10.15.101, subnet mask 255.255.255.0, so the subnet is 10.10.15.0/24

Ethernet 2, connected to your Teensy, must have an IP address in a different subnet to Ethernet (1), so I am suggesting subnet 10.10.16.0/24. Suggested IP address 10.10.16.110

Teensy must have a static IP address in the same subnet as Ethernet 2, but must be different from the one Ethernet 2 has. Suggested IP address 10.10.16.111

Alright, now I am getting the point (thank you very much for all the patience with me). The only question that is left for me is:

Ethernet 2 basically is my teensy. If I disconnect LAN cable from my teensy, there is no Ethernet 2 left in the ipconfig. So do I still need to assign same subnet but different IP adresses (one to ethernet 2 and the second one in the Arduino IDE code for the teensy itself) It feels so counterintuitive...

I mean, in the windows configuration, I enter 10.10.16.110 for ethernet 2, and in the Arduino IDE I enter 10.10.16.111 for the teensy code? Is that really how it works?

I don't understand this. From everything you have said I believe you have 2 ethernet ports on your PC, Ethernet (1) connected to your network and Ethernet 2 connected to your Teensy. Is this correct?

Yes, that is correct.

Okay, maybe ''Ethernet 2 basically is my teensy" wasnt exact in technical terms.

But Ethernet 1 is my internet netwrok port, and Ethernet 2 is connected to teensy indeed.

That looks right to me. Why do you think it's counterintuitive? What does your intuition tell you?

Okay, I did just like that. My problem still persists but at least I learned something about networking. Thank you very much again.

Ok, sorry I don't have any further suggestions. I hope someone else can help you.

never used that board or lib either..
but that is not how to use a static address assignment..
give this untested code a shot, sorry..

// SPDX-FileCopyrightText: (c) 2023 Shawn Silverman <shawn@pobox.com>
// SPDX-License-Identifier: MIT

// BroadcastChat is a simple chat application that broadcasts and
// receives text messages over UDP.
//
// This file is part of the QNEthernet library.

#include <QNEthernet.h>

using namespace qindesign::network;

// --------------------------------------------------------------------------
//  Configuration
// --------------------------------------------------------------------------

//constexpr uint32_t kDHCPTimeout = 10'000;  // 10 seconds

// Set the static IP to something other than INADDR_NONE (all zeros)
// to not use DHCP. The values here are just examples.
IPAddress staticIP{10, 10, 16, 111};//{192, 168, 1, 101};
IPAddress subnetMask{255, 255, 255, 0};
IPAddress gateway{10, 10, 16, 1};


constexpr uint16_t kPort = 5190;  // Chat port

// --------------------------------------------------------------------------
//  Program State
// --------------------------------------------------------------------------

// UDP port.
EthernetUDP udp;

// --------------------------------------------------------------------------
//  Main Program
// --------------------------------------------------------------------------

// Forward declarations (not really needed in the Arduino environment)
static void printPrompt();
static void receivePacket();
static void sendLine();

// Program setup.
void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 4000) {
    // Wait for Serial
  }
  printf("Starting...\r\n");

  uint8_t mac[6];
  Ethernet.macAddress(mac);  // This is informative; it retrieves, not sets
  printf("MAC = %02x:%02x:%02x:%02x:%02x:%02x\r\n",
         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

  Ethernet.onLinkState([](bool state) {
    printf("[Ethernet] Link %s\r\n", state ? "ON" : "OFF");
  });

  // Static IP
  printf("Starting Ethernet with static IP...\r\n");
  if (!Ethernet.begin(staticIP, subnetMask, gateway)) {
    printf("Failed to start Ethernet\r\n");
    return false;
  }

  /*
    printf("Starting Ethernet with DHCP...\r\n");
    if (!Ethernet.begin()) {
      printf("Failed to start Ethernet\r\n");
      return;
    }
  */

  /*
    if (!Ethernet.waitForLocalIP(kDHCPTimeout)) {
    printf("Failed to get IP address from DHCP\r\n");
    return;
    }
  */
  IPAddress ip = Ethernet.localIP();

  //IPAddress ip = {10, 10, 15, 110};
  printf("    Local IP     = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);
  ip = {255, 255, 255, 0};                     //Ethernet.subnetMask();
  printf("    Subnet mask  = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);
  ip = {255, 255, 255, 255};                   //Ethernet.broadcastIP();
  printf("    Broadcast IP = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);
  ip = {10, 10, 10, 254};                      //Ethernet.gatewayIP();
  printf("    Gateway      = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);
  ip = {10, 10, 10, 244};                      //Ethernet.dnsServerIP();
  printf("    DNS          = %u.%u.%u.%u\r\n", ip[0], ip[1], ip[2], ip[3]);

  // Start UDP listening on the port
  udp.begin(kPort);

  printPrompt();
}

// Main program loop.
void loop() {
  receivePacket();
  sendLine();
}

// --------------------------------------------------------------------------
//  Internal Functions
// --------------------------------------------------------------------------

// Control character names.
static const String kCtrlNames[] {
  "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
  "BS",  "HT",  "LF",  "VT",  "FF",  "CR",  "SO",  "SI",
  "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
  "CAN", "EM",  "SUB", "ESC", "FS",  "GS",  "RS",  "US",
};

// Receives and prints chat packets.
static void receivePacket() {
  int size = udp.parsePacket();
  if (size < 0) {
    return;
  }

  // Get the packet data and remote address
  const uint8_t *data = udp.data();
  IPAddress ip = udp.remoteIP();

  printf("[%u.%u.%u.%u][%d] ", ip[0], ip[1], ip[2], ip[3], size);

  // Print each character
  for (int i = 0; i < size; i++) {
    uint8_t b = data[i];
    if (b < 0x20) {
      printf("<%s>", kCtrlNames[b].c_str());
    } else if (b < 0x7f) {
      putchar(data[i]);
    } else {
      printf("<%02xh>", data[i]);
    }
  }
  printf("\r\n");
}

// Tries to read a line from the console and returns whether
// a complete line was read. This is CR/CRLF/LF EOL-aware.
static bool readLine(String &line) {
  static bool inCR = false;  // Keeps track of CR state

  while (Serial.available() > 0) {
    int c;
    switch (c = Serial.read()) {
      case '\r':
        inCR = true;
        return true;

      case '\n':
        if (inCR) {
          // Ignore the LF
          inCR = false;
          break;
        }
        return true;

      default:
        if (c < 0) {
          return false;
        }
        inCR = false;
        line.append(static_cast<char>(c));
    }
  }

  return false;
}

// Prints the chat prompt.
static void printPrompt() {
  printf("chat> ");
  fflush(stdout);  // printf may be line-buffered, so ensure there's output
}

// Reads from the console and sends packets.
static void sendLine() {
  static String line;

  // Read from the console and send lines
  if (readLine(line)) {
    if (!udp.send(Ethernet.broadcastIP(), kPort,
                  reinterpret_cast<const uint8_t *>(line.c_str()),
                  line.length())) {
      printf("[Error sending]\r\n");
    }
    line = "";
    printPrompt();
  }
}

got this by looking through all the examples for your lib..
hope this helps..

good luck.. ~q

Thank you so much, after a bit of experiments and editing I managed to get what I needed. I wrote a simple python script for PC to take the communication to next level. The only problem left now is how do I send other types of data from teensy? What I mean by that is that code is written for transmitting a serial monitor input. But what if want to send lets say parameters of some sensors or just a pre-compile defined text.

// Reads from the console and sends packets.
static void sendLine() {
  static String line;

  if (readLine(line)) {
    if (!udp.send({10, 10, 16, 110}, kPort,
                  reinterpret_cast<const uint8_t *>(line.c_str()),
                  line.length())) {
      printf("[Error sending]\r\n");
    }
    line = "";
    printPrompt();
  }
}

udp.send looks to be writen using really advanced C syntax, could you provide me a simple template how I would call this function if I want to send just a simple defined int or char?

I tried some way myself, but that was only resulting in errors