-2

GOAL: I am trying to connect 4 RFID readers to a Pi and I need to differentiate each one's port.

WHAT I'VE DONE: I entered lsusb into terminal with nothing but one reader plugged in. It returns :

Bus 001 Device 004: ID 0c27:232a RFIDeas, Inc

This is my reader. So my Vendor ID should be 0c27 and my Product ID should be 232a Now I need the serial # because all of my readers show the same Vendor and Product IDs.

My device is on port ttyACM0, so in terminal I search for the serial attribute as well as verify my product ID and vendor ID by putting:

udevadm info --name=ttyACM0 --attribute-walk | grep -i "serial" -e "product" -e "vendor"

This returns:

ATTRS{idProduct}=="232a"
ATTRS{idVendor}=="0c27"
ATTRS{product}=="USB Serial"
ATTRS{idProduct}=="9514"
ATTRS{idVendor}=="0424"
ATTRS{idProduct}=="0002"
ATTRS{idVendor}=="1d6b"
ATTRS{product}=="DWC OTG Controller"
ATTRS{serial}=="3f980000.usb"

PROBLEM: 3 Product IDs and 3 Vendor IDs return. While only one serial # returns.

QUESTIONS:

  1. Why does this return 3 Product IDs and 3 Vendor IDs when there is only one device connected?

  2. Which ones am I supposed to use in my udev rules to make a persistent device name?

If I am leaving something out please let me know so I can update the question.

EDIT: I have successfully created a udev rule using the first mentioned product ID and vendor ID:

SUBSYSTEM=="tty", ATTRS{idVendor}=="0c27", ATTRS{idProduct}=="232a", SYMLINK+="reader1"

This creates a working udev rule, BUT when I add the serial # ATTRS{serial}=="3f980000.usb" it stops working. I need a unique identifier.

  • 1
    Perhaps [Raspberry Pi Stack Exchange](http://raspberrypi.stackexchange.com/), [Internet of Things Stack Exchange](http://iot.stackexchange.com/) or [Unix & Linux Stack Exchange](http://unix.stackexchange.com/) would be a better place to ask. – jww Oct 17 '18 at 06:22
  • I had no idea that any of these existed. I actually just found my answer and am about to post it, but I will definitely go there from now on. Thank you for your help. – Kevin Coleman Oct 17 '18 at 06:25

2 Answers2

2

While from your perspective you just plugged one device into your computer, the Linux kernel has a more complicated view of what is happening. The kernel keeps track of a hierarchy of devices, each with its own attributes, drivers, and child devices. The root of the hierarchy is usually some kind of root device representing your CPU, which is then connected (perhaps indirectly) to a USB controller device, which is connected to a "root hub", which is then connected to the physical USB device you plugged in, which in turn might have child devices for each function/interface that the USB device exposes.

You can run man udevadm to learn more about what the command does. It says:

   -a, --attribute-walk
       Print all sysfs properties of the specified device that can be used
       in udev rules to match the specified device. It prints all devices
       along the chain, up to the root of sysfs that can be used in udev
       rules.

So there is this chain of devices, starting with ttyACM0 (a function of your USB device), and going up to the physical USB device, then the root hub, and then the USB controller, until it reaches the root of the heirarchy. The --attribute-walk option walks up that chain and prints out attributes of each of the devices along the way.

You are piping the output of that command into grep so you are not seeing the full output, and that it probably why you are confused. The full output of the command is actually very informative: it prints out a nice paragraph explaining what it does, and there are helpful sentences to make it clear when it switches from printing the attributes of one device to printing that of its parent. Here is some of the output I get when examining a USB device on my Raspberry Pi:

$ udevadm info --name=sda2 --attribute-walk

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda2':
    KERNEL=="sda2"
    SUBSYSTEM=="block"
    [snip]

  looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0/0:0:0:0/block/sda':
    KERNELS=="sda"
    SUBSYSTEMS=="block"
    [snip]

  looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0':
    KERNELS=="target0:0:0"
    SUBSYSTEMS=="scsi"
    [snip]

  looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0':
    KERNELS=="1-1.2.1:1.0"
    SUBSYSTEMS=="usb"
    [snip]

  looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1':
    KERNELS=="1-1.2.1"
    SUBSYSTEMS=="usb"
    [snip]

  [... and so on, up to the root device]

Unfortunately, from the output of your udevadm command, it looks like your RFID adapter does not have a USB serial number, so distinguishing it from other devices of the same model might by tricky. To confirm it doesn't have a serial number, I recommend that you run lsusb -v -d 0c27:232a | grep iSerial. If the number after iSerial is 0, it means there is no serial number.

I recommend looking at the symbolic links that Linux creates for you in /dev/serial/by-id; maybe those symbolic links will have enough detail in their names so that you don't need to create a new udev rule. (Hint: run ls -lR /dev/serial/by-id.)

If you still need more help finding or creating stable symbolic links, I think you should plug in all four RFID readers and then post the full output from each of these commands:

ls -lR /dev/serial/by-id
ls /dev/ttyACM*
udevadm info --name=ttyACM0 --attribute-walk
David Grayson
  • 84,103
  • 24
  • 152
  • 189
0

I was able to create a udev rule by putting in the following:

SUBSYSTEM=="tty", ATTRS{idVendor}=="1d6b", ATTRS{idProduct}=="0002", ATTRS{serial}=="3f980000.usb", SYMLINK+="reader1"

The reason for multiple Product and Vendor IDs is explained by David Grayson's answer quoted below. This is what lead me to the solution.

While from your perspective you just plugged one device into your computer, the Linux kernel has a more complicated view of what is happening. The kernel keeps track of a hierarchy of devices, each with its own attributes, drivers, and child devices. The root of the hierarchy is usually some kind of root device representing your CPU, which is then connected (perhaps indirectly) to a USB controller device, which is connected to a "root hub", which is then connected to the physical USB device you plugged in, which in turn might have child devices for each function/interface that the USB device exposes.

You can run man udevadm to learn more about what the command does. It says:

-a, --attribute-walk Print all sysfs properties of the specified device that can be used in udev rules to match the specified device. It prints all devices along the chain, up to the root of sysfs that can be used in udev rules. So there is this chain of devices, starting with ttyACM0 (a function of your USB device), and going up to the physical USB device, then the root hub, and then the USB controller, until it reaches the root of the heirarchy. The --attribute-walk option walks up that chain and prints out attributes of each of the devices along the way.

You are piping the output of that command into grep so you are not seeing the full output, and that it probably why you are confused. The full output of the command is actually very informative: it prints out a nice paragraph explaining what it does, and there are helpful sentences to make it clear when it switches from printing the attributes of one device to printing that of its parent. Here is some of the output I get when examining a USB device on my Raspberry Pi:

$ udevadm info --name=sda2 --attribute-walk

Udevadm info starts with the device specified by the devpath and then walks up the chain of parent devices. It prints for every device found, all possible attributes in the udev rules key format. A rule to match, can be composed by the attributes of the device and the attributes from one single parent device.

looking at device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda2': KERNEL=="sda2" SUBSYSTEM=="block" [snip]

looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0/0:0:0:0/block/sda': KERNELS=="sda" SUBSYSTEMS=="block" [snip]

looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0': KERNELS=="target0:0:0" SUBSYSTEMS=="scsi" [snip]

looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0': KERNELS=="1-1.2.1:1.0" SUBSYSTEMS=="usb" [snip]

looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1': KERNELS=="1-1.2.1" SUBSYSTEMS=="usb" [snip]

[... and so on, up to the root device]"

  • 1
    Are you sure that `3f980000.usb` is actually the serial number of your RFID USB device? It seems like it would be the serial number of your Raspberry Pi's USB controller, based on where it shows up in the `udevadm` output. You'll probably see the same serial number in there when you plug a different RFID reader into the same port, and your udev rule will be too general. – David Grayson Oct 17 '18 at 22:06
  • I see my mistake. In that case you would be correct that my device has no serial. I tried `lsusb -v -d 0c27:232a | grep iSerial`. It does, in fact, return 0. – Kevin Coleman Oct 18 '18 at 02:11
  • I've also tried `ls -lR /dev/serial/by-id`. I've never heard of creating symbolic links, so I'm not sure what to do with this info. I'm looking into it. – Kevin Coleman Oct 18 '18 at 02:13
  • EDIT: I've not heard of creating symbolic links for this application that are not udev rules. – Kevin Coleman Oct 18 '18 at 02:21
  • 1
    The return from `ls -lR /dev/serial/by-id` is `total 0` and then `lrwxrwxrwx root root 13 Mar 14 00:52 usb-RFIDeas_USB_Serial-if00 -> ../../ttyACM0`. Unfortunately, I only have access to the one reader right now so I can't look for differences between the 4. I will post again when these arrive. Again, thank you for your help. It's starting to make sense now. – Kevin Coleman Oct 18 '18 at 02:30
  • Glad I could help. You would not create symbolic links in `/dev/serial/by-id`, you would just look there and see if the links that already live there are good enough for you to use. – David Grayson Oct 18 '18 at 18:04
  • So assuming `usb-RFIDeas_USB_Serial-if00` IS good enough. How do I use that? Would I just serial read from `/dev/usb-RFIDeas_USB_Serial-if00`? – Kevin Coleman Oct 19 '18 at 02:07
  • You would have to use the full, correct path, which starts with `/dev/serial/by-id/`. It should be `/dev/serial/by-id/usb-RFIDeas_USB_Serial-if00` if your previous comment is correct. You'd use that path in place of `/dev/ttyACM0` in whatever piece of software you are using to open the serial port. – David Grayson Oct 19 '18 at 05:15