So you're a Noob? Post your questions here until you graduate! Don't be shy.

User avatar
By MAWMN
#86053 While trying to write my own simple custom udp client library, I am having some troubles getting it to work.

[see Code parts UDPClient2.cpp and UDPClient2.h as well as a test application ESP8266_UDPClient2.ino]

Is there anyone who can point me in the right direction ?

Problems & Questions :

    No data is being sent to the PC, because in the Library the _socketIsOpen keeps being reported as FALSE, while when having received Data the _socketIsOpen should be reported as being TRUE
    In the library defined debug messages don't work either
    I am wondering why I have to declare "WiFiUDP clUDP" to be able to use "UDPClient2 myClient(clUDP)"

thanks..

UDPClient2.cpp
Code: Select all#include "Arduino.h"
#include "UDPClient2.h"

// Uncomment to enable printing out nice debug messages.
#define DEBUG_UPDClientLib           // UDP Library produces Debug info on Serial Monitor..

 UDPClient2::UDPClient2(UDP& udp) {
   this->_udp            = &udp;
 }


void UDPClient2::begin() {
  this->_udp->begin(this->_port);   // = UDP_DEFAULT_LOCAL_PORT

  this->_udpSetup = true;

  #ifdef DEBUG_UDPClientLib
    Serial.print("UDP-Port        : ");
    Serial.println(this->_port);
   Serial.print("UDPSetup        : ");
    Serial.println(this->_udpSetup);
   Serial.flush();
  #endif
}


void UDPClient2::begin(int port) {   // = ANY GIVEN PORT
  this->_port = port;

  this->_udp->begin(this->_port);

  this->_udpSetup = true;

  #ifdef DEBUG_UDPClientLib
    Serial.print("UDP-Port        : ");
    Serial.println(this->_port);
   Serial.print("UDPSetup        : ");
    Serial.println(this->_udpSetup);
   Serial.flush();
  #endif
}

int UDPClient2::receive() {
  //   if there's data available, read the packet
  int packetSize = this->_udp->parsePacket();
  if (packetSize)
  {
    // Receive ANY packet and Remember the open Socket Params
    this->_remoteIp = this->_udp->remoteIP();
    this->_remotePort = this->_udp->remotePort();

    // Read the packet into receiveBufffer
    int len = this->_udp->read(this->_receiveBuffer, sizeof(this->_receiveBuffer));
    if (len > 0) this->_receiveBuffer[len] = 0;   // close the received data in the buffer

    this->_socketIsOpen = true;

   #ifdef DEBUG_UDPClientLib
     Serial.println("*** UDP-Data Received ***");
     Serial.print("UDP-Data Size   : ");
      Serial.println(packetSize);
     Serial.print("from RemoteIP   : ");
      Serial.println(this->_remoteIp);
     Serial.print("in RemotePort   : ");
      Serial.println(this->_remotePort);
     Serial.print("SocketState     : ");
      Serial.println(this->_socketIsOpen);
      Serial.flush();
    #endif
  }
  return packetSize;
}


String UDPClient2::getReceiveBuffer() {
  String rtnStr = this->_receiveBuffer;   // Convert Array to String
  #ifdef DEBUG_UDPClientLib
   Serial.print("UDP-Data String : ");
    Serial.println(rtnStr);
   Serial.flush();
  #endif
  return rtnStr;
}


bool UDPClient2::send(String toSend) {
  #ifdef DEBUG_UDPClientLib
   Serial.println("*** UDP-Data Send ***");
   Serial.print("SocketState     : ");
    Serial.println(this->_socketIsOpen);
   Serial.print("UDP-Data String : ");
    Serial.println(toSend);
   Serial.flush();
  #endif
  if (this->_socketIsOpen) {
    // Send ANY Packet if the Socket is open
    memset(this->_sendBuffer, 0, sizeof(this->_sendBuffer));  // fill the sendBuffer with 0
//    strcpy(this->_sendBuffer, toSend.c_str());                // Copy the chars to_send array to the sendBuffer
    strcpy((char *)this->_sendBuffer, toSend.c_str());          // Copy the bytes to_send array to the sendBuffer

    #ifdef DEBUG_UDPClientLib
     Serial.print("Sendbuffer      : ");
      Serial.println(this->_sendBuffer);
     Serial.print("Sendbuffer Size : ");
      Serial.println(sizeof(this->_sendBuffer));
     Serial.print("to RemoteIP     : ");
      Serial.println(this->_remoteIp);
     Serial.print("in RemotePort   : ");
      Serial.println(this->_remotePort);
     Serial.flush();
    #endif

    // Send the Packet, to the IP address and port that sent us these packets before
    this->_udp->beginPacket(this->_remoteIp, this->_remotePort);
    //this->_udp->write((uint8_t) *this->_sendBuffer );             // Does NOT Work as in NTPClient2, Sendbuffer is of type char ipv byte
    this->_udp->write(this->_sendBuffer, sizeof(this->_sendBuffer)); // Works as in NTPClient2, Sendbuffer is of type byte ipv char

    this->_udp->endPacket();
    return true;
  } else return false;
}


bool UDPClient2::getIsSocketOpen() {
  if (this->_socketIsOpen) {
    // No packet has been received in 70 seconds, restart the UdpClient
    this->_socketIsOpen = false;

    // Stop & Restart the Udp client2 connection ,
    //   to clear the remebered remoteIp and remotePort
    // Because of reset WDT cause:2, boot mode:(3,6), insert delay(0)
    this->_udp->stop();
    delay(0);
    this->_udp->begin(this->_port);         // = LocalPort
    delay(0);
    #ifdef DEBUG_UDPClientLib
     Serial.println("*** Socket has been Closed ***");
     Serial.print("SocketState     : ");
      Serial.println(this->_socketIsOpen);
     Serial.print("Port Restart    : ");
     Serial.println(this->_port);
     Serial.flush();
    #endif
  }
  return this->_socketIsOpen;
}


bool UDPClient2::update() {
  if ((millis() - this->_lastUpdate >= this->_updateInterval)     // Update after _updateInterval
    || this->_lastUpdate == 0) {                                  // Update if there was no update yet.
    if (!this->_udpSetup) this->begin(this->_port);               // setup the UDP client if needed
    return this->getIsSocketOpen();
  } else return true;
}


IPAddress UDPClient2::getRemoteIp() {
  #ifdef DEBUG_UDPClientLib
   Serial.print("getRemoteIP     : ");
    Serial.println(this->_remoteIp);
   Serial.flush();
  #endif
  return this->_remoteIp;
}


uint16_t UDPClient2::getLocalPort() {
  #ifdef DEBUG_UDPClientLib
   Serial.print("getLocalPort    : ");
    Serial.println(this->_port);
   Serial.flush();
  #endif
  return this->_port;
}


uint16_t UDPClient2::getRemotePort() {
  #ifdef DEBUG_UDPClientLib
   Serial.print("getRemotePort   : ");
    Serial.println(this->_remotePort);
   Serial.flush();
  #endif
  return this->_remotePort;
}


void UDPClient2::setUpdateInterval(unsigned int updateInterval) {
  this->_updateInterval = updateInterval;
  #ifdef DEBUG_UDPClientLib
   Serial.print("setUpdateInterval: ");
    Serial.println(this->_updateInterval);
   Serial.flush();
  #endif
}


void UDPClient2::end() {
  this->_udp->stop();

  this->_udpSetup = false;
  #ifdef DEBUG_UDPClientLib
   Serial.println("*** Close UDP Connection ***");
   Serial.print("UDPSetup        : ");
    Serial.println(this->_udpSetup);
   Serial.flush();
  #endif
}


UDPClient2.h
Code: Select all#ifndef UDPClient2_h
#define UDPClient2_h

#pragma once

#include "Arduino.h"
#include <WiFiUdp.h>

// Uncomment to enable printing out nice debug messages.
#define DEBUG_UPDClientLib     // UDP Library produces Debug info on Serial Monitor..

#define UDP_DEFAULT_LOCAL_PORT 2101
#define UDP_DEFAULT_BUFFSIZE 255

class UDPClient2 {
  private:
    UDP*          _udp;
    bool          _udpSetup       = false;
    int           _port           = UDP_DEFAULT_LOCAL_PORT;
    IPAddress     _remoteIp       = '\0';
    uint16_t      _remotePort     = 0;

    char          _receiveBuffer[UDP_DEFAULT_BUFFSIZE];      // Buffer to hold incoming Udp-packet
//    char          _sendBuffer[255];       // A Custom char string to send back to the PC
    byte          _sendBuffer[UDP_DEFAULT_BUFFSIZE];         // A Custom byte string to send back to the PC

    bool          _socketIsOpen   = false;

    unsigned int  _updateInterval = 60000;  // In ms

    unsigned long _lastUpdate     = 0;      // In ms

  public:
    UDPClient2(UDP& udp);

    // /**
    //  * Starts the underlying UDP client with the default local port
    //  */
    void begin();

    /**
     * Starts the underlying UDP client with the specified local port
     */
    void begin(int port);

    /**
     * This should be called in the main loop of your application.
     * By default an update from the UDP Server is done automatically.
     *
     * @return #num of characters received on success, 0 on failure
     */
     int receive();

    /**
     * @return The Receivebuffer contents as a String
     */
    String getReceiveBuffer();

    /**
     * @return The result if the message has been sent
     */
    bool send(String toSend);

    /**
     * @return The Status of the Current UDP Socket, OPEN = true, CLOSED = false
     */
    bool getIsSocketOpen();

    /**
     * @return The RemoteIP for the UDP Socket
     */
    IPAddress getRemoteIp();

    /**
     * @return The LocalPort for the UDP Socket
     */
    uint16_t getLocalPort();

    /**
     * @return The RemotePort for the UDP Socket
     */
    uint16_t getRemotePort();

    /**
     * This should be called in the main loop of your application.
     * By default an update from the UDP Server is only
     * made every 60 seconds.
     *
     * @return true on success, false on failure
     */
     bool update();

    /**
     * Sets the timer update Interval
     */
    void setUpdateInterval(unsigned int interval);

    /**
     * Stops the underlying UDP client
     */
    void end();

};

#endif


ESP8266_UDPClient2.ino
Code: Select all// Orgineel - 11-03-2020   ESP8266_UDPClient2.ino

#include <ESP8266WiFi.h>                            // ESP8266 WiFi
#include <WiFiUdp.h>                                // WiFi

#include <ESP8266WebServer.h>     // tbv WiFiManager
#include <DNSServer.h>            // tbv WiFiManager
#include <WiFiManager.h>          // tbv WiFiManager


#include <UDPClient2.h>                             // tbv Simple Custom UDPClient for Wemos Device specific application

// Uncomment to enable printing out nice debug messages.
#define DEBUG_UPDClientLib     // UDP Library produces Debug info on Serial Monitor.. (NOT Working ??)

// Uncomment to enable printing out nice debug messages.
// #define UDPCLIENT_DEBUG
#define UDPCLIENT_DEBUG

// Define where debug output will be printed.
#define UDPCLIENT_PRINTER Serial

// Setup DBG_UDP printing MACRO
#ifdef UDPCLIENT_DEBUG
  #define DBG_UDP_PRINT(...) { UDPCLIENT_PRINTER.print(__VA_ARGS__); }
  #define DBG_UDP_PRINTLN(...) { UDPCLIENT_PRINTER.println(__VA_ARGS__); }
#else
  #define DBG_UDP_PRINT(...) {}
  #define DBG_UDP_PRINTLN(...) {}
#endif

// tbv testen LIBRARY CODE UDPClient2 (myClient)
WiFiUDP clUDP;                                    // Start the underlying UDP Library
UDPClient2  myClient(clUDP);                      // Start the Custom Udp Client (LIBRARY) functionality

int UdpLocPort                        = 2101;     // local port to listen on for Udp messages send by the PC

unsigned long alivePeviousSendTime    = millis(); // aliveSendTime when the last alive packet was send to the PC
const long    aliveSendtimeoutTime    = 60;       // Define timeout time to send an alive packet to the PC in sec.
unsigned long lastReceivedTime        = millis(); // timestamp of the last received packet from the PC
unsigned long lastReceivedtimeoutTime = 70;       // Define min. timeout of the last received packet from the PC in sec.



void setup() {

  /*******************************************************************************/
  /***** Serial Setup *****/
  /*******************************************************************************/
  Serial.begin(115200);

  /*******************************************************************************/
  /***** WiFiManager Setup *****/
  /*******************************************************************************/
  // WiFiManager Initialisation
  WiFiManager wifiManager;

  // WiFiManager setDebugInfo (true or false)
  wifiManager.setDebugOutput(false);

  // Reset WiFiManager's saved Setting from Eeprom
  //   comment out after config is done, Parameter Reset can Now be done by WebPage
  //wifiManager.resetSettings();

  // Set TimeOut until the Configuration Portal gets turned OFF (in Sec.)
  wifiManager.setTimeout(120UL);

  // Sets the minimum Signal Quality, will NOT show sign ON networks below the set value,
  //   default is set to 8% (so uou will see a lot of networks !!!)
  wifiManager.setMinimumSignalQuality(30);  // Min. RSSI Quality = 30%

  // Disable sleep, can improve Access Point stability
  WiFi.setSleepMode(WIFI_NONE_SLEEP);

  // Start an AccessPoint with the specified name here (mna_AP_Test_Manager),
  //   and goes into a blocking loop awaiting configuration at IP Address 192.168.4.1
  //   Serial.println("Failed to connect and hit TimeOut");
  //   delay(3000);
  //   // Reset and Try again
  //   ESP.reset();
  //   delay(5000);
  // }

  // OR With Autoconnect !!!
  //   fetches SSID and Password from Eeprom and tries to Connect,
  //   if it does NOT Connect it starts an AccessPoint with the specified name,
  //   and goes into a blocking loop awaiting configuration.

  // OR With Autoconnect & Reset!!!
  //   fetches SSID and Password from Eeprom and tries to Connect,
  //   if it does NOT Connect it starts an AccessPoint with the specified name,
  //   and goes into a blocking loop awaiting (New) configuration.
  if (!wifiManager.autoConnect("mna_AP_Test_Manager", "")) {
    Serial.println("Failed to connect and hit TimeOut");
    Serial.flush();
    delay(3000);
    // Reset and Try again
    //   the complete Program will be Restarted Now...(as if it was Powered UP again)
    ESP.reset();
    delay(5000);
  }

  /*******************************************************************************/
  /***** Start the Custom UDP Client (myClient) @port 2101 *****/
  /*******************************************************************************/
  myClient.begin();                       // Start the Custom Client to listen @port 2101


  /*******************************************************************************/
  /***** Application Startup *****/
  /*******************************************************************************/
  Serial.println();
  Serial.println();
  Serial.println("***** mna_AP_Test_Manager - Board Startup Message  *****");
  Serial.print("Connected to     : ");
  Serial.println(WiFi.SSID());
  Serial.flush();

  Serial.print("IP gateway       : ");               
  Serial.println(WiFi.gatewayIP());
  Serial.print("IP subnet        : ");             
  Serial.println(WiFi.subnetMask());
  Serial.print("IP address       : ");             
  Serial.println(WiFi.localIP());
  Serial.print("UdpLocalPort     : ");             
  Serial.println(myClient.getLocalPort());
  Serial.flush();
  Serial.println("----------------------------------------------");     
  Serial.println("Start Receiving & Sending the UDP Data");
 }


void UdpClientDebugInfo(String InpStr, int Richting)    // Richting 1 = Send To PC, 2 = Received from PC
{
  #ifdef UDPCLIENT_DEBUG
    // tbv Debug
    if (Richting == 1) {
      UDPCLIENT_PRINTER.print("Send to PC       : ");
      UDPCLIENT_PRINTER.print(InpStr);                  // Packet contents
    } else if (Richting == 2) {
      UDPCLIENT_PRINTER.print("Received from PC : ");
      UDPCLIENT_PRINTER.print(InpStr);                  // Packet contents
    }
    UDPCLIENT_PRINTER.print(" (");
    UDPCLIENT_PRINTER.print(InpStr.length());           // Packet Length
    UDPCLIENT_PRINTER.print(")\t[locIP (Dev) ");
    UDPCLIENT_PRINTER.print(WiFi.localIP());            // Local IP (Dev)
    UDPCLIENT_PRINTER.print(" : remIP (PC) ");
    UDPCLIENT_PRINTER.print(myClient.getRemoteIp());    // Remote IP (PC)
    UDPCLIENT_PRINTER.print(" : DevLisPort ");
    UDPCLIENT_PRINTER.print(myClient.getLocalPort());   // Device Listener Port
    UDPCLIENT_PRINTER.print(" : DevOutPort ");
    UDPCLIENT_PRINTER.print(myClient.getRemotePort());  // Device Output via Port
    UDPCLIENT_PRINTER.println("]");
  #endif
}


bool SendPacket(String &toSend) {
  Serial.print("SocketState : ");
  Serial.println(myClient.getIsSocketOpen());
  if (myClient.getIsSocketOpen()) {
    Serial.print("Data to Send : ");
    Serial.println(toSend);
    myClient.send(toSend);
    return true;
  } else return false;
}


void ReceiveUdp() {
  // Try to Receive UDP-Packets
  int packSize =  myClient.receive();
  if (packSize > 0)
  {
    yield();  // Feed the WDT as the text output can take a while to print.
    lastReceivedTime = millis();

    // Analize the Received contents
    String recvStr = myClient.getReceiveBuffer();   // Convert Array to String

    #ifdef UDPCLIENT_DEBUG
      // tbv Debug
      UdpClientDebugInfo(recvStr, 2);
    #endif
    Serial.flush();

    // Analize received data, do we need to reply ?
    String WhatToSend = "";
    if (recvStr == "PcAlive") {
      WhatToSend = "DevACK";
    } else {
      // what else to do ??
    }

    // Send the Reply
    if (WhatToSend != "") {
      SendPacket(WhatToSend);     // Blind send a packet to the PC, NO Control if the socket realy is open
      #ifdef UDPCLIENT_DEBUG
        // tbv Debug
        UdpClientDebugInfo(WhatToSend, 1);
      #endif
      Serial.flush();
      yield();  // Feed the WDT as the text output can take a while to print.
    }
  }
}


void SendDeviceAlive() {
  // Send a (fixed) packet to the PC in an fixed time interval (change this for other situations..)
  if ((millis() - alivePeviousSendTime) > (aliveSendtimeoutTime * 1000)) {
    String WhatToSend = "DevAlive";

    if (SendPacket(WhatToSend)) {          // Control if the socket realy is open
      #ifdef UDPCLIENT_DEBUG
        // tbv Debug
        UdpClientDebugInfo(WhatToSend, 1);
      #endif
      Serial.flush();
      yield();  // Feed the WDT as the text output can take a while to print.
    } else {
      #ifdef UDPCLIENT_DEBUG
        // tbv Debug
        UDPCLIENT_PRINTER.println("There is NO open Socket (anyMore, AutoClosed) to send anything to...");
      #endif
      Serial.flush();
    }
    alivePeviousSendTime = millis();
  }
}


void loop() {
  // Your main code here, to run repeatedly & test the Library:
  // Try to Receive UDP-Packets
  ReceiveUdp();

  yield();  // Feed the WDT as the text output can take a while to print.

  SendDeviceAlive();

  yield();  // Feed the WDT as the text output can take a while to print.

  myClient.update();

}