Closed RadhiFadlillah closed 6 years ago
Since my barcode scanner doesn't work when using KeyboardReportParser
, I've decide to create my own parser. Here is my first parser's code :
#include <usbhid.h>
#include <usbhub.h>
#include <hiduniversal.h>
#include <SPI.h>
class MyParser : public HIDReportParser {
public:
MyParser();
void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};
MyParser::MyParser() {}
void MyParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
Serial.println(*buf);
}
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
MyParser Parser;
void setup() {
Serial.begin( 115200 );
Serial.println("Start");
if (Usb.Init() == -1)
Serial.println("OSC did not start.");
delay( 200 );
Hid.SetReportParser(0, &Parser);
}
void loop() {
Usb.Task();
}
When I try it on my barcode :
my code gives following result :
Start
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
Well, it obviously doesn't work, but at least there are some kind of event that detected by my parser, so maybe I'm in right direction.
After looking around the hidboot.cpp
and hidboot.h
, I've updated my code into this :
#include <usbhid.h>
#include <usbhub.h>
#include <hiduniversal.h>
#include <SPI.h>
class MyParser : public HIDReportParser {
public:
MyParser();
void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};
MyParser::MyParser() {}
void MyParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
// If error, return
// I don't know why it starts on 2, I just following the example
if (buf[2] == 1) return;
// If empty, return
// I check on 2 because the previous if check on 2 too
if (buf[2] == 0) return;
// Like above, WHY it starts on 2 ?
// What is the purpose of bit in 0 and 1 ?
for (uint8_t i = 2; i < 8; i++) {
Serial.print(buf[i]);
Serial.print(" ");
}
Serial.println();
}
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
MyParser Parser;
void setup() {
Serial.begin( 115200 );
Serial.println("Start");
if (Usb.Init() == -1)
Serial.println("OSC did not start.");
delay( 200 );
Hid.SetReportParser(0, &Parser);
}
void loop() {
Usb.Task();
}
I've tested this code on three barcode with following content :
For all numbers, I use barcode with value 1234567890
and got following result :
30 0 0 0 0 0 => 1
31 0 0 0 0 0 => 2
32 0 0 0 0 0 => 3
33 0 0 0 0 0 => 4
34 0 0 0 0 0 => 5
35 0 0 0 0 0 => 6
36 0 0 0 0 0 => 7
37 0 0 0 0 0 => 8
38 0 0 0 0 0 => 9
39 0 0 0 0 0 => 0
40 0 0 0 0 0 => Enter ?
For uppercase letters, I use value ABCDEFGH
with following result :
225 4 0 0 0 0 => A
225 5 0 0 0 0 => B
225 6 0 0 0 0 => C
225 7 0 0 0 0 => D
225 8 0 0 0 0 => E
225 9 0 0 0 0 => F
225 10 0 0 0 0 => G
225 11 0 0 0 0 => H
40 0 0 0 0 0 => Enter
And last, for lowercase letters, I use abcdefgh
with following result :
4 0 0 0 0 0 => a
5 0 0 0 0 0 => b
6 0 0 0 0 0 => c
7 0 0 0 0 0 => d
8 0 0 0 0 0 => e
9 0 0 0 0 0 => f
10 0 0 0 0 0 => g
11 0 0 0 0 0 => h
40 0 0 0 0 0 => Enter ?
So, now my code can read the value for number, letter and enter signal. All I have to do now is to translate that from value into ASCII. It's quite interesting to see that uppercase and lowercase letters has same value, but different bit position.
Alright guys, it works now. I just have to modify the OemToAscii
to satisfy my need. Here is my final code :
#include <usbhid.h>
#include <usbhub.h>
#include <hiduniversal.h>
#include <hidboot.h>
#include <SPI.h>
class MyParser : public HIDReportParser {
public:
MyParser();
void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
protected:
uint8_t KeyToAscii(bool upper, uint8_t mod, uint8_t key);
virtual void OnKeyScanned(bool upper, uint8_t mod, uint8_t key);
virtual void OnScanFinished();
};
MyParser::MyParser() {}
void MyParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
// If error or empty, return
if (buf[2] == 1 || buf[2] == 0) return;
for (uint8_t i = 7; i >= 2; i--) {
// If empty, skip
if (buf[i] == 0) continue;
// If enter signal emitted, scan finished
if (buf[i] == UHS_HID_BOOT_KEY_ENTER) {
OnScanFinished();
}
// If not, continue normally
else {
// If bit position not in 2, it's uppercase words
OnKeyScanned(i > 2, buf, buf[i]);
}
return;
}
}
uint8_t MyParser::KeyToAscii(bool upper, uint8_t mod, uint8_t key) {
// Letters
if (VALUE_WITHIN(key, 0x04, 0x1d)) {
if (upper) return (key - 4 + 'A');
else return (key - 4 + 'a');
}
// Numbers
else if (VALUE_WITHIN(key, 0x1e, 0x27)) {
return ((key == UHS_HID_BOOT_KEY_ZERO) ? '0' : key - 0x1e + '1');
}
return 0;
}
void MyParser::OnKeyScanned(bool upper, uint8_t mod, uint8_t key) {
uint8_t ascii = KeyToAscii(upper, mod, key);
Serial.print((char)ascii);
}
void MyParser::OnScanFinished() {
Serial.println(" - Finished");
}
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
MyParser Parser;
void setup() {
Serial.begin( 115200 );
Serial.println("Start");
if (Usb.Init() == -1) {
Serial.println("OSC did not start.");
}
delay( 200 );
Hid.SetReportParser(0, &Parser);
}
void loop() {
Usb.Task();
}
Now that it's done, the code looks really simple. I guess it took me so long because I never use C or C++ before, which make me a bit confused about pointer, bits and bytes.
Before I close this issue, I have several questions to ask. While I'm making this parser, I've tried this code :
void MyParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
for (uint8_t i = 0; i < 8; i++) {
Serial.print(buf[i]);
Serial.print(" ");
}
}
When I use this code to scan barcode with letter A
on it, it gives following result :
0 0 225 4 0 0 0 0
My questions are :
Why the bit value only started and checked from index 2 ? What is the purpose of bit in index 0 and 1 ? Are they always empty ?
According to this blog, uint8_t
data type is basically the same as byte
in Arduino. Both of them is used to store an 8-bit unsigned number, from 0 to 255. So, when I loop through a variable with data type uint8_t
or byte
, I should get the bit value on index 0 to 7. Now, I know that bit is only 1 and 0. So, why that loop print value 225 and 4 ? Or maybe I'm misunderstanding the purpose of that loop ?
Well, that's all. Thank you.
Great work man.. It helped a lot..
Thank you very much.
@RadhiFadlillah thanks for sharing.
Regarding the code you posted. It simply just prints the raw incoming bytes, which are specific to your device. You never posted the model of barcode scanner you are using, so I can't look up the specification.
Also you are mixing up the terms bits and bytes. Remember that a byte consist of 8-bits and in your code you are printing 8 bytes. I'm not sure if that answers your questions?
@krushnaR you're welcome, I'm glad it solved your problem.
@Lauszus thanks for your response.
You never posted the model of barcode scanner you are using, so I can't look up the specification.
I'm sorry about that. Unfortunately, my barcode scanner is a brandless, chinese product that I bought dirt cheap from my local seller, that's why I don't know what is the model of my barcode scanner.
Also you are mixing up the terms bits and bytes.
LOL yeah that's true. Next time, I should take a rest before submitting my question.
LOL yeah that's true. Next time, I should take a rest before submitting my question.
Haha no worries, we have all been there :)
Your code is fantastic. Could you please tell me where is the data being stored when scanned through the barcode scanner, I'm asking this because I want to write the serial to a text file.
@SaadatKhan26 Simply store the data in the Parse
function. For instance you could write to a SD card like so:
for (uint8_t i = 0; i < 8; i++) {
file.print(buf[i]);
file.print(" ");
}
Where file
is a files object. Please see: https://www.arduino.cc/en/Reference/SD for more information.
@RadhiFadlillah Good job well done. Thank yo u very much. It helped a lot..
Thanks to RadhiFadlillah, I am also able to get the barcode exactly as it is without a bit of knowledge of arduino programming. However, Now I want to perform specific function (like running a stepper motor certain steps on a specific barcode value). can anyone please help me with this?
"dot " can't be read?
Hi i'm using this code to read qrcodes. Is it possible to read other symbol such has "." or "$"? I already find in the code where letters and numbers are read but i cant understand a way for other symbols. Any help or tips?
Hi. Thanks for the code. I am using a 4POS scanner. This code helped a lot. The difference that I got was that with Capital letters buf[0] contained a 2 and the key still in buff[2]. This was sorted easily inside the Parse function by changing the call: OnKeyScanned(buf[0]==2, 0, buf[i]); /// replace buf with 0 Also the second parameter was a problem for the compiler as it was before: OnKeyScanned(buf[0]==2, buf, buf[i]); /// replace buf with 0 There was a type mismatch as it expects an uint8_t and buf is a pointer to an array, I just put in 0, as I did not know what uint8_t mod was, and also mod does not seem to be used.
I would like to ask the question though: 1) When I plug this scanner into my pc, the text is printed onto notepad as if I entered the text on the keyboard. Is there some kind of similar parser that gets loaded for the scanner on the pc that converts these array of 8's to Ascii before sending it to Notepad? 2) Why are the codes that you get from the scanner [in buf(2)] not the same as Ascii codes? 3)Can anyone recomend some more reading for me to get up to speed with the whole USB thing. 4) Is there some explanations covering the different USB libraries, or do I have to pick appart the code to discover what each one does. (Maybe in some of the broken links to circuitsathome?)
Thanks
@SaadatKhan26 Simply store the data in the
Parse
function. For instance you could write to a SD card like so:for (uint8_t i = 0; i < 8; i++) { file.print(buf[i]); file.print(" "); }
Where
file
is a files object. Please see: https://www.arduino.cc/en/Reference/SD for more information.
I am going to implement this logic to save the scanned bar codes on an SD however I am having this problem, for a while now, in wiring SD Card module over the USB Host Shield. Can someone enlighten me about SPI and USB Host shield?
Edit: I tried saving data to SD card without the USB Host Shield and it is working fine. However when the Shield is attached, both SD Card and USB Barcode Scanner are not working. I am using Arduino UNO
Hi everyone
This code is great, but I have a bar code reader that is not run .....somebody can Help me to give an ideia how to solve this? What I must to work in this code maybe to solve it. This reader is chinese brandless. Best regards Ideali
sir when try to work this project using USB host shield and arduino uno and barcode scanner when I first try USB_desc it gives me Start ) 00705
Endpoint descriptor: Endpoint address: 81 Attr.: 03 Max.pkt size: 0008 Polling interval: 02
Addr:1(0.0.1) 00705
Endpoint descriptor: Endpoint address: 81 Attr.: 03 Max.pkt size: 0008 Polling interval: 02
Addr:1(0.0.1) ⸮j⸮hsX 8⸮&⸮AqX this some illegal characters and when I load USBHID_desc it shows Start port Size(08) Logical Max(FF00) Usage Page Kbrd/Keypad(07) Usage Min(00) Usage Max(91) Input(00000000) End Collection) Report Size(08) Logical Max(FF00) Usage Page Kbrd/Keypad(07) Usage Min(00) Usage Max(91) Input(00000000) End Collection⸮⸮(⸮⸮⸮-⸮⸮1
%⸮84⸮Ȋ⸮b⸮VI,⸮>/⸮⸮⸮@⸮⸮M ⸮ӧ⸮⸮⸮fARq same song un seen characters anyone can suggest any ideas please
Hi everyone, I want to ask how is it possible to create a variable that has a value as the number of characters in the barcode. Thanks.
Alright guys, it works now. I just have to modify the
OemToAscii
to satisfy my need. Here is my final code :#include <usbhid.h> #include <usbhub.h> #include <hiduniversal.h> #include <hidboot.h> #include <SPI.h> class MyParser : public HIDReportParser { public: MyParser(); void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); protected: uint8_t KeyToAscii(bool upper, uint8_t mod, uint8_t key); virtual void OnKeyScanned(bool upper, uint8_t mod, uint8_t key); virtual void OnScanFinished(); }; MyParser::MyParser() {} void MyParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { // If error or empty, return if (buf[2] == 1 || buf[2] == 0) return; for (uint8_t i = 7; i >= 2; i--) { // If empty, skip if (buf[i] == 0) continue; // If enter signal emitted, scan finished if (buf[i] == UHS_HID_BOOT_KEY_ENTER) { OnScanFinished(); } // If not, continue normally else { // If bit position not in 2, it's uppercase words OnKeyScanned(i > 2, buf, buf[i]); } return; } } uint8_t MyParser::KeyToAscii(bool upper, uint8_t mod, uint8_t key) { // Letters if (VALUE_WITHIN(key, 0x04, 0x1d)) { if (upper) return (key - 4 + 'A'); else return (key - 4 + 'a'); } // Numbers else if (VALUE_WITHIN(key, 0x1e, 0x27)) { return ((key == UHS_HID_BOOT_KEY_ZERO) ? '0' : key - 0x1e + '1'); } return 0; } void MyParser::OnKeyScanned(bool upper, uint8_t mod, uint8_t key) { uint8_t ascii = KeyToAscii(upper, mod, key); Serial.print((char)ascii); } void MyParser::OnScanFinished() { Serial.println(" - Finished"); } USB Usb; USBHub Hub(&Usb); HIDUniversal Hid(&Usb); MyParser Parser; void setup() { Serial.begin( 115200 ); Serial.println("Start"); if (Usb.Init() == -1) { Serial.println("OSC did not start."); } delay( 200 ); Hid.SetReportParser(0, &Parser); } void loop() { Usb.Task(); }
HI! @RadhiFadlillah ,when I upload this I got these errors:
F:\Users\Documents\Arduino\Barcodetest_9\Barcodetest_9.ino: In member function 'virtual void MyParser::Parse(USBHID, bool, uint8_t, uint8_t)':
F:\Users\Documents\Arduino\Barcodetest_9\Barcodetest_9.ino:35:38: warning: invalid conversion from 'uint8_t {aka unsigned char}' to 'uint8_t {aka unsigned char}' [-fpermissive]
OnKeyScanned(i > 2, buf, buf[i]);
^
F:\Users\Documents\Arduino\Barcodetest_9\Barcodetest_9.ino:13:18: note: initializing argument 2 of 'virtual void MyParser::OnKeyScanned(bool, uint8_t, uint8_t)'
virtual void OnKeyScanned(bool upper, uint8_t mod, uint8_t key);
^
I don't really understand how to fix this. It just printing "start" on a serial monitor and when I scan a barcode, nothing happens on the serial monitor. What will I do for this?
Hi @RadhiFadlillah , thank you for your wonderful code. I would like to send the barcode to another Arduino using I2C for inventory purposes but I am new to hid so I hardly get the idea of the code. Could you help me on this matter? Thanks again for the code. I attached my datasheet of my scanner: `Device descriptor: Descriptor Length: 12 Descriptor type: 01 USB version: 0110 Device class: 00 Device Subclass: 00 Device Protocol: 00 Max.packet size: 20 Vendor ID: FFFF Product ID: 0035 Revision ID: 0001 Mfg.string index: 01 Prod.string index: 02 Serial number index: 03 Number of conf.: 01
Configuration descriptor: Total length: 0022 Num.intf: 01 Conf.value: 01 Conf.string: 00 Attr.: A0 Max.pwr: 64
Interface descriptor: Intf.number: 00 Alt.: 00 Endpoints: 01 Intf. Class: 03 Intf. Subclass: 01 Intf. Protocol: 01 Intf.string: 04 Unknown descriptor: Length: 09 Type: 21 Contents: 100121012241000705
Endpoint descriptor: Endpoint address: 81 Attr.: 03 Max.pkt size: 0008 Polling interval: 02`
here is my contribution on @RadhiFadlillah 's code. added some extra ascii code like ($,! ...) . Since am using "Aibecy 2D QR scanner" it's detecting shift signal differently so you need to keep that in mind
#include <usbhid.h>
#include <usbhub.h>
#include <hiduniversal.h>
#include <hidboot.h>
#include <SPI.h>
const uint8_t numKeys[10] PROGMEM = {'!', '@', '#', '$', '%', '^', '&', '*', '(', ')'};
const uint8_t symKeysUp[12] PROGMEM = {'_', '+', '{', '}', '|', '', ':', '"', '', '<', '>', '?'};
const uint8_t symKeysLo[12] PROGMEM = {'-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/'};
const uint8_t padKeys[5] PROGMEM = {'/', '*', '-', '+', '\r'};
bool shift = false;
class MyParser : public HIDReportParser {
public:
MyParser();
void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
protected:
uint8_t KeyToAscii(bool upper, uint8_t mod, uint8_t key);
virtual void OnKeyScanned(bool upper, uint8_t mod, uint8_t key);
virtual void OnScanFinished();
};
MyParser::MyParser() {}
void MyParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
// If error or empty, return
// if (buf[2] == 1 || buf[2] == 0) {
// return;
// }
if(buf[0] == 2)
shift = true;
for (uint8_t i = 7; i >= 2; i--) {
// If empty, skip
if (buf[i] == 0) continue;
// If enter signal emitted, scan finished
if (buf[i] == UHS_HID_BOOT_KEY_ENTER) {
OnScanFinished();
}
// If not, continue normally
else {
// If bit position not in 2, it's uppercase words
OnKeyScanned(shift, buf, buf[i]);
shift = false;
}
return;
}
}
uint8_t MyParser::KeyToAscii(bool upper, uint8_t mod, uint8_t key) {
// Letters
if (VALUE_WITHIN(key, 0x04, 0x01d)) {
if (upper) return (key - 4 + 'A');
else return (key - 4 + 'a');
}
// Numbers
else if (VALUE_WITHIN(key, 0x1e, 0x27)) {
if (shift)
return ((uint8_t)pgm_read_byte(&numKeys[key - 0x1e]));
else
return ((key == UHS_HID_BOOT_KEY_ZERO) ? '0' : key - 0x1e + '1');
}
// Keypad Numbers
else if (VALUE_WITHIN(key, 0x59, 0x61)) {
return (key - 0x59 + '1');
} else if (VALUE_WITHIN(key, 0x2d, 0x38))
return ((upper) ? (uint8_t)pgm_read_byte(&symKeysUp[key - 0x2d]) : (uint8_t)pgm_read_byte(&symKeysLo[key - 0x2d]));
else if (VALUE_WITHIN(key, 0x54, 0x58))
return (uint8_t)pgm_read_byte(&padKeys[key - 0x54]);
else {
switch (key) {
case UHS_HID_BOOT_KEY_SPACE: return (0x20);
case UHS_HID_BOOT_KEY_ENTER: return ('\r'); // Carriage return (0x0D)
}
}
//Serial.println(key, HEX);
return 0;
}
void MyParser::OnKeyScanned(bool upper, uint8_t mod, uint8_t key) {
//Serial.print(upper);
uint8_t ascii = KeyToAscii(upper, mod, key);
Serial.print((char)ascii);
}
void MyParser::OnScanFinished() {
Serial.println(" - Finished");
}
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
MyParser Parser;
void setup() {
Serial.begin( 115200 );
Serial.println("Start");
if (Usb.Init() == -1) {
Serial.println("OSC did not start.");
}
delay( 200 );
Hid.SetReportParser(0, &Parser);
}
void loop() {
Usb.Task();
}
hi my Scanner info is : Intf. Class: 03 Intf. Subclass: 00 Intf. Protocol: 01 Intf.string: 00
and it doesn't work with the Codes I found in the internet...
in the PC Device Manager it is Known as a Keyboard
but it's not working with the Arduino mega ADK
any idea?
Hi,I think that the protocol must be 06 but not 01Enviado do meu iPhoneEm 16 de jan. de 2023, à(s) 06:08, Mobin Mortazavi @.***> escreveu: hi my Scanner info is : Intf. Class: 03 Intf. Subclass: 00 Intf. Protocol: 01 Intf.string: 00 and it doesn't work with the Codes I found in the internet... in the PC Device Manager it is Known as a Keyboard but it's not working with the Arduino mega ADK any idea?
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you commented.Message ID: @.***>
In hidboot.h, the driver is looking for a HID device with (class,subclass,protocol), of (3,1,1). If your keyboard does not have this, the driver does not recognize it as a keyboard. You can experiment to make the driver accept (3,0,1) but the scanner/keyboard may not work.
Hi guys, I'm trying to connect my barcode scanner to Arduino using the USB Host Shield. I've followed tutorial from circuit@home, and there it said :
Fortunately, my barcode scanner has
Intf. Class = 03
,Intf. Subclass = 01
andIntf. Protocol = 01
, therefore according to the tutorial, my barcode scanner should work usingHID Protocol Keyboard
. However, in practice two of my barcode scanners didn't work, but my wired keyboard worked. The barcode is powered up, but doesn't print anything.Here is my code :
Here is my
USB_desc
:And here is my
USBHID_desc
: