AsyncUDP_STM32 for STM32 using builtin LAN8742A Ethernet

Working libraries, libraries being ported and related hardware
Post Reply
khoih-prog
Posts: 102
Joined: Thu Feb 27, 2020 7:54 am
Location: Toronto

AsyncUDP_STM32 for STM32 using builtin LAN8742A Ethernet

Post by khoih-prog »

AsyncUDP_STM32

AsyncUDP_STM32

How To Install Using Arduino Library Manager


Why do we need this Async AsyncUDP_STM32 Library

- Using asynchronous network means that you can handle more than one connection at the same time
- You are called once the packet is ready
- After connecting to a UDP server as an Async Client, you are immediately ready to handle other connections while the Client is taking care of receiving the UDP responding packets in the background.
- You are not required to check in a tight loop() the arrival of the UDP responding packets to process them.
- Speed is OMG

Initial Releases v1.1.0

1. Initial coding to port the powerful ESPAsyncUDP Library to STM32 boards using built-in LAN8742A Ethernet. More supports will be added gradually later, such as other Ethernet / WiFi shields.
2. Add more examples.
3. Add debugging features.
4. Bump up to v1.1.0 to sync with ESPAsyncUDP Library v1.1.0.

Currently Supported Boards

1. Nucleo-144 (F429ZI, F746ZG, F756ZG, F767ZI)
2. Discovery STM32F746G-DISCOVERY
3. Any STM32 boards with enough flash/memory and already configured to run LAN8742A Ethernet.

Sample Code

This is the AsyncUdpNTPClient example

Code: Select all

/*
   Currently support
   1) STM32 boards with built-in Ethernet (to use USE_BUILTIN_ETHERNET = true) such as :
      - Nucleo-144 (F429ZI, F767ZI)
      - Discovery (STM32F746G-DISCOVERY)
      - STM32 boards (STM32F/L/H/G/WB/MP1) with 32K+ Flash, with Built-in Ethernet,
      - See How To Use Built-in Ethernet at (https://github.com/khoih-prog/EthernetWebServer_STM32/issues/1)
*/

#include "defines.h"
#include <time.h>

IPAddress timeWindowsCom = IPAddress(13, 86, 101, 172);

#define NTP_REQUEST_PORT      123

char timeServer[]         = "time.nist.gov";  // NTP server

const int NTP_PACKET_SIZE = 48;       // NTP timestamp is in the first 48 bytes of the message

byte packetBuffer[NTP_PACKET_SIZE];   // buffer to hold incoming and outgoing packets

// A UDP instance to let us send and receive packets over UDP
AsyncUDP Udp;

// send an NTP request to the time server at the given address
void createNTPpacket(void)
{
  Serial.println("============= createNTPpacket =============");

  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)

  packetBuffer[0]   = 0b11100011;   // LI, Version, Mode
  packetBuffer[1]   = 0;     // Stratum, or type of clock
  packetBuffer[2]   = 6;     // Polling Interval
  packetBuffer[3]   = 0xEC;  // Peer Clock Precision
  
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;
}

void parsePacket(AsyncUDPPacket packet)
{
  struct tm  ts;
  char       buf[80];
  
  memcpy(packetBuffer, packet.data(), sizeof(packetBuffer));

  Serial.print("Received UDP Packet Type: ");
  Serial.println(packet.isBroadcast() ? "Broadcast" : packet.isMulticast() ? "Multicast" : "Unicast");
  Serial.print("From: ");
  Serial.print(packet.remoteIP());
  Serial.print(":");
  Serial.print(packet.remotePort());
  Serial.print(", To: ");
  Serial.print(packet.localIP());
  Serial.print(":");
  Serial.print(packet.localPort());
  Serial.print(", Length: ");
  Serial.print(packet.length());
  Serial.println();

  unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
  unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);

  // combine the four bytes (two words) into a long integer
  // this is NTP time (seconds since Jan 1 1900):
  unsigned long secsSince1900 = highWord << 16 | lowWord;
  
  Serial.print(F("Seconds since Jan 1 1900 = "));
  Serial.println(secsSince1900);

  // now convert NTP time into )everyday time:
  Serial.print(F("Epoch/Unix time = "));
  
  // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
  const unsigned long seventyYears = 2208988800UL;
  
  // subtract seventy years:
  unsigned long epoch = secsSince1900 - seventyYears;
  time_t epoch_t = epoch;   //secsSince1900 - seventyYears;
 
  // print Unix time:
  Serial.println(epoch);

  // print the hour, minute and second:
  Serial.print(F("The UTC/GMT time is "));       // UTC is the time at Greenwich Meridian (GMT)

  ts = *localtime(&epoch_t);
  strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts);
  Serial.println(buf);
}

void sendNTPPacket(void)
{
  createNTPpacket();
  //Send unicast
  Udp.write(packetBuffer, sizeof(packetBuffer));
}

void setup()
{
  Serial.begin(115200);
  while (!Serial);

  Serial.println("\nStart AsyncUdpNTPClient on " + String(BOARD_NAME));

  // start the ethernet connection and the server
  // Use random mac
  uint16_t index = millis() % NUMBER_OF_MAC;

  // Use Static IP
  //Ethernet.begin(mac[index], ip);
  // Use DHCP dynamic IP and random mac
  Ethernet.begin(mac[index]);

  // you're connected now, so print out the data
  Serial.print(F("You're connected to the network, IP = "));
  Serial.println(Ethernet.localIP());

  //NTP requests are to port NTP_REQUEST_PORT = 123
  if (Udp.connect(timeWindowsCom, NTP_REQUEST_PORT))
  {
    Serial.println("UDP connected");

    Udp.onPacket([](AsyncUDPPacket packet)
    {
      parsePacket(packet);
    });
  }
}

void loop()
{
  sendNTPPacket();

  // wait 60 seconds before asking for the time again
  delay(60000);
}

Debug Termimal Output Samples

1. This is terminal debug output when running AsyncUdpNTPClient example on STM32F7 Nucleo-144 NUCLEO_F767ZI. It connects to NTP Server time.windows.com (IP=13.86.101.172) using AsyncUDP_STM32 library, and requests NTP time every 60s. The packet is then received and processed asynchronously to print current UTC/GMT time.

Code: Select all

Start AsyncUdpNTPClient on NUCLEO_F767ZI
You're connected to the network, IP = 192.168.2.187
UDP connected
============= createNTPpacket =============
[UDP] _recv: Call packetHandler with packet from remoteIP = 13.86.101.172 , remotePort = 123
[UDP] To destIP = 192.168.2.187 , destPort = 62510
[UDP] Packet len = 48
Received UDP Packet Type: Unicast
From: 13.86.101.172:123, To: 192.168.2.187:62510, Length: 48
Seconds since Jan 1 1900 = 3808150993
Epoch/Unix time = 1599162193
The UTC/GMT time is Thu 2020-09-03 19:43:13 GMT
...
============= createNTPpacket =============
[UDP] _recv: Call packetHandler with packet from remoteIP = 13.86.101.172 , remotePort = 123
[UDP] To destIP = 192.168.2.187 , destPort = 62510
[UDP] Packet len = 48
Received UDP Packet Type: Unicast
From: 13.86.101.172:123, To: 192.168.2.187:62510, Length: 48
Seconds since Jan 1 1900 = 3808151290
Epoch/Unix time = 1599162490
The UTC/GMT time is Thu 2020-09-03 19:48:10 GMT
============= createNTPpacket =============
[UDP] _recv: Call packetHandler with packet from remoteIP = 13.86.101.172 , remotePort = 123
[UDP] To destIP = 192.168.2.187 , destPort = 62510
[UDP] Packet len = 48
Received UDP Packet Type: Unicast
From: 13.86.101.172:123, To: 192.168.2.187:62510, Length: 48
Seconds since Jan 1 1900 = 3808151349
Epoch/Unix time = 1599162549
The UTC/GMT time is Thu 2020-09-03 19:49:09 GMT
Post Reply

Return to “Libraries & Hardware”