2

I have a device attached to a Raspberry Pi. The Pi is running ARCH Linux. The device communicates with the Pi via USB. The device has to be switched on and off via a pulse and I have control, from the Pi, of a relay which causes this pulse. However I can never be sure whether the device is initially on or off.

In my code I toggle the relay and then speculatively call open() on the device (with flags O_RDWR | O_NOCTTY). The problem is that if I am doing this when the device is off the open() call hangs. I have tried waiting for 1 second after the toggle, for things to settle, but that hasn't helped. I have tried calling stat() before the open() call but this always returns zero (so the device is there as far as stat() is concerned). I have tried specifying O_NON_BLOCK in the open() call but that causes it to always fail.

Can anyone suggest either (a) what I'm doing wrong or (b) a reliable way forward?

Rob
  • 865
  • 1
  • 8
  • 21

4 Answers4

1

If you can be sure that the device will eventually turn up, the blocking open() ("hangs") may actually be what you want! The call to open() will return, hopefully with success, when your device turns up.

The stat() call simply checks if the device special file is there. It can't tell you if there is anything listening.

One possible way forward, would be to open() with O_NONBLOCK in an exponential back-off loop.

Depending on what you mean with "communicates via USB", you may want to use libusb. If it's just a USB serial port, wrapping open() yourself is probably the easiest though.

  • No, I'm using open() as way to determine if the device is there between calls to the toggle of that "power switch" relay, which I now realise is a bad use of open(). I should be checking that the device enumerates instead! – Rob Mar 09 '15 at 10:21
  • In that case, libusb will save you a lot of time / code. :) You can have it wait until the device you expect enumerates and then fire a callback. –  Mar 09 '15 at 10:34
1

You can be certain that the device has powered if it has USB enumerated. You can use libudev to find the list of USB enumerated devices and check whether your device is on that list.

The command line "lsusb" does that. So if you need an example of how to use libudev then you can read the lsusb source code (https://github.com/gregkh/lsusb).

kaylum
  • 13,833
  • 2
  • 22
  • 31
  • Ah, yes, that's it, just what I wanted, I should be checking that the device enumerates, not dumbly trying to open() it. Thanks very much for pointing me to the lsusb code, I will work my way forward from there. – Rob Mar 09 '15 at 10:22
1

It's not clear what you have done to get a device file that survives disconnect.

The usual approach is to use hotplug+udev to create (and remove) the device symlinks, then the special file would only be there when the device is plugged in.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • I've not done anything special myself, just allowed the OS to enumerate the device, which is maybe part of the problem. – Rob Mar 09 '15 at 10:19
  • @Rob: Enumerating the device will, at most, automatically load a driver. You don't get device special files on your filesystem automatically, not even with `devfs`. You need a userspace service to do that, most likely `udev` (although it can also be busybox `mdev` on embedded systems). And that userspace service can be configured... – Ben Voigt Mar 09 '15 at 14:04
  • Sorry, yes, I do have a rules file of my own which pops up a device under /dev if that's what you mean. Apologies for my lack of clarity, I don't have to do this very often and/or I forget about it once it has begun working :-). – Rob Mar 09 '15 at 16:55
  • @Rob: Well I suggest you use a device-removal rule to delete the symlink. when the device is unplugged. Lots of information about that, such as http://stackoverflow.com/q/1474266/103167 and http://unix.stackexchange.com/q/71348/11284 and http://unix.stackexchange.com/q/178341/11284 – Ben Voigt Mar 09 '15 at 16:56
  • Nice one, adding ACTION=="remove", ATTRS{interface}=="blah", MODE="7777", SYMLINK-="MySymlink" removes the special file when the device is switched off and my code does what I originally intended it to do now. I think I will still do the enumeration check as it seems the more correct thing to do, but it can wait until I have time. Thanks very much. – Rob Mar 09 '15 at 18:11
0

Courtesy of all the helpful people below, the quick answer was to include in my .rules file a "remove" action to go with the existing "add" action. So in the file where I have:

ACTION=="add", ATTRS{interface}=="Pololu Orangutan X2 Serial Adapter", MODE="7777", SYMLINK+="OrangutanUSB"

...to give me a /dev/OrangutanUSB device, I have included a new line:

ACTION=="remove", ATTRS{interface}=="Pololu Orangutan X2 Serial Adapter", MODE="7777", SYMLINK-="OrangutanUSB"

...to cause the operating system to remove the /dev/OrangutanUSB device when it has been powered off. This way the open() call fails correctly when the device has gone, rather than hanging.

Ultimately, what I should do is check that the device is enumerated, rather than expecting open() to fail, but that can wait until I have the time. For now my code works as originally intended.

Rob
  • 865
  • 1
  • 8
  • 21