Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

writeQuick #34

Closed
crmabs opened this issue Apr 30, 2017 · 7 comments
Closed

writeQuick #34

crmabs opened this issue Apr 30, 2017 · 7 comments
Labels

Comments

@crmabs
Copy link

crmabs commented Apr 30, 2017

Hi, I'm trying to make all my I2C communication async in my code and I bumped into the following. Please take a look at it, but it could happen that I'm doing something flat-out wrong.

It's about calling writeQuick, I include the test code:
wqtest.txt
and the output of the program:
output.txt

var wqAsync = function () {
    var bus = i2c.openSync(1);
    bus.writeQuick(0x73, 0, function (err) {
        if (err) {
            console.log("no, failed.")
            throw "writeQuick " + err;
        } else {
            console.log("ok, worked.");
            bus.closeSync();
        }
    });
};

And the result is:

/home/pi/.node-red/node_modules/i2c-bus/i2c-bus.js:282
    i2c.writeQuickAsync(device, bit, cb);
        ^

Error: EINVAL, incorrect arguments passed to writeQuick(int fd, int bit, function cb)
    at Error (native)
    at Bus.<anonymous> (/home/pi/.node-red/node_modules/i2c-bus/i2c-bus.js:282:9)
    at /home/pi/.node-red/node_modules/i2c-bus/i2c-bus.js:83:9

Also this little piece of code is supposed to check the I2C device's presence. It works fine - I used the sync version so far - but I want to make sure I understand it properly what I'm doing.
Could you please validate if this pseudo code is the way?

handle one device starts:
open i2cBus - nicely async and pass the instance on
...
device check: writeQuick/Sync a single bit -> then evaluate the the program's condition
and set true or false accordingly.
...
since the device check went through I can start communicating using the device.
... do some I2c comm ...
...
i2cBus.close()
handle one device ends

The real question is that do I have to do anything else after the writeQuick? Somekind of stop communication is needed there to make the target device abort the comm, and ignore the bit we sent as a probe. --- well, if I'm right.

@fivdi
Copy link
Owner

fivdi commented May 1, 2017

Hi, thank you for reporting this issue. You are right. There is a bug in the argument checking in the writeQuick method in i2c-bus v1.2.1. This has now been fixed in v1.2.2 which was published on npm this morning. If you update to i2c-bus v1.2.2 the writeQuick method should function as expected.

The real question is that do I have to do anything else after the writeQuick? Somekind of stop communication is needed there to make the target device abort the comm, and ignore the bit we sent as a probe. --- well, if I'm right.

Whether or not it's a good idea to use writeQuick to check for the presence of a device is a different question. It will depend on the device and what the device does when writeQuick is called to write a bit to the device. To be honest, I wouldn't use a method that writes to the device to check for it's presence as write commands will generally tell the device to do something which may not be wanted.

i2c-bus has a scan method and that's what I'd used to check for the presence of a device. The scan method will detect the same device as the command i2cdetect -y -r. The implementation of the scan method calls receiveByte which only reads data from the device. I'd do something like this:

'use strict';

var i2cBus = require('i2c-bus'),
  i2c1;

function closeBus() {
  i2c1.close(function(err) {
    if (err) {
      throw err;
    }
    console.log('finished');
  });
}

function communicateWithDevice() {
  console.log('communicate with device...');
  closeBus();
}

i2c1 = i2cBus.open(1, function(err) {
  if (err) {
    throw err;
  }

  i2c1.scan(function(err, devices) {
    if (err) {
      throw err;
    }

    if (devices.indexOf(0x73) !== -1) {
      console.log('found device');
      communicateWithDevice();
    } else {
      console.log('device not found');
      closeBus();
    }
  });
});

@crmabs
Copy link
Author

crmabs commented May 1, 2017

Thanks a lot for the detailed answer and the quick fix!
Well, I fully agree what you are saying about the write. Actually it was a result of my desperate attempts. The case was that one device got always the bus jammed when I tried to do the traditional scan with receiveByte. (i might messed it up) But when I found the writeQuick version of the scan I was jumping in joy. :D "aaaah, the insiders do it this way"

The writeQuick works.

@fivdi
Copy link
Owner

fivdi commented May 1, 2017

Thanks a lot for the detailed answer and the quick fix!

Your welcome and thank you for reporting the issue.

The case was that one device got always the bus jammed when I tried to do the traditional scan with receiveByte. (i might messed it up)

If you call i2cdetect -y -r 1 from the command line, does the bus also get jammed? (If you haven't got i2cdetect installed the command sudo apt-get install i2c-tools should install it.)

If you call i2cdetect -y -q 1 does it function correctly and detect the device at address 0x73 without jamming the bus?

Internally i2cdetect -y -r 1 uses receiveByte and internally i2cdetect -y -q 1 uses writeQuick.

The i2c-bus scan method uses receiveByte because not all platforms support writeQuick. For example, the Raspberry Pi supports both receiveByte and writeQuick, but the BeagleBone only supports receiveByte.

The writeQuick works.

Thats good news 😄

@crmabs
Copy link
Author

crmabs commented May 1, 2017

I did some tests with the async receiveByte and when I call it second time the bus gets stuck. This was the symptom at the first time.

"If you call i2cdetect -y -r 1 from the command line, does the bus also get jammed?"
No, the i2cdetec -y 1 didn't jam the device, and that made me suspicious. That's why I started researching. I must have done something wrong back then. The only thing that wasn't clear to me how to kinda "roll back" the probing operation. I read something about a STO signal (instead of STOP) which makes the targeted device abort the communication whatever was started. (i haven't got time to find the article again)

By the way in your example code when you are finished with the async scan you go on and do the i2c communication. Though within the i2c-bus.scan() you close the bus.
I have few options:
1 - you either thought re-opening it in the beginning of the I2C communications.
2 - that simple close within scan() is the STO i was looking for.
3 - it is just there because the scan() opens it, so it's has to be closed inside scan() as well
4 - i'm lucid dreaming, and next time I should take only the half of it. => That sto/stop is not needed 'coz receiveByte is "harmless" I can continue normal operation, nothing special is needed.

I promise if it's clear to me I'll stop.

@fivdi
Copy link
Owner

fivdi commented May 1, 2017

The only thing that wasn't clear to me how to kinda "roll back" the probing operation. I read something about a STO signal (instead of STOP) which makes the targeted device abort the communication whatever was started.

I'm not familiar with an I2C STO signal. There are START and STOP conditions, however the i2c-bus API does not provide direct access to these conditions and allows the operating system to handle them.

By the way in your example code when you are finished with the async scan you go on and do the i2c communication. Though within the i2c-bus.scan() you close the bus.

This isn't entirely correct. The i2c-bus.scan() method opens an new Bus object for the scan and stores it in a local variable called scanBus here. After it has finished its work, the scan method closes the Bus object that it stored in the local variable scanBus here. The Bus object that the user opens in order to call scan isn't closed.

1 - you either thought re-opening it in the beginning of the I2C communications.
2 - that simple close within scan() is the STO i was looking for.
3 - it is just there because the scan() opens it, so it's has to be closed inside scan() as well
4 - i'm lucid dreaming, and next time I should take only the half of it. => That sto/stop is not needed 'coz receiveByte is "harmless" I can continue normal operation, nothing special is needed.

If I understand things correctly, I'd say 1 and 2 are incorrect and 3 and 4 are correct.

If a Bus object is created with open or openSync, that Bus object can be used to talk to any number of devices on the I2C bus for as long as you choose. Any Bus method, including scan can be called as often as required. In addition, and if needed, it's possible to create more than one Bus object for the same bus.

@crmabs
Copy link
Author

crmabs commented May 1, 2017

The scan method works perfectly, and it perfectly does what I need.
Many thanks for your help!

@fivdi
Copy link
Owner

fivdi commented May 1, 2017

No problem. You're welcome.

@fivdi fivdi closed this as completed May 1, 2017
@fivdi fivdi added the bug label Jan 4, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants