stm32duino / STM32Ethernet

Arduino library to support Ethernet for STM32 based board
151 stars 41 forks source link

Added multicast udp, added callback for interrupt data arrival #7

Closed straccio closed 4 years ago

straccio commented 6 years ago

Implemented begin multicast for receiving multicast udp. Added ability to add a callback from the interrupt when udp receive data. (Usefull with FreeRTOS.

void EthernetUDP::onDataArrival( std::function<void()> onDataArrival_fn){
  _udp.onDataArrival = onDataArrival_fn;
}

Prereq: https://github.com/stm32duino/Arduino_Core_STM32/pull/198

fpistm commented 6 years ago

Thanks @straccio Have you an example to test this?

straccio commented 6 years ago

The example here, i don't have the board with me, in order to try this code. In the example i have used FreeRTOS.

/*
 FreeRTOS DHCP Chat UDP
 */

#include <LwIP.h>
#include <STM32Ethernet.h>
#include <STM32FreeRTOS.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network.
// gateway and subnet are optional:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 177);
IPAddress myDns(192,168,1, 1);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 0, 0);

IPAddress multicast_address(224,0,1,186);
uint16_t multicast_port = 5684;
uint16_t port = 5683;

// telnet defaults to port 23
EthernetUDP receiver;
EthernetUDP transmitter;
SemaphoreHandle_t recv_sem;

void recv_multicast_message(){
  xSemaphoreGiveFromISR(recv_sem,NULL);
}

static void vReceiverTask(void *pvParameters){
  size_t packetlen;
  char * buffer;
  buffer = (char *) malloc(80);
  for(;;){
    //waiting for inccoming message or 2 ms 
    xSemaphoreTake(recv_sem,2);
    if(packetlen = receiver.parsePacket()>0){
      if(receiver.read(buffer,packetlen)==packetlen){
        IPAddress remote = receiver.remoteIP();
        for (int i = 0; i < 4; i++) {
          Serial.print(remote[i], DEC);
          if (i < 3) {
            Serial.print(".");
          }
        }
        Serial.print(": ");
        Serial.println(buffer);
      }
    }
  }
}

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  // this check is only needed on the Leonardo:
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // start the Ethernet connection:
  Serial.println("Trying to get an IP address using DHCP");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // initialize the Ethernet device not using DHCP:
    Ethernet.begin(mac, ip, myDns, gateway, subnet);
  }
  // print your local IP address:
  Serial.print("My IP address: ");
  ip = Ethernet.localIP();
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(ip[thisByte], DEC);
    Serial.print(".");
  }
  Serial.println();
  recv_sem = xSemaphoreCreateBinary();

  // start listening for clients on multicast address
  if(receiver.beginMulticast(multicast_address,multicast_port)==1){
    receiver.onDataArrival(recv_multicast_message);
  }

  // start listening for clients on unicast address
  // used only for transmitting;
  transmitter.begin(port);

  //start receiver task 
  xTaskCreate(vReceiverTask,
    "RECV_TASK",
    configMINIMAL_STACK_SIZE + 100,
    NULL,
    tskIDLE_PRIORITY + 1,
    NULL);

  // start FreeRTOS Scheduler
  vTaskStartScheduler();

  // should never return
  Serial.println(F("Die"));
  while(1);
}

void loop() {
  String toSend;
  //Echoing serial over UDP
  if(Serial.available()){
    toSend = Serial.readString();
    transmitter.beginPacket(multicast_address, multicast_port);
    transmitter.write(toSend.c_str(),toSend.length());
    transmitter.endPacket();
  }
  Ethernet.maintain();
}
fpistm commented 6 years ago

I've submitted #8 to avoid LwIP option file core dependency. Need to see if #define LWIP_IGMP 1 should be added per default.

rzr commented 5 years ago

Unsure it is related but I managed with a couple of fixes to use ArduinoMDNS library on Nucleo-f767zi with this:

https://github.com/stm32duino/Arduino_Core_STM32/pull/401# (Under review)

fpistm commented 5 years ago

@rzr did you test this PR?

rzr commented 5 years ago

mine yes, not yours ;) how to reproduce ?

fpistm commented 5 years ago

This is not my PR ;) So if I well understood you implement multicast on your own side ? I have to admit I'm not an expert about that, so any input are welcome to add it.

rzr commented 5 years ago

well I did use @arduino library it seems to work with my sample code, I can eventually commit a simpler example, meanwhile there are a couple of hints at bottom of: https://github.com/rzr/webthing-iotjs/wiki/MCU

fpistm commented 5 years ago

So if I well understood, this PR is not required for multicast if using third part library. Last question to check if is this PR is compatible with third party library.

straccio commented 5 years ago

This PR is for multicast, in listening,by subscribing to the IGMP group. This also add a callback when receive message from UDP.

rzr commented 5 years ago

For the record this change: https://github.com/stm32duino/STM32Ethernet/pull/17

is released in: https://github.com/stm32duino/Arduino_Core_STM32/releases/tag/1.5.0

Sorry for confusion...

fpistm commented 5 years ago

Well, I did not have time to investigate this, yet. I'm not comfortable with this. So, what do you advise on this? Is this PR is requested? useful? compatible with @rzr update?... How can I validate it simply ?

fpistm commented 4 years ago

Hi @straccio I've rebased and do some clean/refactor: https://github.com/stm32duino/STM32Ethernet/commit/b956c4b29cef0f96893fc2bb73d067c7d2c6aa51 it works when enable LWIP_IGMP is enabled. So I close this PR. Sorry for the delay.