Imitating specific USB device - linux

I recently got hands on an workout device which has a USB to PC interface and logs workouts on a lousy Windows Application. My intention is to read out the USB and build a custom application for presenting that data.
When connected to a linux machine the device registers in /dev/ttyUSB0, can be seen with lsusb and stty reports the baudrate among other information. I fire up minicom with the stty settings and as soon as the workout is initiated the device sends a series of 41 bytes
I assume that those bytes represent an announcement to the the PC interface.
What I would like to do is to imitate the workout device and send those 41 bytes to the PC interface myself in order to see what the PC side does upon initiation. Is there a way to imitate the device so that the PC software will recognize it?

if the device is /dev/ttyUSB0 it is very likel implementing a virtual COM port, this is USB Communication Device class CDC (ACM).
the operating system knows what driver / kernel module it has to load because when you plug in the device in USB protocol descriptors are exchanged ( the device sends its device descriptor to the host, according to this the host loads the driver / kernel module ), you can see this information with lsusb -v. Specifically the device sends the following descriptors to the host : device descriptor, configuration descriptor, interface descriptor, endpoint descriptor : http://www.beyondlogic.org/usbnutshell/usb1.shtml
for imitating a device you have to write a firmware on a MCU with exaclty these descriptors and additionally with identic VID ( vendor id ) and PID ( product id )
the 41 bytes you receive flow over the virtual COM port and so in RS-232 protocol ( you are able to receive them with minicom ) and so they are above USB level, however they are part of the payload in USB packets. if you have a proprietary driver in windows of your device in windows these 41 bytes are very likely addressed to the driver ( whichs source code you very likely do not have ...). this is very common there are multimeters with RS-232 interface and one has to send a D = 44 (hex) = 01000100 (bin) to receive any data
so you can try to sniff the virtual COM port ( RS-232 protocol ) directly using a RS-232 sniffer, i.e. https://www.eltima.com/rs232-sniffer.html
alternatively you can try is to sniff the underlying USB traffic with wireshark ( or usbmon in linux ) and extract the payload from the USB packets to record the communication between the windows driver and ther device
https://ask.wireshark.org/question/36/how-to-capture-usb-packets-please/
https://www.youtube.com/watch?v=EfkC7kmIMt8 ( USB in Wireshark )
https://www.kernel.org/doc/Documentation/usb/usbmon.txt
( https://www.kernel.org/doc/html/v4.13/driver-api/usb/URB.html )

Related

RS-422 to usb convertor does work but Serial Com port does not

I am trying to get my com port working with my device and am having trouble doing so. I have already tested the serial output from my device using a RS-422 to USB convertor and data was being shown on my screen terminal flawlessly thorough /dev/ttyUSB0. My goal is to forgo the convertor and connect directly to my com port, /dev/ttyS0. The problem is when using screen to view my data on /dev/ttyS0 all I get is nonsensical data.
My device uses a slightly faster baud rate of 230400 so I though that might be an issue so I contacted the manufacturer but they stated the com port is capable of high speeds with an RS-422 protocol. I then followed up by doing getting a loopback cable and seeing if Tx matches Rx and it does. Ultimately, I am very confused as to why the RS-422 - USB convertor does the trick but when trying to simply use the serial port I get garbage data.
For clarity, My PC does indeed have a COM port to connect to serially. The bios settings let me pick if the port uses RS-422, RS-232, and RS-485. I have a gps connecting to my device and my device connects to my PC either through the COM port(does not work) or by usb with the convertor(does work). I expect a steady stream of positional data which I get only when using the convertor. When using the COM port I get random Char/numbers and unkown symbols(�). Only things I can think of is:
A. my COM port is broken(though it passed the loobback test)
B. Missing some sort of driver in order to run with a 230400 baud rate
C. Somehow the convertor is able to translate the ascii characters but the serial port cannot.

Always assign the same bluetooth dongle the same linux identifier hci0

we have a Raspberry Pi that is always listening for Bluetooth devices and if some conditions for the peripheral apply, it opens a Bluetooth connection to write some data to the peripheral.
For performance optimizations, there is one Bluetooth Dongle only for listening and another one that does the connections/writing. In our scripts, we hardwired hci0 to be the listening device and hci1 to connect.
Now we have the problem, that if somebody unplugs the dongle during runtime and plugs it back in, the device will receive the name hci2. This of course breaks our scripts.
So, my question is: Can I configure my Raspberry Pi OS to always assign the same name to the dongle? I would imagine, as they are using the MAC of the Dongle as an identifier, this should be possible.
Thanks for your help!
Rather than hardcode hci0 and hci1 in your code, I would look up the value for the mac address.
I'll assume you are using the D-Bus API and so could use GetManagedObjects.
For example:
import pydbus
bus = pydbus.SystemBus()
mngr = bus.get('org.bluez', '/')
def get_hci(address):
mngd_objs = mngr.GetManagedObjects()
for path in mngd_objs:
device_info = mngd_objs[path].get('org.bluez.Adapter1', {}).get('Address', 'none')
if device_info == address:
return path
print(get_hci('B8:27:EB:22:33:44'))
# /org/bluez/hci0

Determine USB device file Path

How can i get USB device file path correctly in Linux.
I used command: find / -iname "usb" and got the result as below:
/dev/bus/usb
/sys/bus/usb
/sys/bus/usb/drivers/usb
/sys/kernel/debug/usb
Under /dev/bus/usb i see:
001 002 003 004 005 006
But I think they aren't files as i need.
Under /sys/bus/usb/devices/:
sh-3.2# ls /sys/bus/usb/devices/
1-0:1.0 1-1:1.0 3-0:1.0 5-0:1.0 usb1 usb3 usb5
1-1 2-0:1.0 4-0:1.0 6-0:1.0 usb2 usb4 usb6
And Under /sys/bus/scsi/devices/ when i pluged an USB i see:
2:0:0:0 host0 host2 target2:0:0
And when i removed USB i see:
sh-3.2# ls
host0
So which device file is used for USB? How can i indentify it? I need to make a C program with USB device file...
Further more, could you explain to me the number 1-1:1.0? What does it mean?
Thank you.
So which device file is used for USB? How can i indentify it?
What you see behind /sys/ is mainly configuration/information about devices. /dev/bus/usb is what you are looking for. I think that the following article can help you
http://www.linuxjournal.com/article/7466?page=0,0
Is quite old, but still it can help you. (In the article they speak about /proc/bus/usb, today we have /dev/bus/usb)
Further more, could you explain to me the number 1-1:1.0? What does it mean?
The generic form is
X-Y.Z:A.B
Each field identify the connection point of your device. The first two field are mandatory:
X is the USB bus of your motherboard where is connected the USB system.
Y is the port in use on the bus system
So the USB device identified with the string 3-3 is the device connected on the port 3 of the bus 3.
If you connect an USB hub, you are extending the connection capability of a single USB port. The Linux kernel identify this situation by appending the Z field.
Z is the port is use on an hub
So, the USB device identified with the string 1-2.5 is the device connected on the port 5 of the hub connected on the port 2 of the bus 1.
USB specification allow you to connect in cascade more then one USB hub, so the Linux kernel continue to append the port in use on the different hubs. So, the USB device identified with the string 1-2.1.1 is the device connected on the port 1 of the hub connected on the port 1 of the hub connected to the port 2 of the bus 1.
A fast way to retrieve these information is to read the kernel messages (if you can).
$ dmesg | grep usb
[... snip ...]
[ 2.047950] usb 4-1: new full-speed USB device number 2 using ohci_hcd
[ 2.202628] usb 4-1: New USB device found, idVendor=046d, idProduct=c318
[ 2.202638] usb 4-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 2.202643] usb 4-1: Product: Logitech Illuminated Keyboard
[ 2.202648] usb 4-1: Manufacturer: Logitech
[... snip ...]
Then, the last two fields of the pattern (after colon) identify an internal section of an USB device :
A is the configuration number of the device
B is the interface number of a configuration
So, the string 4-1:1.1 means: the interface 1, on configuration 1 that is connected on the port 1 of the bus 4.
You can retrieve these information with the command lsusb.

Porting DOS program to linux to read/write serial port over usb

I have old DOS program which works with serial port. And I need to port it to linux. I've connected my serial device to linux via USB (using rs232 cable). It appears as /dev/ttyUSB0.
Can I use functions inb, outb (instead of DOS equivalent inp, outp) for reading or writing in device from my code? (inb and outb special function for lowlevel reading-writing bytes to specific port address). I don't understand how to determine proper port number.
Maybe there is another approach - for example open file '/dev/ttyUSB0'. But in this case I have a problem reading device registers such as modem control register (MCR) or line status register (LSR).
You can use inb/outb or mmap (eg. devmem, depends on architecture) for onboard standard serial port but it is not recommended in userland. You need root priviledges, you can cause conflict with kernel's driver and you have to be sure that your hardware (eg. 16C550) is full compatible with your code.
To trigger your program when serial port added can use udev rule or old hotplug. To determine port in case of USB serial port converter you can use USB bus id and port id. You can check the numbers via lsusb -t command.
serial port configuration: http://linux.die.net/man/3/termios
check if there are received data (LSR): select()
data inb / outb -> read() / write()
MSR (DCD, RI, CTS) / MCR (DTR, RTS if hardware flow control disabled) -> ioctl() or tty_ioctl
You can learn from picocom source code
Possible problem for realtime application: delays caused by USB bus polling and process/thread switching.

USB Keyboard Protocol

I am trying to build an HID keyboard. I got my STM32 MCU to recognize as a keyboard, but for some reason when I try to send the HID report (8 bytes) using Endpoint 1 in Interrupt mode. The host side doesn't get the data(key pressed) . Do I need to use the standard method Get_Report ?
I have also tried another implementation on a AT90USB1287. It works well but for some odd reason I must set the endpoint to 3 in order to get it working.
i am wondering if the USB HID keyboard protocol only looks at end point 3 when getting data?
The USB HID (keyboard) protocol uses the endpoint you specify in your USB descriptor. Look at the Endpoint address in the Endpoint descriptor.

Resources