epoll icon indicating copy to clipboard operation
epoll copied to clipboard

Inaccurate interrupt detection after sometime of being idle

Open adonespitogo opened this issue 6 years ago • 12 comments

Hi, I'm trying to interface a multi coin acceptor with Espressobin. This coin acceptor emits pulses for every coin inserted. For example 1 peso coin (I'm in philippines) pulses 0 for 20ms and then pulses 1 for 100ms (using 'both' edge). It turns the GPIO input to 0 for 20ms and turns to 1 for 100ms. It does this one time for 1 peso coin and 5 times for 5 peso coin.

So if you print the value of 'both' edge every time an interrupt occurs, this is the output:

1 peso coin:

0
1 (after 20ms)

5 peso coin:

0
1 (after 20ms)
0 (after 100ms)
1 (after 20ms)
0 (after 100ms)
1 (after 20ms)
0 (after 100ms)
1 (after 20ms)

The problem is that sometimes, some of the interrupts are not detected by the epoll library when I'm no longer interacting with the coin acceptor after sometime. What happens is, for example inserting a 5 peso coin to the multi coin acceptor results to:

1 (after 20ms) - it skipped the first `falling edge` and/or
1 or 0 (after 120ms) - it skipped the falling/rising edge detection
0 (after 100ms)
1 (aftter 20ms)
0 (after 100ms)
1 (after 20ms)
0 (after 100ms)
1 (after 20ms)

I think the interrupt detection job is somewhat put to background or something that's why it can't properly detect the pulses when there is no activity for some time. In the next consecutive insertion of coins, it properly detects the coins again.

I can confirm that the problem is not the circuit or the coin acceptor because this doesn't happen when I use the same schematics on raspberry pi's GPIO and a python script.

I'd just like to know if you have any idea on top of your head what might be the cause of this issue.

adonespitogo avatar Apr 14 '18 14:04 adonespitogo

I think the interrupt detection job is somewhat put to background or something that's why it can't properly detect the pulses when there is no activity for some time.

I haven't seen something like this in the past. This doesn't however mean that it's not happening.

I'd just like to know if you have any idea on top of your head what might be the cause of this issue.

Do the pulses from the coin acceptor bounce? If so, this may explain what's happening.

There is a delay between point in time when an interrupt occurs and point in time when the callback passed to the Epoll constructor is called. Between those two points in time the pin state may change. If the pin state changes between these points in time then the value read from the GPIO will not be the expected value. This can happen with momentary push buttons that bounce. Perhaps there is a similar effect with the coin acceptor.

fivdi avatar Apr 14 '18 17:04 fivdi

I tried using debounceTimeout option from onoff npm package. I tested with values 1,10, 15. But as the number gets larger, the more interrupts are being skipped.

I solved my problem by using python instead and polling the value by reading the gpio#/value with interval 10ms, since python never skips a tick unlike nodejs' setTimeout/setInterval.

I have no knowledge with c language and can't dig on this issue. I can close this issue if you think this is unlikely to be epolls shortcoming.

On Sun, Apr 15, 2018, 1:13 AM Brian Cooke, [email protected] wrote:

I think the interrupt detection job is somewhat put to background or something that's why it can't properly detect the pulses when there is no activity for some time.

I haven't seen something like this in the past. This doesn't however mean that it's not happening.

I'd just like to know if you have any idea on top of your head what might be the cause of this issue.

Do the pulses from the coin acceptor bounce? If so, this may explain what's happening.

There is a delay between point in time when an interrupt occurs and point in time when the callback passed to the Epoll constructor is called. Between those two points in time the pin state may change. If the pin state changes between these points in time then the value read from the GPIO will not be the expected value. This can happen with momentary push buttons that bounce. Perhaps there is a similar effect with the coin acceptor.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/fivdi/epoll/issues/26#issuecomment-381344437, or mute the thread https://github.com/notifications/unsubscribe-auth/ADqWxEe4skVNNumssPzCAwJP5H6qiFCDks5toi4xgaJpZM4TVFRq .

adonespitogo avatar Apr 14 '18 18:04 adonespitogo

Let's leave the issue open. I'll take a closer look at some point to see if something goes wrong when the process is inactive for a long period of time.

Thank you for reporting this issue.

fivdi avatar Apr 14 '18 18:04 fivdi

Thanks as well for this project. Still a great library :)

On Sun, Apr 15, 2018, 2:04 AM Brian Cooke, [email protected] wrote:

Let's leave the issue open. I'll take a closer look at some point to see if something goes wrong when the process is inactive for a long period of time.

Thank you for reporting this issue.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/fivdi/epoll/issues/26#issuecomment-381348366, or mute the thread https://github.com/notifications/unsubscribe-auth/ADqWxP4YELYUmyPrPgmHw6A8G7e-u1mzks5tojpHgaJpZM4TVFRq .

adonespitogo avatar Apr 14 '18 18:04 adonespitogo

@adonespitogo above you mention the following:

I think the interrupt detection job is somewhat put to background or something that's why it can't properly detect the pulses when there is no activity for some time

Approximately how long is it necessary to wait before the issue can be seen?

fivdi avatar Apr 14 '18 20:04 fivdi

Actually, I just realize that this has become very random. I didnt have to wait so long, it can happen within a minute. Sometimes, even on first insertion of coin. Sometimes, on second, on third insertion. Sometimes it doesn't occur within 15 mins of trying to insert coin at around 30s - 1min interval.

On Sun, Apr 15, 2018, 4:03 AM Brian Cooke, [email protected] wrote:

@adonespitogo https://github.com/adonespitogo above you mention the following:

I think the interrupt detection job is somewhat put to background or something that's why it can't properly detect the pulses when there is no activity for some time

Approximately how long is it necessary to wait before the issue can be seen?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/fivdi/epoll/issues/26#issuecomment-381356597, or mute the thread https://github.com/notifications/unsubscribe-auth/ADqWxDx_DxEhSzImqcSr1XAZu_rRZm_Sks5tolX_gaJpZM4TVFRq .

adonespitogo avatar Apr 14 '18 20:04 adonespitogo

I think theres a problem either in the emiting of the interrupt, in which case the epoll is not at fault. Or theres a problem with epoll with regards to the delay of the callback as you mentioned.

Regarding the debounce, I think the problem doesn't lie there because I tried using the debounceTimeout option of onoff library with no success.

My suspicion is that since nodejs is single threaded, the callback may have been delayed.

On Sun, Apr 15, 2018, 4:10 AM adones pitogo, [email protected] wrote:

Actually, I just realize that this has become very random. I didnt have to wait so long, it can happen within a minute. Sometimes, even on first insertion of coin. Sometimes, on second, on third insertion. Sometimes it doesn't occur within 15 mins of trying to insert coin at around 30s - 1min interval.

On Sun, Apr 15, 2018, 4:03 AM Brian Cooke, [email protected] wrote:

@adonespitogo https://github.com/adonespitogo above you mention the following:

I think the interrupt detection job is somewhat put to background or something that's why it can't properly detect the pulses when there is no activity for some time

Approximately how long is it necessary to wait before the issue can be seen?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/fivdi/epoll/issues/26#issuecomment-381356597, or mute the thread https://github.com/notifications/unsubscribe-auth/ADqWxDx_DxEhSzImqcSr1XAZu_rRZm_Sks5tolX_gaJpZM4TVFRq .

adonespitogo avatar Apr 14 '18 20:04 adonespitogo

Thanks for the information.

I'll implement a stress test and run it for a several hours to see what happens. The pulses from the coin acceptor could be generated by a second Raspberry Pi or an AVR microcontroller.

fivdi avatar Apr 14 '18 20:04 fivdi

This is my code by the way, I believe this might be of use as reference for your stress test:

'use strict'

const Q = require('q')
const payment = require('./payment.js');
const config = require('./config/config.json')
const Gpio = require('onoff').Gpio

module.exports.init = function () {

  let coinslot = new Gpio(451, 'in', 'both')

  let time_now = 0
  let last_detect_time = 0
  let has_detected = false
  let diff = 0
  let current_total = 0
  let interval = 100
  let prev_val = 1

  function checkDoneInsert() {
    if (has_detected) {
      time_now += interval
      diff = time_now - last_detect_time

      if (diff > 1000) {

        console.log('payment: ', current_total)
        payment.received(current_total);

        current_total = 0
        diff = 0
        time_now = 0
        last_detect_time = 0
        has_detected = false
      }
    }
  }

  function onChange(val) {
    if (val === 1 && prev_val === 0) {
      has_detected = true
      last_detect_time = time_now
      current_total += 1
    }

    prev_val = val

  }

  coinslot.watch(function (err, val) {
    if (err)
      console.log(err)
    else
      onChange(val)
  })

  setInterval(function () {
    checkDoneInsert()
  }, interval)

  return Q()

}

adonespitogo avatar Apr 14 '18 20:04 adonespitogo

After some experimentation I think the most likely cause for failing to detect some of the pulses from the coin acceptor is blocking synchronous code.

coin-acceptor.c is a program that can be used to simulate the coin acceptor on an atmega328p. Every two seconds the program will generate five pulses to simulate a five peso coin. The program stops after simulating 10.000 coins.

coin-counter-success.js successfully detects the pulses for 10.000 five peso coins.

coin-counter-fail.js fails to detect all the pulses for 10.000 five peso coins. Each pulse is low for 20 milliseconds and high for 100 milliseconds. The program fails to detect approximately 7% of the pulses. The failures occur because the program blocks the main JavaScript thread by executing synchronous code for 30 milliseconds once per second. The 30 milliseconds of blocking is longer that 20 milliseconds for which the pulse is low and the JavaScript code doesn't get around to processing some of the falling edges before the rising edges occur.

The last 16 lines of output for one run of coin-counter-success.js:

fallingPulses: 49975, risingPulses: 49975, errors: 0
fallingPulses: 49975, risingPulses: 49975, errors: 0
fallingPulses: 49980, risingPulses: 49980, errors: 0
fallingPulses: 49980, risingPulses: 49980, errors: 0
fallingPulses: 49981, risingPulses: 49981, errors: 0
fallingPulses: 49985, risingPulses: 49985, errors: 0
fallingPulses: 49985, risingPulses: 49985, errors: 0
fallingPulses: 49990, risingPulses: 49990, errors: 0
fallingPulses: 49990, risingPulses: 49990, errors: 0
fallingPulses: 49992, risingPulses: 49991, errors: 0
fallingPulses: 49995, risingPulses: 49995, errors: 0
fallingPulses: 49995, risingPulses: 49995, errors: 0
fallingPulses: 50000, risingPulses: 50000, errors: 0
fallingPulses: 50000, risingPulses: 50000, errors: 0
fallingPulses: 50000, risingPulses: 50000, errors: 0
fallingPulses: 50000, risingPulses: 50000, errors: 0

The last 16 lines of output for one run of coin-counter-fail.js:

fallingPulses: 46503, risingPulses: 49985, errors: 0
fallingPulses: 46505, risingPulses: 49987, errors: 0
fallingPulses: 46505, risingPulses: 49987, errors: 0
fallingPulses: 46509, risingPulses: 49992, errors: 0
fallingPulses: 46509, risingPulses: 49992, errors: 0
fallingPulses: 46511, risingPulses: 49995, errors: 0
fallingPulses: 46513, risingPulses: 49997, errors: 0
fallingPulses: 46513, risingPulses: 49997, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0

fivdi avatar Apr 28 '18 08:04 fivdi

epoll has its own thread for detecting events. The code in this thread could be modified to queue events for later processing. Events that occur when blocking JavaScript synchronous code is executing for prolonged periods of time would then be queued and could be processed later without getting 'lost'.

fivdi avatar Apr 28 '18 08:04 fivdi

Wow thanks for taking the time to test this. I'm really looking forward for the fix for this. Right now I'm using polling to detect the coins and it's taking a bit of processing resources by constantly reading the gpio value every 10ms.

adonespitogo avatar Apr 28 '18 16:04 adonespitogo