Ethernet + I2C + IR LED = No good

Hey all. I’m having a bit of a nightmare. Let me list the order of things I’m wanting it to do

  • I have an Uno with a shield, hosting a REST server. I am able to make successful POST requests from Postman to this.

  • When I receive a POST request with a certain parameter I want it begin transmission to the slave Nano. This works.

  • When the Nano receives an event through Wire I am doing a Serial.println() to print the enum sent from the master Uno. This works

  • When the enum is equal to a certain value, I want it to transmit IR to turn on an LGTV.

Here is where the problems start to rise…

When the slave Nano receives the event from the master and calls my sendIR() function, it dies. The nano halts and the Uno halts and never sends a 200 back to postman.

If I call sendIR() in setup() of the Nano, the IR transmission is successful and the tv turns on. Winner winner. Adding the combination of the receive event and the sendIR() locks up the Nano without actually sending the IR and the Uno returns a 200. If I send another request both up so I have to hard reset them both.

Here is my code (excuse it’s length and disorganisation - it’s rough and ready):
Master

#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>

byte mac[] = { 0X52, 0X64, 0X75, 0X69, 0X6E, 0X6F };
IPAddress ip( 192,168,1,102 );

enum request{
  IRSend
};

EthernetServer server(80); // Port 80 is HTTP port
char new_state[1024];

boolean reading = false;
String myStr;

void setup(){
  Wire.begin();
  delay(1000); 

  Serial.begin(9600);
  // Start the Ethernet server:
  Ethernet.begin(mac, ip);

  server.begin();

  // Set the digital pins ready to write to
  for (int pin = 2; pin <= 9; pin++) {
    pinMode(pin, OUTPUT);
  }

  Serial.print("Serving on http://");
  Serial.println(Ethernet.localIP());
}

void respond(EthernetClient client)
{
  client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: application/json;charset=utf-8");
          client.println("Server: Arduino");
          client.println("Connection: close");
          client.println();
    client.print("{\"message\" : \"success\",\"status\" : \"200\"}");
          client.println();
}

void loop()
{
  checkForClient();
}

void checkForClient(){

  EthernetClient client = server.available();

  if (client) {

    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    boolean sentHeader = false;
    String myStr = "";
    while (client.connected()) {
      if (client.available()) {

        char c = client.read();

        if(reading && c == ' ') reading = false;
        if(c == '?') reading = true; //found the ?, begin reading the info

        if(reading){
          //Serial.print(c);
          if (c!='?') {
            myStr += c;
          }

        }

        if (c == '\n' && currentLineIsBlank)  break;

        if (c == '\n') {
          currentLineIsBlank = true;
        }else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }

    parseRequest(myStr);
    
    Serial.println("Sending response");
    client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: application/json;charset=utf-8");
    client.println("Server: Arduino");
    client.println("Connection: close");
    client.println();
    client.print("{\"response\":\"success\"}");
    delay(1000);
    client.stop(); // close the connection: 
    Serial.println("finished response");   
  } 
}

void parseRequest(String str) {
  int startIndex = str.indexOf("c");
  String commStr= str.substring(startIndex + 2, startIndex + 3);
  char tempCom[4];
  commStr.toCharArray(tempCom, sizeof(tempCom));
  int command = atoi(tempCom);
  
  
  switch(command){
    case IRSend:
    {
      Serial.println("Sending IR request");
      Wire.beginTransmission(9);
      Wire.write(IRSend);
      Wire.endTransmission();
      Serial.println("IR request transmission complete");
    }
    break;
    default:
    break;
  }
#include <Wire.h>
#include <IRremote.h>

IRsend irsend;

enum request{
  IRSend
};

void setup() {
  Serial.begin(9600);
  Wire.begin(9); 
  Wire.onReceive(receiveEvent);
  sendIR(); //this works
}

int x=0;
void receiveEvent(int bytes) {
  x = Wire.read(); 
  Serial.println("received request");// prints only 're' to serial monitor
  delay(500); // I have played around with this value here, in case it needed to respond to the wire event or something..

  switch(x){
    case IRSend:
      sendIR();
    break;
    default:
    break;
  }
}

void sendIR(){
  int khz = 38; // 38kHz carrier frequency for the NEC protocol
  unsigned int irSignal[] = {9000, 4500, 560, 560, 560, 560, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 39416, 9000, 2210, 560}; //AnalysIR Batch Export (IRremote) - RAW
  irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz);
}

void loop()
{
}
}

I have a total of 2 days of Arduino development under my belt - I am a mobile developer by day (mostly Objective-C for iOS) so am familiar with certain aspects of development, but I’m a little stumped by this.
My leading suspicion is that the combination of the wire event and the IR stuff is overloading the little critter and ends up just dying a death. I was hoping that putting a delay between the event receive and the IR stuff would prove this, but unfortunately it made no difference. Even with the delay bumped up to 1000 it still even fails to print the ‘received request’ line. It tends to get as far as as ‘re’ and stops. This has me really confused as I was under the impression that this would mean that the IR code would not break anything until after the delay(). If I comment out the switch statement in the slave’s receiveEvent() it all works fine (apart from sending the IR on event, of course.). As commented, if I call the sendIR() from the setup code, it does work.

Interestingly (and perhaps, tellingly) with the sendIR() code in setup, it runs setup() twice.
I do have a test project that runs this sendIR function as follows

void loop()
{
//exact same as sendIR()
delay(5000);
}

and this runs perfectly well.

Well, I think I’ve taken up enough of your time. If you could shed some light on this little problem, I would be most grateful as it’s kind of a show-stopper.

Thanks a lot,
Luke

arduino1.ino (2.71 KB)

arduino2_with_servo.ino (1.11 KB)

I GUESS recieveEvent is called from ISR. If so, you cannot use functions that depend on interrupts inside this function. Delay is definitely such function and sendRaw probably too. Try to only set a flag in the recieveEvent and call sendIR from loop if flag is set.

No way..
I was sure I had tried this earlier on as I suspected that this would be the case. After a number of taps of the undo button, it reveals that I had done exactly this - with the addition of the delay().
Well. Thanks a lot for this.
I have now stashed the received int (along with a completed flag = false) and placed a switch statement in the for loop, nested in an if check.

Thanks again.