WiFi testing program

Over in the Support category a member was recently having trouble connecting to WiFi to update firmware: Can’t connect to wifi. It occurred to me that the firmware update is not the ideal way to debug WiFi problems. So I wrote a small WiFi application where the code can be easily fiddled with to try various potential solutions to WiFi problems.

Here is the program:

// Programming example: connecting to a WiFi network and periodically exchanging UDP datagrams with the
// NTP server at time.nist.gov (port 123). UDP is an unreliable protocol in that no UDP datagram is guaranteed
// to reach its destination, so not every request for current time will be honored. Furthermore time.nist.gov
// does not allow requests less than 4 seconds apart. So this program requests the time approximately every
// 10 seconds and extrapolates the time after each 10-second request by using the jiffy clock function millis().

// This program is intended to allow debugging WiFi connection problems including DNS failures. See the highlited
// code below where the user may customize this program to use either the DHCP-supplied DNS server or a known
// good DNS server, and to attempt to connect to a NIST NTP server either by name or by IP address. If the
// connection by name fails to resolve the name, then the DNS server in use is failing.

// If the WiFi connection to the specified SSID with the specified password succeeds, and the NTP server name
// resolves, the program will display the date/time returned by the server. If datagrams get lost, there may be
// momentary pauses in updating the date/time while the UDP request is retried; occasional datagram loss is
// expected as such is the nature of UDP.

// See highlighted comments below to customize program for your network and DNS testing.

// Example coded 5/10/2020 by Frank Prindle.

#include "MAKERphone.h"
MAKERphone mp;

void setup()
{
  mp.begin(1);

  /*-----------------------------------------------------------*/
  /* Set the following two strings to match your WiFi network. */
  /*-----------------------------------------------------------*/
  char *SSID = "FrankNet5";
  char *WPAPassword = "1234ABCD";

  /*-------------------------------------------------------------------*/
  /* Disable the following line to use DHCP supplied DNS server.       */
  /* Enable the following line to use a well-known DNS server.         */
  /*    Set the first IP address to a valid static IP on your network. */
  /*    Set the second IP address to the IP address of your router.    */
  /*    Set the third IP address to your network mask.                 */
  /*    Leave the fourth IP address alone (Google DNS).                */
  /*-------------------------------------------------------------------*/
  //WiFi.config(IPAddress(192,168,1,177),IPAddress(192,168,1,1),IPAddress(255,255,255,0),IPAddress(8,8,8,8));
  
  WiFi.begin(SSID,WPAPassword);
  int count=100;
  while(WiFi.status() != WL_CONNECTED && count--) delay(100);
  mp.display.setTextFont(1);
  mp.display.fillScreen(TFT_BLACK);
  if(WiFi.status() != WL_CONNECTED)
  {
    Serial.printf("WiFi cannot connect to given SSID with given password\n");
    statusline("WiFi Connect Failure", true);
    delay(5000);
    statusline("WiFi Connect Failure", false);
  }
  else
  {
    Serial.printf("WiFi is connected\n");
    statusline("WiFi Is Connected", true);
    delay(2000);
    statusline("WiFi Is Connected", false);
  }
}

void loop()
{
  unsigned int localPort = 8888; // Fairly arbitrary
  unsigned char inPacket[48];
  // NTP time request packet
  unsigned char outPacket[48] = {0b11100011, 0, 6, 0xEC, 0, 0 ,0, 0, 0, 0, 0, 0, 49, 0x4E, 49, 52, 0, 0, 0, 0, 0,
                                 0, 0, 0, 0 ,0 ,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
                                 
  WiFiUDP udp;
  udp.begin(localPort);
  statusline("Trying To Resolve Server", true);

  /*-------------------------------------------------------------*/
  /* Enable only one of the following two lines.                 */
  /* Enable first line to use DNS to find an NTP server by name. */
  /* Enable second line to use an NTP server's IP address.       */
  /*-------------------------------------------------------------*/
  udp.beginPacket("time.nist.gov", 123); // NTP requests are to port 123
  //udp.beginPacket("129.6.15.28", 123); // NTP requests are to port 123

  statusline("Trying To Resolve Server", false);
  udp.write(outPacket, sizeof(outPacket));
  udp.endPacket();
  int count=100;
  while(udp.parsePacket() < sizeof(inPacket) && --count)
  {
    statusline("NTP Waiting For Response", true);
    delay(20);
  }
  statusline("NTP Waiting For Response", false);
  if(count)
  {
    // NTP request honored - time is in packet
    unsigned long ms = millis();
    udp.read(inPacket, sizeof(inPacket));
    unsigned long secsSince1900 = (inPacket[40]<<24) | (inPacket[41]<<16) | (inPacket[42]<<8) | inPacket[43];
    long secsSinceEpoch = secsSince1900 - 2208988800UL;

    // Extrapolate displayed time over 10 seconds
    while(millis()-ms < 10000)
    {
      // Extrapolate time now
      long sse = secsSinceEpoch+(millis()-ms)/1000;
      char *msg = ctime(&sse);
      msg[24]='\0';
      Serial.printf("%s UTC\n",msg);

      // Display the extrapolated time - if top line is yellow, time is from NTP - if green, time is exratpolated
      if(sse == secsSinceEpoch) mp.display.setTextColor(TFT_YELLOW);
      else                      mp.display.setTextColor(TFT_GREEN);
      mp.display.fillScreen(TFT_BLACK);
      mp.display.setCursor(20,8);
      mp.display.print("FROM: time.nist.gov");
      mp.display.setTextColor(TFT_GREEN);
      mp.display.setCursor(8,50);
      mp.display.print(msg);
      mp.display.print("\n\n            UTC");
      mp.display.pushSprite(0,0);
    }
  }
  else
  {
    // NTP request not honored (either outgoing packet or incoming packet lost)
    statusline("NTP No Response - Retry", true);
    delay(1000);
    statusline("NTP No Response - Retry", false);
  }
  // Shut down UDP in preparation for next loop
  udp.stop();
}

// Display (on==true) or erase (on==false) transient status line near bottom of display
void statusline(char *msg, bool on)
{
  mp.display.setTextColor(on ? TFT_YELLOW : TFT_BLACK);
  mp.display.setCursor(0,100);
  mp.display.print(msg);
  mp.display.pushSprite(0,0);

}

You can compile and upload this to the Ringo phone using the Arduino IDE after customizing it (see comments in code). If your WiFi is working well and you’ve used a valid WiFi network SSID and password, it will display the UTC date and time obtained from NTP server time.nist.gov. If the WiFi connection fails or time.nist.gov cannot be resolved to an IP address, a status line will so indicate, and you can modify the code to further explore the problem. You are obviously not limited to the code variations I’ve marked; feel free to change this in any way that benefits you and enhances your understanding of using WiFi from the Ringo phone.

This is a simple example using UDP over IP. There are other more complex protocols supported by the ESP32 WiFi library such as TCP and HTTP, which you may want to explore on your own.

1 Like

I gave this a try on mine and it works great on its own.

I also tried to export it as a bin to add as an application on the SD card and it doesn’t show up in the list to launch. Not sure why. Would be great to call this on demand from the main OS.

1 Like

Hey there,

Here is the link on how to do that - https://www.circuitmess.com/world/guides/circuitblocks-11/making-a-.bin-file-299.

I guess that your folder name is not the same as the .bin file name, which is crucial in order for this to work. :slight_smile:

Keep in touch and hit me up if you don’t manage to solve it!

Robert

@robertCM oh jeez…of course, that is precisely the caveat I missed. As soon as I name the folder and .bin the same, all works fine. :man_facepalming: Thanks for catching that!

@frankprindle Do you have this on a git I can fork from? I’d love to collaborate on expanding this into a more expansive wifi utility. If not, I can throw it up on my git to allow others to build upon it.

I went ahead and added a new repo for my Ringo code:

I updated the original code above to allow the user to return to the main loader with B or Home, since I prefer to run this as an app on the SD for future development (the original code required reflashing to return to normal)

My next task is to prompt the user at the start to provide the SSID/WPA, instead of a hard code of the values. We can store this on the SD for future runs. Once that is done, it will be a better framework to build upon and for others to play with.

I’m still struggling a little with figuring out what all the mp.*() functions are. Is this documented in one comprehensive location? Been picking through source for what I’ve learned of them thus far…but we all know how tedious that can be. haha

After some generous cut/paste from settingsApp and such in the main codebase, I was able to add the prompts at the start to setup the wifi network, then it proceeds along to the original NTP test.

I tidied everything up a bit, created an icon, and uploaded my current “stable” .ino and .bin. So, you can just download the /WiFiTest repo, unzip it to the SD card, pop it in, and it will show at the bottom of the loader menu. :slight_smile:

This lays some basic foundation for more functionality to be added without things being hard coded. I’m going to work on a menu to specify DHCP or manual network config, NTP server, etc to show immediately after successful connection to a network. Then roll that up into it’s own menu-selected function (I’m probably going to “borrow” a LOT from the settingsApp code for this) so more tests can be added in addition to the NTP test.

TWM, I’ve been offline since last Wednesday due to a storm. Now that I’m back, I see you took this and ran with it - good for you - that’s what I was hoping would happen; I posted it as a little tease as to where one could go with a WiFi application.

@frankprindle Glad you survived the storm! I’ve made sure to give credit where due in the src and on the git. If you wanna jump in and help further, feel free to hop on my git and take a look at where I’ve gotten thus far. :grin:

Hey,

Good to see some active and solid work! Unfortunately, we don’t have our functions documented completely yet, but borrowing from the actual apps is the way to go!

If you don’t understand something feel free to hit me up here so I can explain how something works more thoroughly.

There is also a lot of material online regarding the work with ESP32 and WiFi connections so I’m sure you’ll be able to find a lot of different things in no time. :slight_smile:
Even Arduino ESP32 libraries have a lot of examples which can be used and which display how different protocols work. (here are some of them)

Cheers,
Robert