Ich versuche (fast komplett erfolgreich) selbst erstellte QR- und Barcodes zu scannen.
Sehr hilfreich war mir dabei folgende Diskussion, bei der folgender Sketch erarbeitet wurde:
#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 (buf[i] == 0) continue; // If empty, skip
if (buf[i] == UHS_HID_BOOT_KEY_ENTER) { // If enter signal emitted, scan finished
OnScanFinished();
}
else { // If not, continue normally
OnKeyScanned(i > 2, buf, buf[i]); // If bit position not in 2, it's uppercase words
}
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);
delay(1);
}
void MyParser::OnScanFinished() {
//Serial.println(" - Finished");
Serial.println(F("\r"));
}
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
MyParser Parser;
void setup() {
Serial.begin( 9600 );
Serial.println("Start");
if (Usb.Init() == -1) {
Serial.println("OSC did not start.");
}
delay( 200 );
Hid.SetReportParser(0, &Parser);
}
void loop() {
Usb.Task();
}
Dieser Sketch wird häufig empfohlen, wenn es um Barcode-Scannen mit dem Arduino geht und funktioniert auch im Großen und Ganzen ganz gut.
Lediglich ein Problem stellt sich mir dabei noch und kann in der Diskussion keine Lösung dazu finden: Der Parser unterscheidet nicht zwischen Groß- und Kleinbuchstaben... alle Buchstaben werden klein ausgegeben, obwohl es in der Funktion extra ein Unterscheidungsmerkmal gibt.
Hat der Autor etwas übersehen oder ihr bereits selbst schon einmal vor diesem Problem gestanden?
Das macht der Sketch explizit so. Wenn Du das ändern möchtest, musst Du in der Methode KeyToAscii() den mod-Wert verwenden um den Zustand der sog. Modifiers (Umschalt-, Alt-, Control-Tasten) auszuwerten. Beim geposteten Code wird das nur über upper gesteuert, welches jeweils nur den letzten Buchstaben gross macht (wieso das so ist, ist mir nicht klar).
Hmm.. dass er diese 'upper'-Bedingung nicht erfüllt, scheint wohl zu sein...
die von my_xy_project vorschlagene Änderung getestet: nun sind alle Buchstaben Großbuchstaben. Hmpf... die Bedingung scheint sich wohl woanders zu verstecken. Trotzdem Danke!
@pylon: Leider weiß ich nicht, wie ich den 'mod'-wert auswerten kann, um diesen als umschalt-Kriterium zu verwenden. Hab ihn mir mal spaßeshalber hinter jedem gescannten ascii-Zeichen ausgedruckt ("AbCdEfG" als Test) .. dieser Wert bleibt immer bei 168.
Also wieder einen Schritt zurück:
in o.g. Diskussion hat der Autor ein Testprogramm, um sich die Ausgabe verschiedener BarCodes anzeigen zu lassen. Hier weichen meine Ergebnisse bereits von seinen ab:
(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( 9600 );
Serial.println("Start");
if (Usb.Init() == -1)
Serial.println("OSC did not start.");
delay( 200 );
Hid.SetReportParser(0, &Parser);
}
void loop() {
Usb.Task();
}
Er erhält als Ergebnis bei gescannten Großbuchstaben 7 Stellen mit einer führenden 255 ... die fehlt bei mir. Das gescannte Ergebnis sieht bei mir für Groß- wie Kleinbuchstaben identisch aus und besteht für jedes Zeichen immer nur aus 6 Ziffern.
Die Methode scheint für meinen Scanner also nicht komplett geeignet zu sein
Ich habe mal das Ergebnis von USBdesc für meinen Scanner (Sunmi Blink) hier:
Mehr Info als SUNMI BLINK NS010 konnte ich auch nicht finden. Als Datenblatt wohl nicht so richtig geeignet, deshalb habe ich mal die beiden desc-infos gepostet.
zu Frage 2: yep.. Groß-/Kleinschreibung wird in Textdokumenten richtig angezeigt.
Edit: ich habe noch einen 2. Handscanner (ALBASCA MK-6200 - wird nicht mehr produziert, daher auch keine Infos auffindbar), der sich genauso verhält: im Notepad wird alles richtig dargestellt, bis auf.. die Sache.
Eventuell ist der vorgeschlagene Code ja nicht ganz ausgereift und ja auch schon etwas älter .. Beitrag von 2017. Gibt es denn eventuell andere Vorschläge, einen CodeScanner über das Arduino Host Shield auszulesen? Wie gesagt.. bei den vielen Beispielen der USB_HOST_SHIELD_2.0-Library habe ich (noch) nichts gefunden, mit dem ich eine Ausgabe am seriellen Monitor bekomme.
Der ist ja echt genial
Das Original gibts dann hier - ist aber auch nicht mehr:
Ok, aber der Hersteller ist noch genialer..
Ich zitiere die komplette Dokumentation:
Ist ne Aussage...
Daraus geht wohl hervor, das das Ding nicht zu konfigurieren ist. Da macht dann alles der Treiber.
Damit bekommst Du die Daten auch roh.
Da muss ich jetzt aber passen - mein yún ist leider verschollen; naja nicht zurück gekommen trifft es eher - und leider kann ich so aus der hohlen Hand da nicht mehr weiter helfen.
Aber: Es muss einen Weg geben, da bin ich mir sehr sicher.
OK.. alles wieder etwas komplizierter als zuerst gehofft
Aber apropos Rohdaten, da sagst du was...
Ich habe den Sketch zur Ausgabe ALLER empfangenen Daten etwas verändert:
#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 = 0; i < 8; i++) { // <= STARTE BEI 0, NICHT BEI 2
Serial.print(buf[i]);
Serial.print(" ");
}
Serial.println();
}
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
MyParser Parser;
void setup() {
Serial.begin( 9600 );
Serial.println("Start");
if (Usb.Init() == -1)
Serial.println("OSC did not start.");
delay( 200 );
Hid.SetReportParser(0, &Parser);
}
void loop() {
Usb.Task();
}
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 (buf[i] == 0) continue; // If empty, skip
if (buf[i] == UHS_HID_BOOT_KEY_ENTER) { // If enter signal emitted, scan finished
OnScanFinished();
}
else { // If not, continue normally
bool upper = false;
if (buf[0] == 2) { upper = true; } // If 1st byte is 2, it's uppercase words
OnKeyScanned(upper, buf, buf[i]);
//OnKeyScanned(i > 2, buf, buf[i]); // If bit position not in 2, it's uppercase words
}
return;
}
}
Ich prüfe jetzt einfach das erste byte im buf-array auf 2 und dann muss es ein Großbuchstabe sein. Geht bestimmt eleganter,.. aber funktioniert
Klappt auch bei beiden verlinkten Scannern.
Nächste Baustelle: Sonderzeichen erkennen. Aber da meld ich mich wieder, wenn ich nicht vorankomme.
..und auch Sonderzeichen (nicht alle habe ich eingebunden.. siehe Sketch) werden nun erkannt:
#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 key);
virtual void OnKeyScanned(bool upper, uint8_t key);
virtual void OnScanFinished();
};
MyParser::MyParser() {}
void MyParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
if (buf[2] == 1 || buf[2] == 0) return; // If error or empty, return
for (uint8_t i = 7; i >= 2; i--) {
if (buf[i] == 0) continue; // If empty, skip
if (buf[i] == UHS_HID_BOOT_KEY_ENTER) { OnScanFinished(); } // If enter signal emitted, scan finished
else { // If not, continue normally
bool upper = false;
if (buf[0] == 2) { upper = true; } // If first byte is 2, there is a modifier involved
OnKeyScanned(upper, buf[i]);
}
return;
}
}
uint8_t MyParser::KeyToAscii(bool upper, uint8_t key) {
// Letters
if (VALUE_WITHIN(key, 0x04, 0x1d)) {
if (upper) return (key - 4 + 'A');
else return (key - 4 + 'a');
}
// Numbers
else if ((upper == false) && (VALUE_WITHIN(key, 0x1e, 0x27))) {
return ((key == UHS_HID_BOOT_KEY_ZERO) ? '0' : key - 0x1e + '1');
}
// Special Letters
else if (upper == true) {
switch (key) {
case 30: return 33; break; /* ! */
case 31: return 64; break; /* @ */
case 32: return 35; break; /* # */
case 33: return 36; break; /* $ */
case 34: return 37; break; /* % */
case 35: return 94; break; /* ^ */
case 36: return 38; break; /* & */
case 37: return 42; break; /* * */
case 38: return 40; break; /* ( */
case 39: return 41; break; /* ) */
case 45: return 95; break; /* _ */
case 46: return 43; break; /* + */
case 51: return 58; break; /* : */
case 52: return 34; break; /* " */
case 54: return 60; break; /* < */
case 55: return 62; break; /* > */
case 56: return 63; break; /* ? */
}
}
else if (upper == false) {
switch (key) {
case 45: return 45; break; /* - */
case 46: return 43; break; /* = */
case 47: return 91; break; /* [ */
case 48: return 93; break; /* ] */
case 49: return 92; break; /* \ */
case 51: return 59; break; /* ; */
case 52: return 39; break; /* ' */
case 54: return 44; break; /* , */
case 55: return 46; break; /* . */
case 56: return 47; break; /* / */
}
}
return 0;
}
void MyParser::OnKeyScanned(bool upper, uint8_t key) {
uint8_t ascii = KeyToAscii(upper, 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(9600);
while (!Serial) { delay(1); }
Serial.print ("Initialize USB-HostSHield...");
delay(50);
if (Usb.Init() == -1) {
Serial.println("OSC did not start!");
while (true) { delay(1); }
}
else { Serial.println("done!"); }
Hid.SetReportParser(0, &Parser);
}
void loop(){
Usb.Task();
}
leider habe ich nicht wie der Original-Autor bei den Zahlen und Buchstaben ein Schema erkannt, nach dem ich die ASCII-Werte fortlaufend zuordnen konnte, also habe ich mich mit zwei switch-Abfragen beholfen.
die mod-Variable habe ich komplett entfernt, der Sinn hat sich mir nicht erschlossen. Hoffe, das war kein Fehler..
ich habe nur die Sonderzeichen der ASCII-128-Tabelle berücksichtigt, kann man aber problemlos erweitern wie vorgemacht..