Get device name from usb - c++

lsusb command
i want to get device name like on lsusb. I found this code and i tried its all descriptor parameters.Is there any way to get device name like on picture like Log. Opt. Gam. Mouse
#include <stdio.h>
#include <usb.h>
main(){
struct usb_bus *bus;
struct usb_device *dev;
usb_init();
usb_find_busses();
usb_find_devices();
for (bus = usb_busses; bus; bus = bus->next)
for (dev = bus->devices; dev; dev = dev->next){
printf("Trying device %s/%s\n", bus->dirname, dev->filename);
printf("\tID_VENDOR = 0x%04x\n", dev->descriptor.idVendor);
printf("\tID_PRODUCT = 0x%04x\n", dev->descriptor.idProduct);
}
}

the poiter for you is look into libusb library.
starting with libusb_get_device_list which Returns a list of USB devices currently attached to the system.
https://libusb.sourceforge.io/api-1.0/group__libusb__dev.html
you can take it from there.
if you want other way reading /sys/bus/usb/devices directory and read valid devices.
except root hub or other hubs.
EDIT1:
updated link
here is usage
libusb_device **list;
ssize_t cnt = libusb_get_device_list(NULL, &list);
ssize_t i = 0;
if (cnt < 0)
handle_error(); //handle error and return
for (i = 0; i < cnt; i++) {
libusb_device *device = list[i];
// do your work
}
libusb_free_device_list(list, 1);

Related

Capturing YUYV in c++ using v4l2

I have a webcam connected to beaglebone via usb. I am coding in c++ and my goal is to capture raw UNCOMPRESSED picture from the webcam.
Firstly i checked what formats are supported via command v4l2-ctl --list-formats and the result was:
Index : 0
Type : Video Capture
Pixel Format: 'MJPG' (compressed)
Name : Motion-JPEG
Index : 1
Type : Video Capture
Pixel Format: 'YUYV'
Name : YUYV 4:2:2
So from this I assume it has to be possible to get an uncompressed picture if i try to use YUYV format.
Knowing this I started writing a program in c++. I successfully written a program to capture a compressed picture, but when trying to capture using format YUYV it doesnt work and i really need some help to get this done.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <libv4l2.h>
template <typename typeXX>
void clear_memmory(typeXX* x) {
memset(x, 0, sizeof(*x));
}
void xioctl(int cd, int request, void *arg){
int response;
do{
//ensures we get the correct response.
response = v4l2_ioctl(cd, request, arg);
}
while (response == -1 && ((errno == EINTR) || (errno == EAGAIN)));
if (response == -1) {
fprintf(stderr, "error %d, %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
}
struct LMSBBB_buffer{
void* start;
size_t length;
};
int main(){
const char* dev_name = "/dev/video0";
int width=1920;
int height=1080;
int fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
struct v4l2_format format = {0};
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.width = width;
format.fmt.pix.height = height;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;//V4L2_PIX_FMT_YUYV //V4L2_PIX_FMT_RGB24
format.fmt.pix.field = V4L2_FIELD_NONE; //V4L2_FIELD_NONE
xioctl(fd, VIDIOC_S_FMT, &format);
printf("Device initialized.\n");
///request buffers
struct v4l2_requestbuffers req = {0};
req.count = 2;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
xioctl(fd, VIDIOC_REQBUFS, &req);
printf("Buffers requested.\n");
///mapping buffers
struct v4l2_buffer buf;
LMSBBB_buffer* buffers;
unsigned int i;
buffers = (LMSBBB_buffer*) calloc(req.count, sizeof(*buffers));
for (i = 0; i < req.count; i++) {
clear_memmory(&(buf));
(buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
(buf).memory = V4L2_MEMORY_MMAP;
(buf).index = i;
xioctl(fd, VIDIOC_QUERYBUF, &buf);
buffers[i].length = (buf).length;
printf("A buff has a len of: %i\n",buffers[i].length);
buffers[i].start = v4l2_mmap(NULL, (buf).length, PROT_READ | PROT_WRITE, MAP_SHARED,fd, (buf).m.offset);
if (MAP_FAILED == buffers[i].start) {
perror("Can not map the buffers.");
exit(EXIT_FAILURE);
}
}
printf("Buffers mapped.\n");
for (i = 0; i < req.count; i++) {
clear_memmory(&(buf));
(buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
(buf).memory = V4L2_MEMORY_MMAP;
(buf).index = i;
ioctl(fd,VIDIOC_QBUF, &(buf));
}
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd,VIDIOC_STREAMON, &type);
printf("buffers queued and streaming.\n");
int pic_count=0;
///CAPTURE
fd_set fds;
struct timeval tv;
int r;
char out_name[256];
FILE* fout;
do {
FD_ZERO(&fds);
FD_SET(fd, &fds);
// Timeout.
tv.tv_sec = 2;
tv.tv_usec = 0;
r = select(fd + 1, &fds, NULL, NULL, &tv);
} while ((r == -1 && (errno = EINTR)));
if (r == -1) {
perror("select");
exit(EXIT_FAILURE);
}
clear_memmory(&(buf));
(buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
(buf).memory = V4L2_MEMORY_MMAP;
xioctl(fd,VIDIOC_DQBUF, &(buf));
printf("Buff index: %i\n",(buf).index);
sprintf(out_name, "image%03d.ppm",pic_count);
fout = fopen(out_name, "w");
if (!fout) {
perror("Cannot open image");
exit(EXIT_FAILURE);
}
fprintf(fout, "P6\n%d %d 255\n",width, height);
fwrite(buffers[(buf).index].start, (buf).bytesused, 1, fout);
fclose(fout);
pic_count++;
clear_memmory(&(buf));
(buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
(buf).memory = V4L2_MEMORY_MMAP;
xioctl(fd,VIDIOC_DQBUF, &(buf));
printf("Buff index: %i\n",(buf).index);
sprintf(out_name, "image%03d.ppm",pic_count);
fout = fopen(out_name, "w");
if (!fout) {
perror("Cannot open image");
exit(EXIT_FAILURE);
}
fprintf(fout, "P6\n%d %d 255\n",width, height);
fwrite(buffers[(buf).index].start, (buf).bytesused, 1, fout);
fclose(fout);
pic_count++;
///xioctl(fd,VIDIOC_QBUF, &(buf));
return 0;
}
in line 50, i can choose the format between V4L2_PIX_FMT_YUYV and V4L2_PIX_FMT_RGB24.
for V4L2_PIX_FMT_RGB24 i get the picture, but when using V4L2_PIX_FMT_YUYV I get this error:
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
the error lines goes for ever until i end the program manually.
Does anyone have an idea what to do? I spent over 2 weeks on this and i can't move anywhere from here. I would really appreciate any advice.
From what I see you are requesting a FullHD (1920x1080) buffer in YUYV format from a camera. You did not mention the camera type/model/specs, but if it is a generic USB-attached hardware most likely you will not get a raw FullHD YUYV buffer as an output, only the MJPEG one (which you can decode to YUV, if you hack around with libjpeg) or the decoded RGB buffer (which is pretty much the decoded MJPEG with YUV->RGB conversion) which is not mmapped.
The exact list of formats with framerates can be requested by this command, which would probably tell you it does not provide a 1920x1080 YUYV, only something smaller, like 640x480:
v4l2-ctl --list-formats
If you need video processing with "true" zero-copy access to raw YUYV camera frames, you need direct access to hardware and that specific hardware in the first place. Once you have the USB interface between your software and the camera, you get an extra indirection and that means the speed goes down. Think for a moment, the YUYV frame at 1920x1080 takes up approximately 4 Megabytes of memory. At 30 FPS this is 120 Megabytes (or 960 Megabits) per second of bus throughput. If you have a USB2.0 camera, there is just no bandwidth to support this (thus the need for MJPEG). Even at 15FPS this is 480 Megabits, not counting the USB latency and protocol overhead.
To provide some "actionable feedback" I would advice to first concentrate on the algorithms (probably, you just don't want to loose the processing speed at the very first step) which you want to apply to the image. Don't hesitate to use OpenCV for camera input and basic image processing, later you can switch to some hardware interface and hand-written algorithms.
The easier way of getting raw frames would be to use Android's camera interface and try to process the incoming frames with GLSL shaders using the GL_TEXTURE_EXTERNAL_OES extension, about which there information and code samples available. There you can connect GL textures to AHardwareBuffer instances and then use AHardwareBuffer_lock function to get raw pointers. The exact supported formats also may vary across the hardware, so do not expect this to be super-easy.
I've recently had a similar issue. In my case the camera driver needed the VIDIOC_S_PARM ioctl in order to set the frame rate and initialize the camera for the selected capture mode.
You can try to add this code after the VIDIOC_S_FMT and see if it works for you as well:
struct v4l2_streamparm streamparam;
memset(&streamparam, 0, sizeof(streamparam));
streamparam.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(fd, VIDIOC_G_PARM, &streamparam);
streamparam.parm.capture.timeperframe.numerator = 1;
streamparam.parm.capture.timeperframe.denominator = 5;
xioctl(fd, VIDIOC_S_PARM, &streamparam);

Linux C++ LibUSB Write Register in USB HUB

In Linux, I have a USB hub with the 'register' shown in the image below. This register is supposed to disable power on a certain port on the hub.
I tried to use LibUSB ( my code is shown below ) to write the register, 0x0A, with all zeros to disable all ports. The problem is, the hub is controlled by the standard Linux USB Hub driver and so the Kernel driver is detached. The write also fails. The failure messages are shown below.
Error messages:
$ /mnt/apps/UsbPowerControl
5 Devices in list.
Vendor:Device = 1908:1320
Vendor:Device = 0403:6001
Vendor:Device = 289d:0010
Vendor:Device = 0424:2513
Vendor:Device = 1d6b:0002
Opening Device = 0424:2513
Device Opened
Kernel Driver Active
Kernel Driver Detached!
Claimed Interface
Data-><-
Writing Data...
libusb: error [submit_bulk_transfer] submiturb failed error -1 errno=2
Write Error
Released Interface
How can I use LibUSB to write this Hub register, to dynamically disable and enable the ports, without unregistering the Linux driver and having my write fail?
#include <iostream>
#include <cassert>
#include <libusb-1.0/libusb.h>
using namespace std;
#define VENDOR_ID 0x0424
#define PRODUCT_ID 0x2513
int main() {
libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices
libusb_device_handle *dev_handle; //a device handle
libusb_context *ctx = NULL; //a libusb session
int r; //for return values
ssize_t cnt; //holding number of devices in list
r = libusb_init(&ctx); //initialize the library for the session we just declared
if(r < 0) {
cout<<"Init Error "<<r<<endl; //there was an error
return 1;
}
libusb_set_debug(ctx, 3); //set verbosity level to 3, as suggested in the documentation
cnt = libusb_get_device_list(ctx, &devs); //get the list of devices
if(cnt < 0) {
cout<<"Get Device Error"<<endl; //there was an error
return 1;
}
cout<<cnt<<" Devices in list."<<endl;
for (size_t idx = 0; idx < cnt; ++idx) {
libusb_device *device = devs[idx];
libusb_device_descriptor desc = {0};
int rc = libusb_get_device_descriptor(device, &desc);
assert(rc == 0);
printf("Vendor:Device = %04x:%04x\n", desc.idVendor, desc.idProduct);
}
printf("Opening Device = %04x:%04x\n", VENDOR_ID, PRODUCT_ID);
dev_handle = libusb_open_device_with_vid_pid(ctx, VENDOR_ID, PRODUCT_ID); //these are vendorID and productID I found for my usb device
if(dev_handle == NULL)
cout<<"Cannot open device"<<endl;
else
cout<<"Device Opened"<<endl;
libusb_free_device_list(devs, 1); //free the list, unref the devices in it
unsigned char *data = new unsigned char[1]; //data to write
data[0]=0b00000000;
int actual; //used to find out how many bytes were written
if(libusb_kernel_driver_active(dev_handle, 0) == 1) { //find out if kernel driver is attached
cout<<"Kernel Driver Active"<<endl;
if(libusb_detach_kernel_driver(dev_handle, 0) == 0) //detach it
cout<<"Kernel Driver Detached!"<<endl;
}
r = libusb_claim_interface(dev_handle, 0); //claim interface 0 (the first) of device (mine had jsut 1)
if(r < 0) {
cout<<"Cannot Claim Interface"<<endl;
return 1;
}
cout<<"Claimed Interface"<<endl;
cout<<"Data->"<<data<<"<-"<<endl; //just to see the data we want to write : abcd
cout<<"Writing Data..."<<endl;
r = libusb_bulk_transfer(dev_handle, (0x0A | LIBUSB_ENDPOINT_OUT), data, 1, &actual, 0); //my device's out endpoint was 2, found with trial- the device had 2 endpoints: 2 and 129
if(r == 0 && actual == 1) //we wrote the 1 bytes successfully
cout<<"Writing Successful!"<<endl;
else
cout<<"Write Error"<<endl;
r = libusb_release_interface(dev_handle, 0); //release the claimed interface
if(r!=0) {
cout<<"Cannot Release Interface"<<endl;
return 1;
}
cout<<"Released Interface"<<endl;
libusb_close(dev_handle); //close the device we opened
libusb_exit(ctx); //needs to be called to end the
delete[] data; //delete the allocated memory for data
return 0;
}
int libusb_detach_kernel_driver ( libusb_device_handle * dev,
int interface_number
)
...
If successful, you will then be able to claim the interface and perform I/O.
...
int libusb_kernel_driver_active ( libusb_device_handle * dev,
int interface_number
)
...
If a kernel driver is active, you cannot claim the interface, and libusb will be unable to perform I/O.
...
Due to what is written above, the short answer to the question "How to do I/O without detaching driver" is "You can't".
Why write fails? This is another matter. I'd suggest looking into a number of things:
Check out the value returned from libusb_bulk_transfer, maybe it will give you the idea of what is happening.
Sounds stupid, but I always check it out before anything else: process privileges.
Also, I can suggest another way of approaching the solution, namely sysfs.
I assume that your device(am I right?) supports EEPROM and SMBus access. It means that this support should be manifested in the kernel somewhere around /sys/bus/i2c/devices/[some_device_id]/eeprom (probably another device number, another directory position, etc, because it is all driver-related), but if it can be found and read just as any other file (which is likely, unless something is wrong with the device), then it probably should be able to write into it as well. If the read works, then I suggest to compare the hexdump -C of the found file to the datasheet, and if the data seems legit, try writing directly into your register(file offset).
Anyway, accessing character device files and sysfs files is a general way of accessing drivers' data in linux. Probably you don't even need to use libusb's API to write that single byte.

Send cmd to SD card but error 22 on Linux

I refer an article:
Any way to send commands to SD card from Linux userspace?
and use the source of mmc-util to send cmd to SD card, there is the code:
int cmd_test(int fd, __u8 *ext_csd)
{
int ret = 0;
struct mmc_ioc_cmd idata;
memset(&idata, 0, sizeof(idata));
memset(ext_csd, 0, sizeof(__u8) * 512);
idata.write_flag = 0;
idata.opcode = 17;
idata.arg = 0;
idata.flags = MMC_DATA_READ;
idata.blksz = 512;
idata.blocks = 1;
mmc_ioc_cmd_set_data(idata, ext_csd);
ret = ioctl(fd, MMC_IOC_CMD, &idata);
if (ret)
perror("ioctl");
return ret;
}
finally receive error 22: invalid argument. I try another opcode like 10, 56..., it finally result same error.
The SD card is connected by usb reader, does it cause the error? or there are parameter setting error?
Thanks.

How to use libusb and libusb_get_device_descriptor()?

I'm learning to use libusb v1.0.0 for the first time on Ubuntu 12.10. Here is some small test code I'm using to try and understand how to use this API:
#include <libusb-1.0/libusb.h>
...
libusb_device **list;
libusb_get_device_list(ctx, &list); // Returns 11 USB devices which is correct.
for (size_t idx = 0; list[idx] != NULL; idx ++)
{
libusb_device *dev = list[idx];
libusb_device_descriptor desc = {0};
int rc = libusb_get_device_descriptor(dev, &desc);
At this point, rc == 0, meaning it should have completed successfully. Source: documentation for *libusb_get_device_descriptor()*.
But the structure desc is always empty. None of the fields ever get set. If I change the last two lines above to this:
libusb_device_descriptor desc = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int rc = libusb_get_device_descriptor(dev, &desc);
...then when libusb_get_device_descriptor() returns, I see desc remains unchanged, confirming for me that I'm not getting what I expect from this API.
I've also tried to run a.out as root just in case this requires elevated privileges. Doing a Google search on libusb_get_device_descriptor hasn't gotten me anywhere.
Relevant commands I ran to try this code:
sudo apt-get install libusb-1.0.0-dev
g++ -ggdb test.cpp -lusb-1.0
./a.out
Ah! Crazy user error! sharth's code helped me figure it out. Here is the code I was actually using -- see if you can spot the error:
std::cout << "rc == " << libusb_get_device_descriptor(dev, &desc) << std::endl
<< "vendor == " << desc.idVendor << std::endl;
I guess the way the compiler evaluates this, it is free to evaluate desc.idVendor before the call to libusb_get_device_descriptor() has actually been made. My bad.
You didn't include a full, compilable test case. So I built one. This works for me on CentOS 6 x64. I'm also running this as a normal user account.
Source
#include <cassert>
#include <cstdio>
#include <libusb-1.0/libusb.h>
int main() {
libusb_context *context = NULL;
libusb_device **list = NULL;
int rc = 0;
ssize_t count = 0;
rc = libusb_init(&context);
assert(rc == 0);
count = libusb_get_device_list(context, &list);
assert(count > 0);
for (size_t idx = 0; idx < count; ++idx) {
libusb_device *device = list[idx];
libusb_device_descriptor desc = {0};
rc = libusb_get_device_descriptor(device, &desc);
assert(rc == 0);
printf("Vendor:Device = %04x:%04x\n", desc.idVendor, desc.idProduct);
}
libusb_free_device_list(list, count);
libusb_exit(context);
}
Output
Vendor:Device = 1d6b:0002
Vendor:Device = 1d6b:0002
Vendor:Device = 8087:0020
Vendor:Device = 8087:0020
Vendor:Device = 0424:2514
Vendor:Device = 10c4:ea60
Vendor:Device = 051d:0002
Vendor:Device = 0624:0248
This is not an standalone answer, it's more a comment to Bill Lynch's post. I'm not able to add a comment to Bill Lynch's post (missing reputation) so I decided to do it this way ;-).
There's a little detail missing in the code above:
you have to free the list you got filled from libusb_get_device_list by hand.
From the libusb docu:
You are expected to unreference all the devices when you are done with them, and then free the list with libusb_free_device_list(). Note that libusb_free_device_list() can unref all the devices for you. Be careful not to unreference a device you are about to open until after you have opened it.
Just to add to Bill's answer, to avoid the multiple warnings you will likely recieve from this line
libusb_device_descriptor desc = {0};
Simply remove the assignment.
libusb_device_descriptor desc;
Not a huge deal, but these things bother me.

Winpcap saving raw packets not from an adapter

I am trying to build an application that converts my old custom Ethernet logs (bin files) to standard winpcap style logs.
The problem is that I can't seem to find an example of how to opening a pcap_t* without using an adapter (network card). The temp.pkt has not been created.
I have looked thou the examples provided with Winpcap and all of them use a live adapter when dumping packets. This example is the closest \WpdPack\Examples-pcap\savedump\savedump.c is the closest, see example below slightly modified.
#ifdef _MSC_VER
/*
* we do not want the warnings about the old deprecated and unsecure CRT functions
* since these examples can be compiled under *nix as well
*/
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "pcap.h"
int main(int argc, char **argv)
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_dumper_t *dumpfile;
/* Open the adapter */
if ((adhandle= pcap_open(??????, // name of the device
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
1, // promiscuous mode (nonzero means promiscuous)
1000, // read timeout
errbuf // error buffer
)) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
/* Open the dump file */
dumpfile = pcap_dump_open(adhandle, argv[1]);
if(dumpfile==NULL) {
fprintf(stderr,"\nError opening output file\n");
return -1;
}
// ---------------------------
struct pcap_pkthdr header;
header.ts.tv_sec = 1 ; /* seconds */
header.ts.tv_usec = 1; /* and microseconds */
header.caplen = 100; /* length of portion present */
header.len = 100 ; /* length this packet (off wire) */
u_char pkt_data[100];
for( int i = 0 ; i < 100 ; i++ ) {
pkt_data[i] = i ;
}
pcap_dump( (u_char *) dumpfile, &header, (u_char *) &pkt_data);
// ---------------------------
/* start the capture */
// pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);
pcap_close(adhandle);
return 0;
}
I suggest doing that using pcap_t since using WinPcap is better than writing it yourself.
The following steps is how to do it:
Use pcap_open_dead() function to create a pcap_t. Read the function description here. The linktype for Ethernet is 1.
Use pcap_dump_open() function to create a pcap_dumper_t.
Use pcap_dump() function to write the packet to the dump file.
I hope this would help you.
If all you're doing is converting your own file format to .pcap, you don't need a pcap_t*, you can just use something like:
FILE* create_pcap_file(const char *filename, int linktype)
{
struct pcap_file_header fh;
fh.magic = TCPDUMP_MAGIC;
fh.sigfigs = 0;
fh.version_major = 2;
fh.version_minor = 4;
fh.snaplen = 2<<15;
fh.thiszone = 0;
fh.linktype = linktype;
FILE *file = fopen(filename, "wb");
if(file != NULL) {
if(fwrite(&fh, sizeof(fh), 1, file) != 1) {
fclose(file);
file = NULL;
}
}
return file;
}
int write_pcap_packet(FILE* file,size_t length,const unsigned char *data,const struct timeval *tval)
{
struct pcap_pkthdr pkhdr;
pkhdr.caplen = length;
pkhdr.len = length;
pkhdr.ts = *tval;
if(fwrite(&pkhdr, sizeof(pkhdr), 1, file) != 1) {
return 1;
}
if(fwrite(data, 1, length, file) != length) {
return 2;
}
return 0;
}