linux / libusb get usb device path - linux

I use libusb to enumerate over a few usb-devices. Now i like to get the "device-path". I think it's not called usb device-path, because i was not successful with google.
If i connect a usb-device with linux, i get a message in dmesg, here are a few examples for such a "device-path" with an usb temperature sensor (something like this):
Directly to a usb port:
[68448.099682] generic-usb 0003:0C45:7401.0056: input,hidraw1: USB HID v1.10 Keyboard [RDing TEMPer1V1.2] on usb-0000:00:12.0-1/input0 => 12.0-1
Directly to another port:
[68560.853108] generic-usb 0003:0C45:7401.0058: input,hidraw1: USB HID v1.10 Keyboard [RDing TEMPer1V1.2] on usb-0000:00:13.0-1/input0 => 13.0-1
To a usb hub on the first used port:
[68600.245809] generic-usb 0003:0C45:7401.005A: input,hidraw1: USB HID v1.10 Keyboard [RDing TEMPer1V1.2] on usb-0000:00:12.2-1.4/input0 => 12.2-1.4
To another port on the same usb hub:
[68647.925092] generic-usb 0003:0C45:7401.005C: input,hidraw1: USB HID v1.10 Keyboard [RDing TEMPer1V1.2] on usb-0000:00:12.2-1.3/input0 => 12.2-1.3
An now to a usb hub on the usb hub used before:
[68740.715518] generic-usb 0003:0C45:7401.005E: input,hidraw1: USB HID v1.10 Keyboard [RDing TEMPer1V1.2] on usb-0000:00:12.2-1.4.4/input0 => 12.2-1.4.4
Long story short:
The kernel message always contains a unique path for the physical usb device location (see the bold text before). Is it possible to get this "path" in the user space via libusb? I tried many things with struct usb_bus and struct usb_device, but i always was unsuccessfully.
I need this to identify multiple of these usb thermometers, because they don't have a unique serial number and sometimes they just "reconnect" at runtime, so they get different usb id's. So i think the only way to identify them is via the physical location.
Thanks for the help,
Best Regards
Kevin M.
-edit-
Currently i use the following code to search my usb device:
usb_dev_handle *find_lvr_winusb() {
struct usb_bus *bus;
struct usb_device *dev;
for (bus = usb_busses; bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
if (dev->descriptor.idVendor == VENDOR_ID &&
dev->descriptor.idProduct == PRODUCT_ID ) {
usb_dev_handle *handle;
if(debug) {
printf("lvr_winusb with Vendor Id: %x and Product Id: %x found.\n", VENDOR_ID, PRODUCT_ID);
printf("INFO: %d\n", dev->bus->location);
printf("INFO: %d %s\n", bus->location, bus->dirname);
}
if (!(handle = usb_open(dev))) {
printf("Could not open USB device\n");
return NULL;
}
return handle;
}
}
}
return NULL;
}
But with this code i cannot get a unique physical position id. The bus->location returns an integer (bus->dirname contains the same, but as string), which is not unique. I know usb has a hierarchy and in the dmesg i can see this hierarchys path.
With libusb i only can get the bus-id (?) and some device id's. But they don't help me, because i need to identify two or more of these temperature sensors. The device-id always changes when the temperature sensor reset's the connection (every 5 to 60 seconds) and the bus id is not unique. Unfortunately the temperature sensor has no unique serial id.
So i think the physical path is the only way to identify the device.
Best regards
Kevin M.

Since libusb 1.0.12, they have introduced libusb_get_port_path(), and in 1.0.16 replaced it with libusb_get_port_numbers() which allows you to query the bus topology.

Overall summery of the sysfs structure path:
1-1.3:1.0
|_usb root hub - bus number - 1
|_ port number - 1 of root hub
|_port number - 3 of intermediate hub
|_current configuration number - 1
|_ current interface number - 0
More information here

It's possible, like here.
Just scan all USB devices at all busses. When you find needed VID/PID — that's your device.
Or you can do simpler: write an udev-rule which would create symlink like /dev/thermoX when you attach you device. All you need after is to open needed /dev/thermoX.

Related

UART3 RX being held hi (strong pullup) on TI Omap AM335x Sitara Variscite Dev board

I have a
Variscite VAR-SOM-AM33 SoM and dev board (VAR-AM33CustomBoard)
and I'm trying to get UART3 to work with a
Sparkfun FTDI Basic Breakout - 3.3V TTL UART to USB adapter (http://sfe.io/p9873)
Summary of the puzzling part: I am also working on a custom SoM carrier board based on this Variscite dev board and I know that UART0 works perfectly when I cut the traces and hook up my Sparkfun UART/USB. So there is clearly a difference in how UART0 is configured verses UART3.
Software
I have used this exact FTDI USB adapter on many projects and it always works great. Here's what I've tried to enable UART3 on the dev board:
TI Web-Based PinMux Configuration for AM335x (http://dev.ti.com/pinmux)
UART3 with RXD and TXD only
UART pins
C15 is RXD, No Pull (unlike UART0 by the way)
C18 is TXD, Pull Down (just like UART0 by the way)
Yocto Kernel Serial Driver Selection
After wandering around the enormity of the default kernel serial 8250 stack, I eventually stumbled upon the omap-serial.c driver. I wanted to see if it would magically fix my problem or in the least, be less code to sift thru (being a single .c file).
So I configured the kernel (make menuconfig) to disable 8250 and enable CONFIG_SERIAL_OMAP found in Device Drivers->Char Drivers->Serial Drivers.
Yocto Kernel Device Tree Configuration
The TI Pinmux generates this code which I add to my Yocto environment's kernel device tree:
myuart3_pins_default: myuart3_pins_default {
pinctrl-single,pins = <
0x160 ( PIN_INPUT | MUX_MODE1 ) /* (C15) spi0_cs1.uart3_rxd */
0x164 ( PIN_OUTPUT_PULLDOWN | MUX_MODE1 ) /* (C18) eCAP0_in_PWM0_out.uart3_txd */
>;
};
I notice that when editing kernel-source/arch/arm/boot/dts/var-som-am33.dts there is a SPI device called spi1_pins_default which uses the 0x164 pin, so I remove its entry too (not shown in the git diff). SPI1 isn't used by default anyway, but I was just being paranoid.
Here is a git diff of my device tree source:
diff --git a/arch/arm/boot/dts/var-som-am33.dts b/arch/arm/boot/dts/var-som-am33.dts
index 0fdb4e3..05fbd0a 100644
--- a/arch/arm/boot/dts/var-som-am33.dts
+++ b/arch/arm/boot/dts/var-som-am33.dts
## -263,6 +263,13 ##
>;
};
+ myuart3_pins_default: myuart3_pins_default {
+ pinctrl-single,pins = <
+ 0x160 ( PIN_INPUT | MUX_MODE1 ) /* (C15) spi0_cs1.uart3_rxd */
+ 0x164 ( PIN_OUTPUT_PULLDOWN | MUX_MODE1 ) /* (C18) eCAP0_in_PWM0_out.uart3_txd */
+ >;
+ };
+
## -533,11 +522,8 ##
};
&uart3 {
- /*
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <&uart3_pins_default>;
- pinctrl-1 = <&uart3_pins_sleep>;
- */
+ pinctrl-names = "default";
+ pinctrl-0 = <&myuart3_pins_default>;
status = "okay";
};
Finally rebuild the kernel/device tree with bitbake:
yocto_varsomam33/tisdk/build $ MACHINE=varsomam33 bitbake -C compile linux-ti-variscite
Verify Device Tree Settings
Once the kernel and device tree have been built, boot them (in my case over TFTP/nfs-kernel-server) and check that our device tree settings are what we expect:
root#varsomam33:~# find /sys/firmware/devicetree/ -name "*myuart*"
/sys/firmware/devicetree/base/ocp/l4_wkup#44c00000/scm#210000/pinmux#800/myuart3_pins_default
root#varsomam33:~# od -x /sys/firmware/devicetree/base/ocp/l4_wkup#44c00000/scm#210000/pinmux#800/myuart3_pins_default/pinctrl-single,pins
0000000 0000 6001 0000 2900 0000 6401 0000 0100
0000020
If we endian-fix the output values (my busybox od tool doesn't support "od -t x1"), we see this:
PIN | VALUE
--------|-------
0x0160 | 0x0029
0x0164 | 0x0001
Which verifies precisely with the defines in include/dt-bindings/pinctrl/am33xx.h
#define PULL_DISABLE (1 << 3)
#define INPUT_EN (1 << 5)
#define PIN_OUTPUT_PULLDOWN 0
#define MUX_MODE1 1
Hardware
Connections:
Carrier board | Sparkfun USB
------------------------|-------------
J18 pin 9 (UART3_RXD) | TXO
J18 pin 10 (UART3_TXD) | RXI
J15 pin 4 (Ground) | GND
Testing
I use a very simple 198-line serial terminal program written in C found here (http://github.com/bradgrissom/miniterm)
I have used it for years on various embedded linux and desktop linux devices. It does not use flow control as seen on line 123:
newsertio.c_cflag = cooked_baud | CS8 | CLOCAL | CREAD;
Next I'll open serial terminals on both my desktop linux machine with the Sparkfun device (/dev/ttyUSB1 in this case) and on the
embedded side (/dev/ttyO3). I type characters into each terminal session. Notice the 'a' characters are received on the desktop
when typed from the embedded session, but no characters are received on the embedded side when typed from the desktop session.
Embedded Serial Terminal
I type three 'a' characters on the embedded terminal.
I do not receive any characters typed from the desktop terminal
Output:
root#varsomam33:~# ./miniterm -d/dev/ttyO3
************ REMOTE CONSOLE: CTRL-] TO QUIT ********
Desktop Serial Terminal
Notice I recieve the three 'a' characters on the desktop.
I type 't' in this terminal but it does not show up on the embedded terminal.
Output:
# ./miniterm -d/dev/ttyUSB1
************ REMOTE CONSOLE: CTRL-] TO QUIT ********
aaa
Check UART Status
Notice we have transmitted some characters on UART3 but have not received any
root#varsomam33:~# cat /proc/tty/driver/OMAP-SERIAL
serinfo:1.0 driver revision:
0: uart:OMAP UART0 mmio:0x44E09000 irq:155 tx:3080 rx:8 RTS|CTS|DTR|DSR
1: uart:OMAP UART1 mmio:0x48022000 irq:156 tx:0 rx:0 DSR|CD|RI
2: uart:OMAP UART2 mmio:0x48024000 irq:157 tx:0 rx:0 CTS|DSR
3: uart:OMAP UART3 mmio:0x481A6000 irq:158 tx:3 rx:0 CTS|DSR
4: uart:OMAP UART4 mmio:0x481A8000 irq:159 tx:0 rx:0 CTS|DSR
5: uart:OMAP UART5 mmio:0x481AA000 irq:160 tx:0 rx:0 CTS|DSR
Saleae Logic Analyzer Screenshots
UART3 TX looks good between 0 and 3.3V
UART3 RX only drops to 2.5V from 3.3V
Concluding remarks:
Truth table from my testing so far. Note that when I say it doesn't work, it exhibits the problem described above (2.5V to 3.3V swing).
Board | UART | Configuration | Result
------------------------------------------------
Variscite | UART0 | RS232 DCE | WORKS
Variscite | UART1 | RS232 DTE | WORKS
Variscite | UART3 | TTL/UART | NO WORK (this is described in this post)
Custom | UART0 | TTL/UART | WORKS
Custom | UART1 | RS232 DTE | WORKS
Custom | UART1 | TTL/UART | NO WORK (used same procedure described in this post)
I feel like this has something to do with modem control lines (flow control) and that my configuration settings aren't being taken (as per /proc/tty/driver/OMAP-SERIAL)
Any help is appreciated, thanks!
UART3 is being held high because it is also connected to a RS-485 chip's (LTC2852) pin 1. Luckily the board designers knew what they were doing and attached a 0 Ohm resistor (R83) on that line, so removing it frees up UART3's RX line.
As for UART1 on the custom board, the problem is that UART1 is connected on the SoM itself, to a WiFi/Bluetooth chip. This isn't obvious because Variscite doesn't release SoM schematics. They do, however, have a somewhat vague note in the carrier board schematics "Enable UART1 when on-SOM Bluetooth is not mounted".
On the carrier board, UART1 is connected to a SN74AVC4T245 bus transceiver which is turned on/off via a GPIO. The problem is that UART1 actually functions perfectly when interfaced with the bus transceiver. So testing on the dev carrier board, UART1 works perfectly and nobody is the wiser. Its only when you remove the bus transceiver that UART1 doesn't work.
In the end, my only conclusion is that the bus transceiver is tolerant to handling a logic level of 2.5V - 3.3V whereas ordinary UART devices are not.

On Linux, what's a good way to to use HID reports over USB?

On macOS, I use IOKit to get and set HID reports over a USB connection (for the curious, this is a controller for a standing desk that allows you to raise and lower the desk programmatically). I can get a list of devices using an IOHIDManager:
_manager = IOHIDManagerCreate(NULL, 0);
NSDictionary *deviceQuery = #{#kIOHIDVendorIDKey: #0x12D3, #kIOHIDProductIDKey: #0x0002};
IOHIDManagerSetDeviceMatching(_manager, (__bridge CFDictionaryRef)deviceQuery);
IOHIDManagerOpen(_manager, kIOHIDManagerOptionNone);
CFSetRef devices = IOHIDManagerCopyDevices(_manager);
// pick a device from the set and you eventually get a...
IOHIDDeviceRef myDevice = foo;
I then build up request buffers and make requests using:
int8_t *_buffer = ...;
IOHIDDeviceSetReport(myDevice, kIOHIDReportTypeFeature, *_buffer & 0xff, (const uint8_t *)_buffer, REQ_BUFFER_SIZE);
… and read responses using:
IOHIDDeviceGetReport(myDevice, kIOHIDReportTypeFeature, *_buffer & 0xff, (uint8_t *)_buffer, RES_BUFFER_SIZE);
What is an analogous way to do this on Linux? I've never worked with USB on Linux before (nor HID devices), and I'm open to pretty much any stack as long as it'll run on a Raspberry Pi.
to list all devices, capturing interfaces,... on linux libsub is used, see this http://www.microchip.com/forums/m340898.aspx
for the HID reports you can use usbhid-dump http://www.pkill.info/linux/man/8-usbhid-dump/ https://github.com/DIGImend/usbhid-dump or hidraw for low-level

Unable to detect Seeedstudio Bluetooth Shield

I have a problem regarding Seeedstudio Bluetooth shield http://www.seeedstudio.com/depot/Bluetooth-Shield-p-866.html
I can't detect its presence by any other devices.
The code I uploaded to Arduino is a standard example for slave device from the library:
/* Upload this sketch into Seeeduino and press reset*/
#include <SoftwareSerial.h> //Software Serial Port
#define RxD 6
#define TxD 7
#define DEBUG_ENABLED 1
SoftwareSerial blueToothSerial(RxD,TxD);
void setup()
{
Serial.begin(9600);
pinMode(RxD, INPUT);
pinMode(TxD, OUTPUT);
setupBlueToothConnection();
}
void loop()
{
char recvChar;
while(1)
{
if(blueToothSerial.available()){//check if there's any data sent from the remote bluetooth shield
recvChar = blueToothSerial.read();
Serial.print(recvChar);
}
if(Serial.available()){//check if there's any data sent from the local serial terminal, you can add the other applications here
recvChar = Serial.read();
blueToothSerial.print(recvChar);
}
}
}
void setupBlueToothConnection()
{
blueToothSerial.begin(38400); //Set BluetoothBee BaudRate to default baud rate 38400
blueToothSerial.print("\r\n+STWMOD=0\r\n"); //set the bluetooth work in slave mode
blueToothSerial.print("\r\n+STNA=SeeedBTSlave\r\n"); //set the bluetooth name as "SeeedBTSlave"
blueToothSerial.print("\r\n+STOAUT=1\r\n"); // Permit Paired device to connect me
blueToothSerial.print("\r\n+STAUTO=0\r\n"); // Auto-connection should be forbidden here
delay(2000); // This delay is required.
blueToothSerial.print("\r\n+INQ=1\r\n"); //make the slave bluetooth inquirable
Serial.println("The slave bluetooth is inquirable!");
delay(2000); // This delay is required.
blueToothSerial.flush();
}
I've uploaded it to Arduino UNO, connected the shield and... Nothing.
LED marked as D1 is blinking green, and D2 is switched off. The device is not detected by none of the three devices I've tried (two computers and a smartphone).
By "not detected" I mean "hcitool returns nothing and OS based search for Bluetooth devices reports nothing". All three devices can detect each other without any problems.
I tried to connect it to other UNO board (in case the first one was damaged), but the result is the same.
I thought that the shield is somehow at fault, so I had it replaced by a new one - but the results are still the same.
Summing up:
3 extrnal devices
2 Arduinos
2 shields
Tested in all possible combinations, and still no success.
The device is powered up, because when I set it to send it's status to A1 analog port I always read 0 instead of a random value.
The only logical conclusion is that there is something wrong with the code above, but every google search I've made pointed me exactly to that file. It's from official wiki and in every example I've found. I've tried to contact Seeedstudio about it, but they didn't have anything of value to add ("try rebooting until it works").
Has anyone had similar problem, or has any advice what's wrong with the code?
I've managed to solve the problem on my own.
Two steps were required:
First of all I had to use hardware serial port (ports 0 and 1 on Arduino UNO), because for some reason SoftwareSerial doesn't work well with this shield.
Then I had to battery as power supply, since serial communication via ports 0 and 1 has lower priority than USB serial.
The disadvantage of this solution is that you lose USB communication with your PC, but fortunately I didn't need it.
EDIT: To avoid any confusion, here is an example of the code which worked for me:
void setup()
{
setupBlueToothConnection();
Serial.flush();
}
void loop()
{
for (char i = 0; i <= 254; i++)
{
Serial.print(i);
delay(1000);
}
}
void setupBlueToothConnection()
{
Serial.begin(38400); //Set BluetoothBee BaudRate to default baud rate 38400
Serial.print("\r\n+STWMOD=0\r\n"); //set the bluetooth work in slave mode
Serial.print("\r\n+STNA=SeeedBTSlave\r\n"); //set the bluetooth name as "SeeedBTSlave"
Serial.print("\r\n+STOAUT=1\r\n"); // Permit Paired device to connect me
Serial.print("\r\n+STAUTO=0\r\n"); // Auto-connection should be forbidden here
delay(2000); // This delay is required.
Serial.print("\r\n+INQ=1\r\n"); //make the slave bluetooth inquirable
//Serial.println("The slave bluetooth is inquirable!");
delay(2000); // This delay is required.
Serial.flush();
}
Please note that the modem sends answers to some of the commands, you should clean Serial buffer before reading from it.
Also, the jumpers on the shield should be connected like this: BT_TX to pin 0 and BT_RX to pin 1.

Sending commands from custom made Bluetooth device to android phone to control music player

I have created a simple Bluetooth device using following components
HC05 module
Arduino Uno board (with re-programmable micro-controller)
I am wondering if it is possible to send commands from my BT device, as if these commands were sent from Bluetooth headset?
What I mean is:
we send 0x00000055 keycode - and the music pauses
(KEYCODE_MEDIA_PLAY_PAUSE)
we send 0x00000058 - previous song starts playing
(KEYCODE_MEDIA_PREVIOUS)
...
Here is the full list of keycodes which android uses: http://developer.android.com/reference/android/view/KeyEvent.html
I can probably create a separate app, which will read incoming commands and simulate headset button presses, but that is not what I want. As far as I'm concerned - some of the headsets are plug-and-play, meaning that no additional apps must be installed on android device. Here is the code I am currently use to send commands to Android phone:
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(10, 11); // RX | TX
enum { LED_PIN = 6 };
enum LedState { LED_ON, LED_OFF, LED_BLINK };
LedState led_state;
void setup()
{
led_state = LED_OFF;
pinMode(LED_PIN, OUTPUT);
pinMode(9, OUTPUT);
digitalWrite(9, LOW);
Serial.begin(9600);
Serial.println("Enter AT commands:");
BTSerial.begin(38400); // HC-05 default speed in AT command more
}
const int COMMAND_MUSIC = 85;
void loop()
{
digitalWrite(LED_PIN, HIGH);
delay(100);
digitalWrite(LED_PIN, LOW);
delay(100);
delay(10000);
// trying to play or pause once in 10 seconds
BTSerial.write(0x00000055);
//BTSerial.print(0x00000055, HEX);
}
Both devices are paired but music player on my phone stays unaffected by these commands..Is it possible to control music player without creating a side app for "incoming commands from BT"?
Question is if your board supports AVRCP controller BT profile?
If it does you "only" need to connect against your phones AVRCP target BT profile. When you have a AVRCP BT connection there is specified commands how to pause and skip songs.
This is how the "plug and play" headset does.
Read more about Bluetooth profiles.
http://en.wikipedia.org/wiki/Bluetooth_profile
Looking at your code you have set up a serial link towards a phone.
This link uses SPP profile and you will only be able to send raw data over that link.
If this is the only profile that your BT stack on your Arduino Uno board have you will be forced to create an application on the phone side to be able to read the raw data and do something with it e.g. pause music.
Hope this cleared things little for you.
Probably it is to late for you, but maybe I can help someone else.
Firstly, Bluetooth devices like BT headphones, keyboards etc, are known as HID (Human Interface devices). HC05 are not one of this out of the box, but there is a solution introduced by Evan Kale (link: https://www.youtube.com/watch?v=BBqsVKMYz1I) how to update one of this using serial port connection.
Other solution is to buy BT HID module, but they are more expensive (about 10 times)

ftdi_usb_open() returns -8 on Linux, but the same code is working on Mac

I am using FT2232H in SYNC FIFO FT245 mode and I can't get it working on Linux, my code is perfectly working on Mac OS X, but it doesn't on Linux.
I have installed both libftdi1 and libftdi-dev packages.
Relevant parts of code:
#define PID 0x6010
.
.
.
if(vftdic == NULL)
{
this->ftdic = static_cast<struct ftdi_context*>(malloc(sizeof(struct ftdi_context)));
}
else
{
this->ftdic = vftdic;
}
int f;
// Init 1. channel
if (ftdi_init(ftdic) < 0)
{
throw DeviceException("ftdi_init failure\n", FTDI_ERROR);
}
ftdi_set_interface(ftdic, INTERFACE_A);
f = ftdi_usb_open(ftdic, 0x0403, PID);
if (f < 0 && (f != -5))
{
//here f is equal to -8 only on Linux
throw DeviceException("Unable to open FTDI device, channel A\n", FTDI_ERROR);
}
Here is listing from lsusb:
Bus 001 Device 005: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
All hardware used is the same (MacBook Pro 2010 + my usb device with ft2232h).
Does the user account you're using have permissions to access the raw USB bus? Check permissions of the device file corresponding to your FTDI located somewhere below /dev/bus/usb – most like you don't have permissions to access it.
In that case add some UDev rules to place the device file in the ownership of some dedicated group and and add yourself to the members of this group.
In addition to making sure you have permission to the device node, you must verify that no other driver (such as a USB serial driver which normally ships with a linux distribution) has claimed the interface.

Resources