Pages: [1]   Go Down
Author Topic: Oddities when using Udp.beginPacket within an interrupt  (Read 566 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm using an Arduino Ethernet and the Arduino IDE 1.0.3 to build an interface that will accept a trigger on a digital input and then fire off a UDP packet to some third-party software that accepts the packet and performs a specific action.

On the Arduino, I'm also running a web server so that the IP address, command to send and other details can be updated.  They are then stored in the EEPROM so that they can be retrieved when it next boots.  I've not included this code in the example as it's not relevant to the problem as the 'minimal' code below still exhibits the problem:

Code:
uint8_t s_network_mac[]         = { 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff };
uint8_t s_network_ip[]          = { 192, 168, 0, 50 };
uint8_t s_network_subnet[]      = { 255, 255, 255, 0 };
uint8_t s_network_gateway[]     = { 192, 168, 0, 1 };
uint8_t s_network_dns[]         = { 0, 0, 0, 0 };
uint8_t s_network_server[]      = { 192, 168, 0, 106 };

uint16_t s_network_port         = 1234;

#define TRIGGER_PIN             2
#define TRIGGER_INTERRUPT       0

#define TRIGGER_RISING          1
#define TRIGGER_FALLING         2
#define TRIGGER_BOTH            3

#include "SPI.h"
#include "Ethernet.h"
#include "WebServer.h"

WebServer webserver("", 80);

EthernetUDP Udp;

volatile boolean send_command = false;

void web_page_index(WebServer &server, WebServer::ConnectionType type, char *, bool)
{
  server.httpSuccess();

  server.print(
    F(
      "<!DOCTYPE html>\n"
      " <html>\n"
      "  <head>\n"
      "   <title>Success</title>\n"
      "  </head>\n"
      " <body>\n"
      "  It works!\n"
      " </body>\n"
      "</html>"
    )
  );
}

void interrupt()
{
  static unsigned long last_trigger = 0;

  if ((last_trigger == 0) || millis() > last_trigger + 5000)
  {
    last_trigger = millis();

//    send_udp_packet();
    send_command = true;
  }
}

void send_udp_packet()
{
  uint8_t message[2] = { 'A', BE' };

  Udp.beginPacket(s_network_server, s_network_port);

  Udp.write(message, 2);

  Udp.endPacket();
}

void setup()
{
  Ethernet.begin(s_network_mac, s_network_ip, s_network_dns, s_network_gateway, s_network_subnet);

  webserver.setDefaultCommand(&web_page_index);

  webserver.begin();

  Udp.begin(s_network_port);

  pinMode(TRIGGER_PIN, INPUT);
 
  attachInterrupt(TRIGGER_INTERRUPT, interrupt, FALLING);
}

void loop()
{
  if (send_command)
  {
    send_command = false;
    send_udp_packet();
  }

  webserver.processConnection();
}

Everything works as expected at first.  The web server returns the page and upon triggering the input, the UDP packet is successfully sent.  However after two UDP packets have been sent, the web server becomes inaccessible!

I've traced this back and it appears that the problem is caused by EthernetUdp deciding to use the same W5100 socket as the web server, therefore stopping it listening on port 80.

If I change the interrupt code to this:

Code:
void interrupt()
{
  static unsigned long last_trigger = 0;

  if ((last_trigger == 0) || millis() > last_trigger + 5000)
  {
    last_trigger = millis();

//    send_udp_packet();
    send_command = true;
  }
}

Then everything works as intended - the UDP packet is then sent from within loop() but it's definitely not as neat as it should be.

I can live with this solution but would like to try to understand why the problem only exists when EthernetUdp is used within the interrupt.

Some debugging seems to show that readSnSR returns LISTEN for the first two calls (for the first W5100 socket) but then returns CLOSED, even though the web server hasn't been stopped.

Any advice would be gratefully appreciated.  Many thanks in advance.
Logged

UK
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12534
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Doing network I/O within an interrupt handler seems distinctly dodgy to me. Firstly because some of those I/O methods take a substantial time to complete, and it's bad practice to have long-running interrupt handlers. Secondly because the code in the interrupt handler could have been executed at any point in the loop() and may be calling the network libraries re-entrantly. Unless you know that they are designed to be used like that, you should avoid doing that because it's liable to introduce exactly the sort of problem you're chasing here.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In addition, do you know which of the functions you are using require interrupts themselves to function? Interrupt processing is disabled in an interrupt handler.

If you want to make life interesting, you could enable them. Not for the faint-hearted.
Logged

Pages: [1]   Go Up
Jump to: