[SOLVED] runShellCommand stops further code execution when using ISR(TIMER1)

I've searched endlessly on this topic and can't seem to solve my problem.

I want to run curl from a shell command inside my sketch, and I've tested the following with real USER:PASSWORD and URL values and it works just fine.

void sendState()
{
  Process p;
  p.runShellCommand("curl --user USER:PASSWORD --digest -X PUT -d brightness=0 http://URL");
  while(p.running());
}

The problem is when I try to call sendState(); from within some other function in my sketch, it will execute the curl command properly and then not continue running the rest of the function it was called from. I have also tried runShellCommandAsynchronously() with the same results. I'm sure it's something silly, but I'm a total newbie with C. Thanks in advance for any help!

Comment/delete "while p is running" and see what happens. I think this is what gets stuck.

mart256:
Comment/delete "while p is running" and see what happens. I think this is what gets stuck.

Sorry, I should have mentioned that I have tried that and actually the curl command doesn't even execute properly without it for some reason.

Post complete code.

Method defined at line 424, called at 372.

Test it with wrap up ash script and exit with "0"

nano /mnt/sda1/setbrightness.sh
#!/bin/ash
curl --user USER:PASSWORD --digest -X PUT -d brightness=0 http://URL
exit 0
chmod 755 /mnt/sda1/setbrightness.sh

Test it at SSH terminal:

/mnt/sda1/setbrightness.sh
void sendState()
{
  Process p;
  p.runShellCommand("/mnt/sda1/setbrightness.sh");
  //while(p.running());
}

Sonnyu, that works!! Thank you! Would you mind giving me a brief explanation as to why my method hangs? Thanks!

#!/bin/ash
curl --user $1:$2 --digest -X PUT -d brightness=$3 http://URL
exit 0
/mnt/sda1/setbrightness.sh USER PASSWORD 0

How to pass arguments to a shell script

 Process p;              
p.begin("/mnt/sda1/setbrightness.sh");      
p.addParameter(String(USER));
p.addParameter(String(PASSWORD)); 
p.addParameter(String(brightness)); 
p.run();

Perfect, thank you!

srob650:
... Would you mind giving me a brief explanation as to why my method hangs?
...

play with

--connect-timeout SECONDS
-v, --verbose

The CURL should have default connect-timeout, but might be missing at CURL of openwrt.

or

http://URL did not follow Hypertext Transfer Protocol standard, should response 200 OK, but not. CURL is waiting and waiting... and it is missing default connect-timeout as well.

An other problem of CURL :

curl 7.29.0 (mips-openwrt-linux-gnu) has limit at string size we could pass it and does not report error if over limit.

http://forum.arduino.cc/index.php?topic=320060.msg2217886#msg2217886

Thanks for the resources, makes sense.

Hmm, now I'm getting the same error further down the line. I've made the script modular with $1 style args, and it gets called multiple times. It seems to only run the first time though, the second time the function calling the shell script is called I get the same behavior where the whole program hangs and the curl script doesn't execute. I've tried adding p.close(); at the end of that function and that didn't help either. Any thoughts?

New Code: // avr-libc library includes#include <avr/io.h>#include <avr/interrupt.h> - Pastebin.com
See function at line 425, called at 384

What is "http://URL" ? The code behind. I found your code, Can you give me a brief explanation
what you want to do?

or try:

#!/bin/ash
curl --connect-timeout 2 --user $1:$2 --digest -X PUT -d brightness=$3 http://URL
exit 0

Let curl time out after 2 second.

Unfortunately setting the --connect-timeout doesn't seem to fix the issue. I even tried setting the timeout as high as 5 seconds with no results. I also tried using runShellCommandAsynchronously() with the same error. The command runs fine the first time but hangs the second time.

I also tried just running the shell script repeatedly and quickly via SSH and it worked flawlessly every time.

The curl response IS long, you mentioned earlier that that can cause issues. The response looks like this:

This resource can be found at <a href='http://192.168.1.200:8176/variables/arduinoState'>http://192.168.1.200:8176/variables/arduinoState</a>.

I don't think that would be the issue though because then it wouldn't work the first time, right?

sonnyyu:
Can you give me a brief explanation what you want to do?

Basically the Arduino is doing a curl REST call to my home automation server, and updating a variable on the server. It will update that variable to show the current sprinkler zone that is active. The REST call works just fine executed repeatedly from anywhere (like SSH or a web browser).

Home automation server?

It did not follow Hypertext Transfer Protocol standard, should response 200 OK, but not. It is OK for browser or SSH session but not CURL API call.

Plan B:

use wget to replace curl ?

Fix Home automation server or replace it with some thing correct handle protocol.

sonnyyu:
Fix Home automation server or replace it with some thing correct handle protocol.

It's not something I wrote if that's what you mean. It's essentially making a REST call which talks to the home automation software I have running (Indigo Domotics).

How could I get around this using wget?

More info:

Just tried a simple sketch that just sends the curl every 3 seconds in the main loop and it worked perfectly, so that tells me something about the other code is screwing things up. Could it possibly have something to do with me using the ISR(TIMER1_COMPA_vect) as a timer? Perhaps since that timer gets "caught" every second that process is interrupting the curl commands?

More testing confirms that this is an issue with the timer. I can call any other function in place of this shell script just fine. I can also use a normal delay(seconds) in the main loop with the shell script and it works fine. But calling the shell script when using Timer1 screws things up. I have tried setting the timer interrupt to 4 seconds instead of 1 to theoretically give the script more time to run (even though it's nearly instant) but that didn't work either. I really hope someone well versed in timer interrupts and shell scripts can help me out here!

I think you are doing way too much in your ISR.

Your ISR calls runCycle(), which calls nextZone() which calls sendState() which calls your Process object to run your script. All of that is happening in the ISR while interrupts are disabled. The Process object uses serial communications to send the request to the Linux side, and get the response. The communications transport uses interrupts to send/receive the data, but interrupts are disabled due to the ISR being active, so it never gets the response that lets it continue. It's no surprise you're code is hanging, the odd part us that it even works the first time!

stopTimer() is an appropriate function to call from the ISR - it's short and fast, does it's critical business, and gets out, but that is called from stopAll() which I think does too much. The other functions are far too long to call directly from the ISR, the ISR should set a flag to signal that loop() should call the code. I think the ISR should look something like this:

// THIS IS OUR TIMER CATCH
ISR(TIMER1_COMPA_vect)
{
  // Increment variable seconds to count to curDur (zoneTime)
  seconds++;
  // change curDur to curDur*60 for minutes
  if (seconds == curDur)
  {
    processTimer = true;
  }
}

stopRunCycle is a new Boolean flag, defined as volatile at the global file level. Then loop() contains:

if (processTimer)
{
    processTimer = false;

    if (program == true)
    {
      stopTimer();
      runCycle();
    }
    else if (program == false)
    {
      // Stop sprinklers, end program, reset timer
      stopAll();
    }
}