read from a USB barcode scanner that simulates a keyboard
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
read from a USB barcode scanner that simulates a keyboard
I have a USB barcode scanner that acts like a keyboard: whenever a barcode is read it sends the code where the keyboard would normally write. I would like to write some code (preferably in C) to modify this behavior and to be able to listen to the scanner from a program, just like I would read from a socket or a serial port for instance.
I am writing code to control a robot, the barcode scanner is used for localization. So I need the control code to be able to listen to the scanner.
Maybe you don't know the solution but can give some ideas that would put me on the way. I have the feeling that I could use the ioctl function, but I am not familiar with the underlying concepts, and it's a pretty complex function.
Maybe you could have a look at phidgets - these are usb devices for controlling and sensing various things. Lots of robotics applications. Anyway they have libraries in C, C#, VB and others, that you could look at the source of to see how they talk through the usb bus. There's sure to be a way to define a particular device (all devices are defined by a vendor:device identifier so can be specifically targeted) and to stop the keyboard driver from using it.
Phidgets are here: http://www.phidgets.com/index.php
There was a similar thread, which had never received any answer. http://www.linuxquestions.org/questi...errerid=260969
So I posted the topic again here hoping I would get more chance (and I did, thanks bernied), but in the meantime I contacted this guy to see if he had managed to find a solution. Here is the answer he kindly gave me. I post it here for reference:
They normally configure as a keyboard, though in Linux, by default, some of the COM ports may not be accessible. Add "8250.nr_uarts=8" to the end of your kernel line to have it configure past COM4.
I.E.: kernel /boot/vmlinuz-2.6.15-1.2054_FC5 ro root=LABEL=/ 8250.nr_uarts=8
If you cat /dev/ttySX (X is the number of the COM port you want to listen to) and scan something, you should see input.
If it's a USB scanner, they seem to always configure as a USB keyboard.
I am going to work on those two ideas, and post my results here. In the meantime, more suggestions are welcome.
I managed to read from the USB barcode scanner using libhid. However I have the feeling that there should be some way to redirect whatever comes from that barcode to a file without using libhid. My ultimate goal is to redirect it to a FIFO (/dev/rtfX).
What MardukKurios (the guy I quoted in previous post) suggested sounds like a good idea, but unfortunately 8250.nr_uarts is not an option recognized by my kernel.
However, this suggests that what I want to do should be possible. I've always thought that the main advantage of Linux is that everything is possible, provided that you have enough knowledge.
Does anybody here has enough knowledge to help me? At least some ideas I could start with.
PS: dmesg shows this
usb 2-1: new full speed USB device using uhci_hcd and address 3
input: � Symbol Technologies, Inc, 2000 Symbol Bar Code Scanner as /class/input/input3
input: USB HID v1.10 Keyboard [� Symbol Technologies, Inc, 2000 Symbol Bar Code Scanner ] on usb-0000:00:1d.0-1
read from a USB barcode scanner that simulates a keyboard
Quote:
Originally Posted by bricedebrignaisplage
I managed to read from the USB barcode scanner using libhid. However I have the feeling that there should be some way to redirect whatever comes from that barcode to a file without using libhid. My ultimate goal is to redirect it to a FIFO (/dev/rtfX).
What MardukKurios (the guy I quoted in previous post) suggested sounds like a good idea, but unfortunately 8250.nr_uarts is not an option recognized by my kernel.
However, this suggests that what I want to do should be possible. I've always thought that the main advantage of Linux is that everything is possible, provided that you have enough knowledge.
Does anybody here has enough knowledge to help me? At least some ideas I could start with.
PS: dmesg shows this
usb 2-1: new full speed USB device using uhci_hcd and address 3
input: � Symbol Technologies, Inc, 2000 Symbol Bar Code Scanner as /class/input/input3
input: USB HID v1.10 Keyboard [� Symbol Technologies, Inc, 2000 Symbol Bar Code Scanner ] on usb-0000:00:1d.0-1
Hi,
I am also facing the same problem using a usb device which simulates keyboard types. I am able to get the device information like (vendor name, product name etc.) using libhid. But I am facing problem in reading the output from the usb-device. it is simply sending the reads to the cursor location of the native terminal.
As you solved this problem and able to read the usb device using libhid, could you please give me a guide or send me a sample code to me. my email id is dhrubajyoti.deka@gmail.com .
I am no longer using libusb/libhid, but I am using the input layer of the kernel instead. The idea is to read from the /dev/input/event device associated with your device. To know which /dev/input/event node is associated with my device, I open all of them, get vendor ID and product ID and compare. If you don't have /dev/input, you must enable it in your kernel.
Btw, I got all this information from Vojtech Pavlik, the guy who wrote the input layer of the kernel.
I haven't found how to deal with capital letter though (shift key), and not all characters are in my conversion table... but that should get you started.
Here is my code:
Code:
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#define VENDORID 0x5e0
#define PRODUCTID 0x200
int scan_fd = -1;
int initScanner(){
int count=0;
char path[32];
struct dirent **files=NULL;
struct input_id id;
count = scandir("/dev/input",&files,0,0);
while( count>=0 ){
if( scan_fd==-1 && strncmp(files[count]->d_name,"event",5)==0 ){
sprintf(path,"/dev/input/%s",files[count]->d_name);
scan_fd = open(path,O_RDONLY);
if( scan_fd>=0 ){
if( ioctl(scan_fd,EVIOCGID,(void *)&id)<0 ) perror("ioctl EVIOCGID");
else{
if( id.vendor==VENDORID && id.product==PRODUCTID )
printf("scanner attached to %s\n",path);
else{
close(scan_fd);
scan_fd = -1;
}
}
}
else{
fprintf(stderr,"Error opening %s",path);
perror("");
}
}
free(files[count--]);
}
free(files);
if( scan_fd>=0 ) ioctl(scan_fd,EVIOCGRAB);
else{ printf("scanner not found or couldn't be opened\n"); return 0;}
return 1;
}
int closeScanner(){
close(scan_fd);
scan_fd = -1;
return 1;
}
char keycodelist(int scancode){
char ret = '-';
return (unsigned char)scancode;
switch(scancode){
case 0x02: ret ='1';break;
case 0x03: ret ='2';break;
case 0x04: ret ='3';break;
case 0x05: ret ='4';break;
case 0x06: ret ='5';break;
case 0x07: ret ='6';break;
case 0x08: ret ='7';break;
case 0x09: ret ='8';break;
case 0x0a: ret ='9';break;
case 0x0b: ret ='0';break;
case 0x0c: ret ='-';break;
case 0x10: ret ='q';break;
case 0x11: ret ='w';break;
case 0x12: ret ='e';break;
case 0x13: ret ='r';break;
case 0x14: ret ='t';break;
case 0x15: ret ='y';break;
case 0x16: ret ='u';break;
case 0x17: ret ='i';break;
case 0x18: ret ='o';break;
case 0x19: ret ='p';break;
case 0x1e: ret ='a';break;
case 0x1f: ret ='s';break;
case 0x20: ret ='d';break;
case 0x21: ret ='f';break;
case 0x22: ret ='g';break;
case 0x23: ret ='h';break;
case 0x24: ret ='j';break;
case 0x25: ret ='k';break;
case 0x26: ret ='l';break;
case 0x2c: ret ='z';break;
case 0x2d: ret ='x';break;
case 0x2e: ret ='c';break;
case 0x2f: ret ='v';break;
case 0x30: ret ='b';break;
case 0x31: ret ='n';break;
case 0x32: ret ='m';break;
default: break;
}
return ret;
}
//read a barcode from the scanner.
//reads as long as *loopcond!=0 (if loopcond is NULL then read
//forever). If termination condition is met, returns NULL.
//read all characters from barcode untill we read 0x28 (carriage
//return).
char* readScanner(int *loopcond){
static char barcode[SCN_BCD_SZ];
char code[SCN_BCD_SZ];
int i=0;
struct input_event ev;
while( loopcond==NULL?1:*loopcond ){
read(scan_fd,&ev,sizeof(struct input_event));
if( ev.type==1 && ev.value==1 ){
if( ev.code==28 ){ //carriage return
code[i] = 0;
strcpy(barcode,code);
return barcode;
}
else{
if( ev.code!=0 ){
code[i++] = keycodelist(ev.code);
if( i==SCN_BCD_SZ-1 ){ printf("Barcode buffer full\n"); return NULL;}
}
}
}
}
return NULL;
}
I am no longer using libusb/libhid, but I am using the input layer of the kernel instead. The idea is to read from the /dev/input/event device associated with your device. To know which /dev/input/event node is associated with my device, I open all of them, get vendor ID and product ID and compare. If you don't have /dev/input, you must enable it in your kernel.
Btw, I got all this information from Vojtech Pavlik, the guy who wrote the input layer of the kernel.
I haven't found how to deal with capital letter though (shift key), and not all characters are in my conversion table... but that should get you started.
Here is my code:
Code:
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#define VENDORID 0x5e0
#define PRODUCTID 0x200
int scan_fd = -1;
int initScanner(){
int count=0;
char path[32];
struct dirent **files=NULL;
struct input_id id;
count = scandir("/dev/input",&files,0,0);
while( count>=0 ){
if( scan_fd==-1 && strncmp(files[count]->d_name,"event",5)==0 ){
sprintf(path,"/dev/input/%s",files[count]->d_name);
scan_fd = open(path,O_RDONLY);
if( scan_fd>=0 ){
if( ioctl(scan_fd,EVIOCGID,(void *)&id)<0 ) perror("ioctl EVIOCGID");
else{
if( id.vendor==VENDORID && id.product==PRODUCTID )
printf("scanner attached to %s\n",path);
else{
close(scan_fd);
scan_fd = -1;
}
}
}
else{
fprintf(stderr,"Error opening %s",path);
perror("");
}
}
free(files[count--]);
}
free(files);
if( scan_fd>=0 ) ioctl(scan_fd,EVIOCGRAB);
else{ printf("scanner not found or couldn't be opened\n"); return 0;}
return 1;
}
int closeScanner(){
close(scan_fd);
scan_fd = -1;
return 1;
}
char keycodelist(int scancode){
char ret = '-';
return (unsigned char)scancode;
switch(scancode){
case 0x02: ret ='1';break;
case 0x03: ret ='2';break;
case 0x04: ret ='3';break;
case 0x05: ret ='4';break;
case 0x06: ret ='5';break;
case 0x07: ret ='6';break;
case 0x08: ret ='7';break;
case 0x09: ret ='8';break;
case 0x0a: ret ='9';break;
case 0x0b: ret ='0';break;
case 0x0c: ret ='-';break;
case 0x10: ret ='q';break;
case 0x11: ret ='w';break;
case 0x12: ret ='e';break;
case 0x13: ret ='r';break;
case 0x14: ret ='t';break;
case 0x15: ret ='y';break;
case 0x16: ret ='u';break;
case 0x17: ret ='i';break;
case 0x18: ret ='o';break;
case 0x19: ret ='p';break;
case 0x1e: ret ='a';break;
case 0x1f: ret ='s';break;
case 0x20: ret ='d';break;
case 0x21: ret ='f';break;
case 0x22: ret ='g';break;
case 0x23: ret ='h';break;
case 0x24: ret ='j';break;
case 0x25: ret ='k';break;
case 0x26: ret ='l';break;
case 0x2c: ret ='z';break;
case 0x2d: ret ='x';break;
case 0x2e: ret ='c';break;
case 0x2f: ret ='v';break;
case 0x30: ret ='b';break;
case 0x31: ret ='n';break;
case 0x32: ret ='m';break;
default: break;
}
return ret;
}
//read a barcode from the scanner.
//reads as long as *loopcond!=0 (if loopcond is NULL then read
//forever). If termination condition is met, returns NULL.
//read all characters from barcode untill we read 0x28 (carriage
//return).
char* readScanner(int *loopcond){
static char barcode[SCN_BCD_SZ];
char code[SCN_BCD_SZ];
int i=0;
struct input_event ev;
while( loopcond==NULL?1:*loopcond ){
read(scan_fd,&ev,sizeof(struct input_event));
if( ev.type==1 && ev.value==1 ){
if( ev.code==28 ){ //carriage return
code[i] = 0;
strcpy(barcode,code);
return barcode;
}
else{
if( ev.code!=0 ){
code[i++] = keycodelist(ev.code);
if( i==SCN_BCD_SZ-1 ){ printf("Barcode buffer full\n"); return NULL;}
}
}
}
}
return NULL;
}
Hi..
Thank a lot pls can you help where exactly i need to insert this code to read from barcode scanner?
Thanks a lot..I have done the changes already...your code and explanation really helped me....thanks a lot again....
Please can you help me ..Now my problem is how to detect the device when it is inserted or removed. Becuase once i remove the device and if i insert again new event is assigned to the device.
Please can you help me how to detect device of it is insertion and removal?
An idea would be to detect when device is removed as when a reading error occurs. Then you would have to call initialize() again, which will scan the devices again to find your scanner.
if( scan_fd>=0 ) ioctl(scan_fd,EVIOCGRAB);
else{ printf("scanner not found or couldn't be opened\n"); return 0;}
return 1;
}
int closeScanner(){
close(scan_fd);
scan_fd = -1;
return 1;
}
char keycodelist(int scancode){
char ret = '-';
//return (unsigned char)scancode;
switch(scancode){
case 0x02: ret ='1';break;
case 0x03: ret ='2';break;
case 0x04: ret ='3';break;
case 0x05: ret ='4';break;
case 0x06: ret ='5';break;
case 0x07: ret ='6';break;
case 0x08: ret ='7';break;
case 0x09: ret ='8';break;
case 0x0a: ret ='9';break;
case 0x0b: ret ='0';break;
case 0x0c: ret ='-';break;
case 0x10: ret ='q';break;
case 0x11: ret ='w';break;
case 0x12: ret ='e';break;
case 0x13: ret ='r';break;
case 0x14: ret ='t';break;
case 0x15: ret ='y';break;
case 0x16: ret ='u';break;
case 0x17: ret ='i';break;
case 0x18: ret ='o';break;
case 0x19: ret ='p';break;
case 0x1e: ret ='a';break;
case 0x1f: ret ='s';break;
case 0x20: ret ='d';break;
case 0x21: ret ='f';break;
case 0x22: ret ='g';break;
case 0x23: ret ='h';break;
case 0x24: ret ='j';break;
case 0x25: ret ='k';break;
case 0x26: ret ='l';break;
case 0x2c: ret ='z';break;
case 0x2d: ret ='x';break;
case 0x2e: ret ='c';break;
case 0x2f: ret ='v';break;
case 0x30: ret ='b';break;
case 0x31: ret ='n';break;
case 0x32: ret ='m';break;
default: break;
}
return ret;
}
//read a barcode from the scanner.
//reads as long as *loopcond!=0 (if loopcond is NULL then read
//forever). If termination condition is met, returns NULL.
//read all characters from barcode untill we read 0x28 (carriage
//return).
char* readScanner(int *loopcond){
static char barcode[SCN_BCD_SZ];
char code[SCN_BCD_SZ];
int i=0;
struct input_event ev;
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.