[Solved/Workaround] Spark Core can't send UDP broadcast packets without cloud connection

I’m attempting to send an SSDP packet to a Sony Camera on the same wireless network. I can’t seem to get any UDP packets sent using my current code, wireshark appears to show no packets from the device at all

I read a couple threads about UDP issues, and have added a sizeable delay, and added a check to begin UDP only once connected to the network. But something is still wrong. Is it a bug or am I making a mistake somewhere?

I get an IP address, so I know it’s going into the loop and that it’s connected.
Thanks for any insight you can providw.

1 Like

It seems each time loop runs, you are sending packet again (isn’t local IP being print each second or so?). And after sending, you read 1 character from possible response, then you are sending whole message again. I would move the code up to delay() into the if(… (once ==0)) block. So message gets sent once and each loop() after it, response is checked and one character is read. Not sure delay is needed (I do not have any in my code).

I would read all data at once after parse packet (not sure Udp.parsePacket() would not destroy previously parsed data). Something like:

if (Udp.parsePacket() > 0) {
    while (Udp.available()) {
        char c = Udp.read();
        Serial.println(c);
    }
}

Personally I read whole data into a buffer using:

#define MAX_SIZE 1024
char buffer[MAX_SIZE];
Udp.read(buffer, MAX_SIZE);

Also I am not sure whether assigning new string into const char *message would work. And not sure what localPort should be, I set it to same value as remote port, just in case. Didn’t try network analyzer yet, but packets come and go happily.

Glancing at your code: Is this your intended sendto address? IPAddress ip( 239, 255, 255, 250 ); That ought not to be an address on your LAN if it starts 239. Firewall problem: Can you ping that WAN address from another host, elsewhere on your LAN? Is the port blocked?

1 Like

@psb777 239.255.255.250 is the standard SSDP(Simple Service Discovery Protocol) multicast IP address. Any device that uses the protocol from smart fridges to sony camera to roku, listen on that up. Hell, even my router appears to do so. I can see other packets from other devices sent to that IP, so I don’t thnk that’s it.

@laml All good points. I hadn’t gotten around to modifying the receive code form the example, as I can’t get the packets out. And I have edited the code by your recommendation. I’m not so sure about the const char, but directly placing the message in the send request doesn’t appear to help either.

After 5 or so cycles, the code slows down to a crawl, with one request every 5 seconds or so, even with no delay. I wouldn’t really care, but I still can’t see any packets successfully transmitted and the standard response to the packet is not sent by the local devices. Anyone else have any ideas?

Updated test code:

Are you watching the output with wireshark ?

I’m not in front of a spark right now, but I’d have to hazard a guess that the CC3000 might not be handling the multicast correctly, and might actually be trying to ARP for that address (which obviously will never get an answer) - if you can wireshark it, you might see the arp request get issued.

[disclaimer: all conjecture - as I said I’m not in a position to validate right now…]

This usually means you are out of sockets (7 on the TI chip) or out of packet buffers and you waiting for something to timeout.

With an ip.dst and ip.src filter on wireshark, I don’t see anything at all coming from the IP address of the Spark Core. I’m not sure if there’s a better way to see what’s going on.

If I tell it to ping the router(instead of multicast) with the same message load, it flies through the code, generating responses left and right.

@bko That’s probably true, but I almost suspect a different cause. Sending to a regular IP runs at high speed for at least 30 seconds, while sending multicast acts as I described

I thought I remembered reading that @AndyW got multicast to work sometime. I really need SSDP(and thus multicast), and am wondering if I need to get a better dev board, go bare metal with the CC3000, or just admit defeat.

Hmm. Since it’s always connecting to the same network with no other devices, if the camera’s IP doesn’t change might just be able to hardcode it, and hope the Spark can send HTTP POST requests to a regular IP.

Has anyone reported success with multicast?

The firmware does generate multicast packets every time it starts up, in a half-hearted attempt at playing nicely with other bonjour children, I suspect - so multicast is certainly possible. However, there are all kinds of subtleties like 224.x.x.x vs 239.x.x.x that can come into play with multicast. The devil is truly in the details.

I will not have a chance to test anything for about 10 days, so someone else will need to lead the way with testing and validation.

Some folks appear to have had trouble UDP broadcast on 255.255.255.255 but had success on 168.0.1.255 type addresses. I don't know why this would be--the core software does not appear to look at IP addresses at all before passing them to the TI part.

The Spark software itself does a multicast UDP announcement to 224.0.1.187 on port 5683 and I know for sure that it works since I had some code looking for these "I'm awake!" messages at one time. I see @AndyW mentions these above as I am typing this!

1 Like

I don’t really have any flexibiliy in the implementation. I have to send the multicast packet to 239.255.255.250:1900, if I want to interface with the Sony camera API.

I’ll have to run a few more tests, but it appears that the camera itself reserves an IP and a port, which doesn’t vary. But it’s definitely a hack

I found this link to someone who appears to have successfully setup SSDP on the CC3000.
http://forum.soldersplash.co.uk/viewtopic.php?f=15&t=90
which appears to draw from this example from the WiFi DipCortex. I’ll have to take a closer look at the code, but assuming I can get bare metal access to the CC000, it looks like it should work.
http://developer.mbed.org/users/SolderSplashLabs/code/WiFiDip-KitchenSink/

I can’t say I have a lot of experience with the Spark Core’s UDP library. I’ll take a look, but perhaps some should compare the two libraries and see what the WiFi Dipcortex people are doing differently

1 Like

I just wanted to add that you should be sure you are looking for packets with wireshark when the core powers up, since the usually syndrome is that the core sends 5-6 packets and then goes into the ~5 second timeout.

UDP broadcast on 255.255.255.255 works like a charm for me.

@benwis Tweaked your code a bit and it works like a charm, I can even see it on Wireshark. Two significant changes I did:

  1. kept core autoconnecting to cloud
  2. Disabled WiFi AP configuration

So it connects to my predefined (and single) WiFi at home. It waits for serial console, so send it an Enter and it starts. The code is below:

It sends query packet once and then it listens forever. I was surprised how many devices talk on the network. Hope it helps :smile:

2 Likes

@laml It definitely helps. The packet definitely sends correctly, and that’s a good step forward… I guess I’ll have to see if it only works when the cloud is autoconnected. Maybe a call to spark.disconnect(); immediately will allow successful code execution while still functioning.

Strange that it doesn’t seem to work in manual mode.

Does anyone know what would cause the manual mode to not work? It connects to the WiFi the same, is it something to do with not enough spark.process(); calls? I would think since the UDP code is local, that would be the problem, unless automatic mode does more than I know about. Maybe some garbage collection or initialization routine.

EDIT: I’ve added as many process calls as I can think to, here’s the sample code:


Connects to the wifi successfully, checks for legitimate IP, and uses same packet sending code as the example above, except no indication of a packet actually being sent. Added a lot of Spark.process() calls.

Anyone know of a different way to leave it in automatic, but make it skip the cloud connection?

1 Like

Hi @benwis

I was helping another user with UDP broadcast issues and tried to just modify his short program to broadcast on 239.255.255.250:1900 with the cloud on. It works fine in the sense that I see the packets on wireshark. Since I don’t have the protocol payload correct, it comes over as a non SSDP packet but filtering on UDP I see it correctly.

I would put your wireshark filter to “udp” and look for your core’s source address.

What did not work was trying to use tcpdump or nc to look at those packets presumably since my host OS is already listening on that port.

Here’s the code–I am using a serial LCD on Serial1 to look at debug messages.

[Minor edit–forgot to change port–works on 1900 as well.]


UDP udp;

IPAddress remoteIP(239,255,255,250);
int remotePort = 1900;
int count = 0;

unsigned char TxMsg[5] = { 'H', 'E', 'L', 'L', 'O'};

void setup() {
    udp.begin(5000);
    Serial1.begin(9600);
}

void loop() {
    Serial1.print("Run ");
    Serial1.print(count++);
    udp.beginPacket(remoteIP,remotePort);
    udp.write(TxMsg,5);
    udp.endPacket();
    delay(1000);
}

@bko So I’ve run both yours and @laml example programs, and both work fine. So we know it’s capable of sending multicast packets.

What I haven’t been able to achieve is sending multicast UDP packets while the cloud is disabled, as in SYSTEM_MODE(MANUAL);
I won’t have an internet connection on the network 1000m up.

I don’t know much about the firmware itself, but I suspect one of these things to be occuring.

  1. Some weird connection between cloud code and multicast
  2. Some garbage collection or process call that’s disabled in MANUAL mode
  3. Something weird with the Spark.process call.

I’ve tried testing 3 by adding tons of the calls as in the above post. I’ve also sent the same packet to the router on the network in manual mode, and received responses. So that just leaves 1.

Something in the UDP library specifically relating to multicast only works when Automatic mode is enabled. I think it’s a bug

Here’s my latest code. Change the IP address to your router’s IP address, put in some credentials, and you’re off to the races. Packets sent and received. Comment that IP address line, uncomment the one above for SSDP. Zilch.
Load @laml’s example above, with the same code with cloud enabled. Packets in and out.

Can anyone shed some light on why that would be so?

SYSTEM_MODE(MANUAL);
// UDP Port used for two way communication
unsigned int localPort = 1900;
#define MAX_SIZE 1024
char buffer[MAX_SIZE];

unsigned int once = 0;

unsigned int ssdpport = 1900;
//This is the multicast broadcast IP
// IPAddress ip( 239, 255, 255, 250 );

//This is my router's ip address
IPAddress ip( 192, 168, 8, 1 );
// An UDP instance to let us send and receive packets over UDP
UDP Udp;

void setup() {
    Spark.disconnect();
    Serial.begin(9600);
    WiFi.on();
    // Connects to a network with a specified authentication procedure.
    // Options are WPA2, WPA, or WEP.
    WiFi.clearCredentials();
    WiFi.setCredentials("deathstarplans", "notinthemaincomputer", WPA);
    WiFi.connect();
    // while(!Serial.available()) Spark.process();

    while (!WiFi.ready()) {
        Serial.println("Waiting for WiFi...");
        Spark.process();
        delay(1000);
    }
}

void loop() {
    Spark.process();
    if ((!once) && (WiFi.ready() == true)) {
       IPAddress addr = WiFi.localIP();

      if ((addr[0] != 0 ||addr[1] != 0 || addr[2] != 0 || addr[3] != 0) && (once == 0)) {
     Serial.println("UDP has begun");
        once = 1;
        Udp.begin(localPort);
        Spark.process();
        Serial.println(WiFi.localIP());
         //Sends SSDP Packet to multicast address
        Udp.beginPacket(ip, ssdpport);
        Spark.process();
        Udp.write("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: \"ssdp:discover\"\r\nMX: 5\r\nST: ssdp:all\r\n\r\n");
        Spark.process();
        Udp.endPacket();
        Spark.process();
       }
      

       
    }
    //Module to parse received SSDP packet
    Spark.process();
    int rcvd = Udp.parsePacket();
    if (rcvd > 0) {
        Serial.print("Received UPD packet, length: ");
        Serial.println(rcvd);
        Serial.println(buffer);
        // Read first char of data received
        Udp.read(buffer, MAX_SIZE);
            Spark.process();
        if (rcvd > MAX_SIZE) {
            Serial.println("Too large packet");
            while (Udp.available())
                Udp.read();
                  Spark.process();
        }
    }
}
1 Like

Me too: UDP broadcasts and SYSTEM_MODE(MANUAL) - #2 by psb777 - Troubleshooting - Particle - but a very awkward workaround is that if you initially connect and then disconnect to the cloud then UDP broadcasts do work. It is reported that if you UDP broadcast to the network specific broadcast address e.g. 192.168.1.255 instead of 255.255.255.255 then this works without ever having a cloud connection - but I haven't tried that myself yet.

@psb77 have you created an issue on the Spark firmware github? If not, I’ll make one tomorrow. I’ll also try the network specific broadcast IP later. It’s really bothering me that this is a thing

I can’t connect to the Cloud, as the interface will be started up in remote locations without internet. I hope a solution is found soon.

EDIT: Created issue on firmware github

1 Like

I have been playing with this tonight and the only way I can make broadcast UDP work in cloud off mode is by using a subnet broadcast address. Neither 255.255.255.255 nor 239.255.255.250 worked but constructing the address like this did:

IPAddress myIP;
IPAddress remoteIP;
  ...
myIP = WiFi.localIP();
remoteIP = {myIP[0],myIP[1],myIP[2],255};

There is nothing in the user wiring code or the driver that looks for multicast addresses, so my feeling is that something in the TI CC3000 setup must be different.

And the thing that must be different must be done by the code run on the Spark when you call Spark.connect(). But the TI chip knows nothing about the Cloud. So maybe UDP broadcasts don’t work until some TCP connection is established?

This turns out to be correct--adding this to my test program makes it work with 255.255.255.255 broadcasts with the cloud off.

        if (once == true) {
            //Make TCP request
            const char server[] = "www.google.com";
            client.connect(server,80);
            delay(1000);
            client.stop();
            //Start UDP
            udp.begin(listenPort);
            once = false;
...

This is a much better work-around for the problem, but I will keep digging.

3 Likes