Photon not receiving Multicast UDP packages

I have new photons and they send multicast UDP messages just fine - however, receiving Multicast UDP does not seem to work (it is not an issue of my router, becasue PC’s and RaspberryPI’s all receive the Mulitcast messages - IP =239.200.201.250 and I also can see the messages in wireshark on a PC).

When I look at my particle UDP instance “Udp”, I miss a method/function to join a multicast group like Udp.joinMulticastGroup(IPaddress).

Should multicast UDP work in principle with the Photon?

thx, michael.

This will be fixed in the next release: https://github.com/spark/firmware/issues/468

1 Like

Thanks, Kenneth - I followed your link and just updated the photon with firmware rev 0.4.3-rc2.

Receiving UDP messages works fine now - if I send them to the IP of the photon. However, I have no idea how to receive MULTICAST UDP messages, addressed to a multicast group ip address like “239.200.201.250”.

(Udp.parsePacket() > 0) is never true when this type of message “hits” the photon.

Can I make the photon listen to Multicast messages?

thx,
Michael.

Hi @Michael2,

I also looked for that and as far as I can see, multicast reception is not possible, unless you find something in the lower layers. I would also be extremely interested in that. Automatically discovering the other photons would just be great…

Hi Steve,

I think in principle it should be possible. Broadcom advertises the BCM43362 chip with “WICED SDK includes: … mDNS (Bonjour) device discovery” for which you need to receive multicast UDP messages. (And in the firmware in the /hal/photon section there is at least a definition for IP_ADD_MEMBERSHIP and a setsockopt() function - however, no setsockopt function in “photon/socket_hal.cpp”)

I would be really nice is this functionality could be implemented some time.

Yes, that’s also what I figured. I did not find my way around the deeper layers to be able to enable it. I will leave that to the Particle team :-).

1 Like

Hi @michael2 ,

I finally had some time to play around with receiving multicasted packets. It is in fact supported and was pretty easy to implement as an extension to the API. I would propose to simply add it to a newer firmware release. @kennethlimcp, do you know whom to contact to discuss that?

Thanks,

Stevie

Happy to discuss this! :smile:

Great @mdma should have guessed it is you. I found the following function:

wiced_result_t wiced_multicast_join(
    wiced_interface_t interface, const wiced_ip_address_t* address);

(There is also the corresponding leave function, which will ignore for the discussion).

This will subscribe to a multicast address on the IGMP level. It seems that all UDP sockets will then receive multicast packets sent to their respective ports.

What I did is to add a

int socket_join_multicast(const sockaddr_t *addr);

function to socket_hal. This is then used in

int udp_join_multicast(IPAddress ip);

in spark_wiring_udp. So far so trivial. I am unsure if that is the right location (it is, I think) and if it should be a static function of the UDP class or a free function.

Here is a simple test program which you can put on as many Photons as you like and they will all start flashing the blue LED. The more Photons, the faster they will flash :-).

#include "application.h"

static UDP g_udp;
static int g_last = 0;

void setup()
{
    pinMode(7, OUTPUT);
    Serial.begin(115200);

    g_udp.begin(10000);

    IPAddress address(224, 1, 2, 3);
    int result = udp_join_multicast(address);
    Serial.println(result);
}

void loop()
{
    if (g_udp.parsePacket() > 0)
    {
        // Read first char of data received
        unsigned char v = g_udp.read();
        Serial.print("Received packet ");
        Serial.println(v);
        g_udp.flush();
        digitalWrite(7, true);
        delay(30);
        digitalWrite(7, false);
    }

    int now = millis();
    if (now - g_last < 1000)
        return;
    g_last = now;

    Serial.println("Sending packet");
    unsigned char v = 42;

    IPAddress ipAddress(224, 1, 2, 3);
    g_udp.beginPacket(ipAddress, 10000);
    g_udp.write(&v, 1);
    g_udp.endPacket();
}

We should of course add the leave function as well. What do you think?

socket_multicast is probably not that interesting, in practical terms multicast is limited to UDP.

@AndyW, sorry not sure, what you mean there. Yes multicasting is a UDP only feature, it does not exist with TCP.

I think it is pretty interesting. I have used it to program a system where all Photons in a LAN will discover each other and start synchronizing without any prior configuration. A little test I have done allows you to start whatever number of photons and they will all blink in unison. You can add new Photons at any time, or remove others at any time, they will still continue blinking at the same time. This kind of stuff is very interesting for swarms of robots, security systems and more.

1 Like

So from an implementation standpoint, we should only implement for UDP-based classes, not for TCPClient/TCPServer classes.

Ah, okay, that’s what you mean. Yes, agreed. I could imagine making the join_multicast a static member of the UDP class. Or a free function like I did above and name it udp_join_multicast

2 Likes

Sounds great.

I wonder for the Wiring api, we can wrap it up as

UDP::joinMulticast(IPAddress);
UDP::leaveMulticast(IPAddress);
2 Likes

Yes, sounds good for me. Those would be static, because they apply to all UDP sockets.

If you like, I can make a pull request tomorrow.

1 Like

That would be most awesome! :smile: :+1: