arduino / ArduinoCore-mbed

330 stars 195 forks source link

UPD Multicast does not work on Portenta H7 -- mbed v3.5.4 #629

Open ancabilloni opened 1 year ago

ancabilloni commented 1 year ago

Hello,

I am using Portenta H7 + vision shield, and I set up the codes to receive UDP multicast data. The codes compiled but I'm not receiving any data. Can someone help to clarify if Udp multicast is possible on Portenta H7 and vision shield? Or if I am missing something in the codes?

Arduino IDE version 1.8.19 Arduino Mbed OS Portenta Boards, version 3.5.4

Below is my codes on the Arduino as UDP Multicast Receiver, static ip: 195.0.0.92

#include <PortentaEthernet.h>
#include <Ethernet.h>
#include <EthernetUdp.h>

#ifndef UDP_TX_PACKET_MAX_SIZE
#define UDP_TX_PACKET_MAX_SIZE 24
#endif

EthernetUDP Udp;
IPAddress ip(195,0,0,92);
unsigned int localPort = 1234;
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];
char replyBuffer[] = "acknowledged";

void setup() {
  Serial.begin(9600);
  while (!Serial) {};

  Ethernet.begin(ip);

  if (Udp.beginMulticast(IPAddress(239,1,2,3), 1234)) {
    Serial.println("Connected multicast");
  }
  Serial.begin(9600);
}

void loop() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    Serial.println("Contents:");
    Serial.println(packetBuffer);

    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(replyBuffer);
    Udp.endPacket();
  }
  delay(10);
}

On the UDP Multicast Sender, here is my code in Python running from my laptop, static ip 195.0.0.91

import socket
import struct
import sys

message = 'very important data'
multicast_group = ('239.1.2.3', 1234)

# Create the datagram socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# Set a timeout so the socket does not block indefinitely when trying
# to receive data.
sock.settimeout(0.2)

# Set the time-to-live for messages to 1 so they do not go past the
# local network segment.
ttl = struct.pack('b', 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)

try:

    # Send data to the multicast group
    print >>sys.stderr, 'sending "%s"' % message
    sent = sock.sendto(message, multicast_group)

    # Look for responses from all recipients
    while True:
        print >>sys.stderr, 'waiting to receive'
        try:
            data, server = sock.recvfrom(16)
        except socket.timeout:
            print >>sys.stderr, 'timed out, no more responses'
            break
        else:
            print >>sys.stderr, 'received "%s" from %s' % (data, server)

finally:
    print >>sys.stderr, 'closing socket'
    sock.close()

To further clarify, I could ping Portenta (195.0.0.92) from my laptop (195.0.0.91) after upload the codes to Portenta. I also verified the multicast sender working by reading multicast data from a 2nd laptop with the below Python codes:

import socket
import struct

UDP_PORT = 1234
MYGROUP_4 = '239.1.2.3'
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

mreq = struct.pack("4sl", socket.inet_aton(MYGROUP_4), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
sock.settimeout(5.0)
sock.bind((MYGROUP_4, UDP_PORT))

while True:
    try:
        data, addr = sock.recvfrom(1024)
        print(addr, data)
    except socket.timeout:
        print("timeout")
marcocipriani01 commented 11 months ago

Hello, I can confirm that Arduino Portenta doesn't receive UDP multicast packets. Please fix this as soon as possible, as I need to buy a total of 10 Portenta Machine Control boards and I need them to work reliably. I'm currently testing on a Portenta Breakout board. I tested sending UDP multicast packets from a small C program, and I can always receive them from another C program and an Android app on my phone without issues. I can even send multicast packets from the Portenta, and receive them on both the PC and the phone. Receiving them on the Portenta is, however, a no-go. My Arduino and C code is pretty much equivalent to the code posted by @ancabilloni. I can share it if necessary. Regards, Marco Cipriani

facchinm commented 11 months ago

Hi Marco, the issue is due to https://github.com/ARMmbed/mbed-os/issues/13233 , so STM32 emac does not implement multicast... To enable the multicast functionality you can call

#include "stm32xx_emac.h"
void set_all_multicast(bool all)
{
  STM32_EMAC &emac = STM32_EMAC::get_instance();
  ETH_MACFilterConfigTypeDef pFilterConfig;
  if (HAL_ETH_GetMACFilterConfig(&emac.EthHandle, &pFilterConfig) != HAL_OK) {
    return;
  }
  pFilterConfig.PassAllMulticast = all ? ENABLE : DISABLE;
  HAL_ETH_SetMACFilterConfig(&emac.EthHandle, &pFilterConfig);
}

after Ethernet.begin() .

@manchoz can we test this extensively and properly patch mbed-os before the next release?

manchoz commented 11 months ago

@facchinm Yes, sure. @ancabilloni @marcocipriani01 I'll update the issue as soon as I complete the tests.

marcocipriani01 commented 11 months ago

Thank you very much, the code worked first try!