WiringPi / WiringPi-Node

Node.js bindings to wiringPi
334 stars 94 forks source link

wiringPiISR does not prevent node to terminate #15

Closed LouTerrailloune closed 9 years ago

LouTerrailloune commented 9 years ago

Consider the following code:

var wpi = require('wiring-pi');

wpi.setup('gpio');

var pin = 17;

wpi.pinMode(pin, wpi.INPUT);
wpi.pullUpDnControl(pin, wpi.PUD_UP);

wpi.wiringPiISR(pin, wpi.INT_EDGE_FALLING, function(delta) {
  console.log("Hit ! " + delta);
});

When I run it, it will terminate immediately. I think it would be better if wiringPiISR() worked like setTimeout() and block until the interrupt is removed (is it possible to remove an interrupt after calling wiringPiISR() ?)

This is not a major issue for me, because I will run a web server that will keep the process running, but in some case it might be useful.

As a temporary fix I appended the following code to my program:

setTimeout(function(){
    console.log("Exiting...");
}, 5000);

I have 5 seconds to test my button, and it's working !

nekuz0r commented 9 years ago

Hi,

There is actually no way to remove an interrupt once wiringPiISR has been called. libWiringPi does not provide a way to remove an interrupt handler.

I am searching a way to keep the node process running.

nekuz0r commented 9 years ago

As a temporary fix you can use : setInterval(function(){},10000); that will call an empty callback each 10s and keep the process running.

nekuz0r commented 9 years ago

Cancelling an interrupt handler

A little modification of the libWiringPi should allow us to cancel an interrupt handler. Making wiringPiISR in libWiringPi returning the thread id stored in threadId by a successful call to pthread_create instead of 0. Then we could call pthread_cancel to cancel the interrupt handler.

Interrupt handler keeps event loop running

A way to keep the node process running when calling wiringPiISR is to create a dummy event loop, something like this:

static void UV_ASYNC_NOP(uv_async_t* handler, int status) {}

wiringPiISR(pin, ...) {
  ...
  uv_async_init(uv_default_loop(), &handlers[pin], &UV_ASYNC_NOP);
  uv_ref((uv_handle_t*)&handlers[pin]);
  ...
  threadIds[pin] = ::wiringPiISR(pin, ...);
}

wiringPiCancelISR(pin) {
  ::wiringPiCancelISR(threadIds[pin]);
  uv_close((uv_handle_t*)&handlers[pin]);
}
eugeneware commented 9 years ago

LGTM

nekuz0r commented 9 years ago

I implemented it in the incoming branch, can you test it ? I don't have a rpi within easy reach atm. To install: npm install git+https://github.com/nekuz0r/wiring-pi.git#incoming

wiringPiISR should keep the main event loop running wiringPiISRCancel(pin) should cancel the interrupt handler and if it's the last one running terminates the node process

LouTerrailloune commented 9 years ago

Just tested it, seems to work perfectly.

nekuz0r commented 9 years ago

Found a way to achieve it without modify the signature of the wiringPiISR function. I prefer doing it that way, so i leave it untouched. I'll commit it to incoming soon.

LouTerrailloune commented 9 years ago

Ping me when it's ready to test, however, I've switched to https://github.com/fivdi/onoff which deals with that interrupt issue in a better way. (no more ugly fork() !)