Problems trying to write my own simple custom udp client lib
Posted: Sat Mar 14, 2020 11:09 am
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 :
thanks..
UDPClient2.cpp
UDPClient2.h
ESP8266_UDPClient2.ino
[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();
}