Connecting multiple microcontollers with with UDPSockets

Has anyone seen an example of multiple microcontrollers talking to each other using sockets compatible with Mbed 6? I have two Nucleo F767ZI connected to my router with ethernet cords currently with the data just going one way using the 6.13.0 library and am in mbed studio. I assume my mistake in is connecting with the right port or misuse of SocketAddress.

The code on the transmitting controller is

#include “mbed.h”

#include “EthernetInterface.h”

DigitalOut led1(LED1);

DigitalOut led2(LED2);

// Static IP network variables

static const char* mbedIP = “192.168.1.45”; //IP

static const char* mbedMask = “255.255.255.0”; // Mask

static const char* mbedGateway = “192.168.1.254”; //Gateway

static const char* recvIP = “192.168.1.38”;

const int PORT = 4466; //Port used for UDP communication

EthernetInterface eth; //Ethernet interface

int main()

{

eth.set_network(mbedIP, mbedMask, mbedGateway);

printf("UDP Socket example\n");

SocketAddress sockAddr(recvIP, NSAPI_IPv4, PORT);

if (eth.connect() != 0) {

    printf("Unable to connect to the Ethernet.\r\n");

    return -1;

}



eth.get_ip_address(&sockAddr);

printf("IP address is: %s\n", sockAddr.get_ip_address() ? sockAddr.get_ip_address() : "No IP");



UDPSocket td_sock;

td_sock.open(&eth);

const char  out_buffer[] = "very important data";



while (true) {

    int code = td_sock.sendto(sockAddr, out_buffer, sizeof(out_buffer));

    //int code = td_sock.send(out_buffer, sizeof(out_buffer));

    printf("%d \r\n", code);

    led2 = !led2;                      

    ThisThread::sleep_for(2000ms);             

}

}

the serial monitor then reads
UDPSocket example
192.168.1.45
20
20
20

On the receiving microcontroller it has

/*

  • Copyright (c) 2006-2020 Arm Limited and affiliates.

  • SPDX-License-Identifier: Apache-2.0

*/

#include “mbed.h”

#include “EthernetInterface.h”

DigitalOut led1(LED1);

DigitalOut led2(LED2);

// Static IP network variables

static const char* mbedIP = “192.168.1.45”; //IP

static const char* mbedMask = “255.255.255.0”; // Mask

static const char* mbedGateway = “192.168.1.254”; //Gateway

static const char* recvIP = “192.168.1.38”;

const int PORT = 4466; //Port used for UDP communication

EthernetInterface eth; //Ethernet interface

int main()

{

int code;

eth.set_network(recvIP, mbedMask, mbedGateway);

printf("UDP Socket example\n");

SocketAddress sockAddr(mbedIP, NSAPI_IPv4, PORT);

if (eth.connect() != 0) {

    printf("Unable to connect to the Ethernet.\r\n");

    return -1;

}

eth.get_ip_address(&sockAddr);

printf("IP address is: %s\n", sockAddr.get_ip_address() ? sockAddr.get_ip_address() : "No IP");

UDPSocket td_sock;

td_sock.open(&eth);

code = td_sock.getpeername(&sockAddr);

td_sock.set_timeout(3000);

printf("%d\r\n",code);

while (true) { 

    char in_buff[20];

    //code = td_sock.recvfrom(&sockAddr, in_buff, sizeof(in_buff));

    code = td_sock.recv(&in_buff, sizeof(in_buff));

    printf("%d\r\n",code);

    led2 = !led2;

    //ThisThread::sleep_for(500ms);

}

}

This prints UDP socket example
-3004
-3001
-3001
-3001

I have tried with and without the nsapi version. I have also tried without the timeout and it sticks forever. I assume the in_buff size doesn’t matter but I have tried making it 50 and 254 as well.
I have also checked the buffer with
printf("%u, %u, %u,\r\n",in_buff[0],in_buff[1], in_buff[2]);
and they all remain 0

Hello,

  • I am not sure, but from my point of view you need 2 ports, one for each direction, usually marked as Local and Remote port. I always used it like that
  • a ​description for erros you can found here
  • take care about your router will accept your network settings, especially static IP address
  • also there is some differention between methods of Socket API. There are methods recv(...) / send(...) where also connect(...) method of the socket is neceasary and also sendto(...) / recvfrom(...) where it is not -UDPSocket - API references and tutorials | Mbed OS 6 Documentation
    So basically, we can say your second program, the receiver, need to be connected to somewhere ​or need to change to recvfrom(…) method with already specified address.

I usually use some PC app (YAT or also in Window Store are some apps) and first I establish connection between my PC with both sides of connected boards and then later directly between boards.

BR, Jan

1 Like

I tried opening a UDP socket server terminal in YAT and changed the recvIP to the one of my PC and did not see any messages on the terminal from the sending NUCLEO. I did this with the receiving NUCLEO unplugged. I then changed sendto(…) to send(…) which then prints “-3006, /*!< IP address is not known */”.

I also tried opening a client terminal in YAT with only the receiving NUCLEO plugged in and sending the text from YAT “hello”. The receiving NUCLEO continues to print “-3001, /*!< no data is not available but call is non-blocking */” and the YAT terminal prints "hello[Warning: An existing connection was forcibly closed by the remote host].

When I go back to the addresses set for the two NUCLEOs to talk to each other and scan the network from my computer I see the .38 and .45 addresses.

Also when I use the example code UDPSocket - API references and tutorials | Mbed OS 6 Documentation it does work and prints the time.

I based this code off of this example UDP static IP example | Mbed but made changes to move to OS6

Ok, I had more time for some physical test of your code, now.

  • be sure you have same range of IP address
  • for receiver you also need to call method bind(PORT) before while loop for correct receiving of any message
  • in sender code (you have it in both side of connection code but in sender it is important) you did some mistakes. Check your sockAddr variable. You declared it as SocketAddress sockAddr(recvIP, NSAPI_IPv4, PORT); but later you will override it with eth.get_ip_address(&sockAddr);that cause you send all messages to your local IP (IP of sender) = nowhere.
Sender main- click for show
int main()
{

    eth.set_network(mbedIP, mbedMask, mbedGateway);
    printf("UDP Socket example\n");
    //SocketAddress sockAddr(recvIP, NSAPI_IPv4, PORT); // wrong
    SocketAddress sockAddr;
    SocketAddress remoteSockAddr(recvIP, PORT);
    if (eth.connect() != 0) {
        printf("Unable to connect to the Ethernet.\r\n");
        return -1;
    }

    eth.get_ip_address(&sockAddr);
    printf("IP address is: %s\n", sockAddr.get_ip_address() ? sockAddr.get_ip_address() : "No IP");

    UDPSocket td_sock;
    td_sock.open(&eth);
    const char  out_buffer[] = "very important data";

    while (true) {
        int code = td_sock.sendto(remoteSockAddr, out_buffer, sizeof(out_buffer));
        //int code = td_sock.send(out_buffer, sizeof(out_buffer));
        printf("%d \r\n", code);
        led2 = !led2;                      
        ThisThread::sleep_for(2000ms);             
    }
}

BR, Jan

Thank you so much! That worked. I am also receiving the message on the other NUCLEO with

#include “mbed.h”

#include “EthernetInterface.h”

DigitalOut led1(LED1);

DigitalOut led2(LED2);

// Static IP network variables

//static const char* mbedIP = “192.168.1.45”; //IP

static const char* mbedIP = “192.168.1.212”; //IP

static const char* mbedMask = “255.255.255.0”; // Mask

static const char* mbedGateway = “192.168.1.254”; //Gateway

static const char* recvIP = “192.168.1.38”;

const int PORT = 80; //Port used for UDP communication

EthernetInterface eth; //Ethernet interface

int main()

{

int code;

eth.set_network(recvIP, mbedMask, mbedGateway);

printf("UDP Socket example\n");

//SocketAddress sockAddr(recvIP, NSAPI_IPv4, PORT); // wrong

SocketAddress sockAddr;

SocketAddress remoteSockAddr(mbedIP, PORT);

if (eth.connect() != 0) {

    printf("Unable to connect to the Ethernet.\r\n");

    return -1;

}

eth.get_ip_address(&sockAddr);

printf("IP address is: %s\n", sockAddr.get_ip_address() ? sockAddr.get_ip_address() : "No IP");

UDPSocket td_sock;

td_sock.open(&eth);

code = td_sock.bind(PORT);

printf("%d\r\n",code);

//code = td_sock.getpeername(&sockAddr);

td_sock.set_timeout(3000);



while (true) { 

    char in_buff[25];

    code = td_sock.recvfrom(&remoteSockAddr, &in_buff, sizeof(in_buff));

    //code = td_sock.recv(&in_buff, sizeof(in_buff));

    printf("%d\r\n",code);

    printf("%u, %u, %u,\r\n",in_buff[0],in_buff[1], in_buff[2]);

    led2 = !led2;

    //ThisThread::sleep_for(500ms);

}

}

I was glad to help, good luck with it.

BR, Jan