send barcode to mega using i2c

Hi, I want to send the barcode from the scanner and send it to Arduino Mega using I2C. For the barcode scanner, I am using the code in the link here: https://github.com/felis/USB_Host_Shield_2.0/issues/323. However, when I tried to include the code for the I2C using Wire library, I can only get the first barcode and the serial monitor does not show the next barcode after scanning for multiple times. Here is my code for the master:

#include <usbhid.h>
#include <usbhub.h>
#include <hiduniversal.h>
#include <hidboot.h>
#include <SPI.h>
#include <Wire.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;
}

char barcode;

void MyParser::OnKeyScanned(bool upper, uint8_t mod, uint8_t key) {
  uint8_t ascii = KeyToAscii(upper, mod, key);
  Serial.println((char)ascii);
  Wire.beginTransmission(9); // transmit to device #9 
  Wire.write(ascii); // sendsascii 
  Wire.endTransmission();
}

void MyParser::OnScanFinished() {
  //Serial.println(" - Finished");
}

USB          Usb;
USBHub       Hub(&Usb);
HIDUniversal Hid(&Usb);
MyParser     Parser;

void setup() {
  Wire.begin();
  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();
}

And here is my code for slave:

#include <Wire.h>

void setup()
{
  Wire.begin(9);                // join i2c bus with address #9
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(115200);           // start serial for output
}

void loop()
{
  delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer
}

I am also confused about how to send the barcode using the code provided in the link. The barcode is in ASCII and the author is using Serial.print((char)ascii) to print the barcode. So if I want to send the barcode using I2C, should I send them in string format? If that’s the case, how to convert ASCII into string format?

In your parse() method you should check the length of the data before reading at specific memory positions just to be sure you are not handling garbage.

I2C works with bytes, so at the end of the day that’s what you are sending and receiving.
The type of those bytes is what you define the variable to store them when you read (or print if you cast) them and possibly group them together. So if you store the byte as an integral number then when you print it you’ll see a number

 int x = Wire.read();    // receive byte as an integer
Serial.println(x);      // print the integer

but if you read them as a char, then you’ll print them as ascii symbols.

 char x = Wire.read();    // receive byte as a character
Serial.println(x);       // print the character

J-M-L:
I2C works with bytes, so at the end of the day that’s what you are sending and receiving.
The type of those bytes is what you define the variable to store them when you read (or print if you cast) them and possibly group them together. So if you store the byte as an integral number then when you print it you’ll see a number

 int x = Wire.read();    // receive byte as an integer

Serial.println(x);         // print the integer



but if you read them as a char, then you’ll print them as ascii symbols.


char x = Wire.read();    // receive byte as a character
Serial.println(x);         // print the character

J-M-L:
I2C works with bytes, so at the end of the day that’s what you are sending and receiving.
The type of those bytes is what you define the variable to store them when you read (or print if you cast) them and possibly group them together. So if you store the byte as an integral number then when you print it you’ll see a number

I tried to send the ascii to the slave and use char() to print it to char but the serial monitor of the master is showing only the first out of 17 characters after I scanned with the barcode scanner. And the same problem remains where the serial monitor does not show further inputs from the scanner after I scanned it multiple times. I find some examples online but most of them are just sending simple integers or string. Does the I2C is able to send uint8_t to the slave? If possible I would like to receive the barcode in a string format as I still need it to program for managing inventory purposes.

uint8_t is a formal type for a byte (8 bits unsigned integer)

I’m not sure in which context you usb hid class is being triggered, if it’s in an interrupt, using i2c from within the ISR might be difficult.

J-M-L:
uint8_t is a formal type for a byte (8 bits unsigned integer)

I’m not sure in which context you usb hid class is being triggered, if it’s in an interrupt, using i2c from within the ISR might be difficult.

I am new to hid and usb host shield so I can just get the code from online. Here is the datasheet of my barcode scanner:

Start


01
--

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


Addr:1(0.0.1)

Could you please have a look and see whether the barcode can be send by using i2c or not?

I don’t have a USB Host Shield not a barcode scanner but I can read C++ and make some educated guesses.

Assuming you have an USB Host Shield V2 correctly plugged in, could you upload this code on your Arduino Mega

#include <usbhid.h>
#include <usbhub.h>
#include <hiduniversal.h>
#include <hidboot.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(__attribute__((unused)) USBHID *hid, __attribute__((unused)) bool is_rpt_id, uint8_t len, uint8_t *buf) {

  if (len <= 7) {
    Serial.print(F("ERROR MyParser::Parse - length too short :"));
    Serial.println(len);
    return;
  }

  // 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 (buf[i] == UHS_HID_BOOT_KEY_ENTER) // If enter signal emitted,
      OnScanFinished();                   // scan is finished
    else                                  // If not keep recording the sentence
      OnKeyScanned(i > 2, buf[i]);        // If bit position not in 2, it's uppercase words
    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 (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 key) {
  Serial.print(KeyToAscii(upper, key));
  Serial.print(F("('"));
  Serial.print((char) KeyToAscii(upper, key));
  Serial.print(F("') "));
}

void MyParser::OnScanFinished() {
  Serial.println(F("\nOnScanFinished: END"));
}

USB          Usb;
USBHub       Hub(&Usb);
HIDUniversal Hid(&Usb);
MyParser     Parser;

void setup() {
  Serial.begin(115200 );
  if (Usb.Init() == -1) {
    Serial.println("OSC did not start.");
    while (true);
  }
  delay( 200 );
  Hid.SetReportParser(0, &Parser);
}

void loop() {
  Usb.Task();
}

open the Serial monitor at 115200 bauds and scan with your barcode reader a few barcodes.

==> what do you see in the Serial Console?

I am using Arduino Uno for the barcode scanner and hoping to send the barcode to the Arduino Mega. Here is what I get after uploading the code to my uno:

115('s') 112('p') 120('x') 109('') 121('y') 48('0') 48('0') 53('5') 51('3') 48('0') 49('1') 50('2') 56('8') 49('1') 48('0') 57('9') 99('c') 
OnScanFinished: END
115('s') 112('p') 120('x') 109('m') 121('y') 48('0') 48('0') 48('0') 49('1') 50('2') 49('1') 52('4') 48('0') 57('9') 49('1') 48('0') 98('b') 
OnScanFinished: END

So did you scan the 2 following barcodes?

spxmy00530128109c
spxmy00012140910b

that would indicate that the reading is working fine. if that’s the case we could modify the MyParser class to build up a buffer with these strings and set a flag when the data is ready to be used. You could poll that flag in the loop of your code and use Wire then to send it out.

J-M-L:
So did you scan the 2 following barcodes?

spxmy00530128109c

spxmy00012140910b

Yes I am scanning for these 2 barcodes. The scanner is working fine.

J-M-L:
if that’s the case we could modify the MyParser class to build up a buffer with these strings and set a flag when the data is ready to be used. You could poll that flag in the loop of your code and use Wire then to send it out.

My programming knowledge is quite basic so I looked online and modified your code. I managed to get the barcode after scanning and received on the Mega. However not every time the Mega will receive the barcode and some of the barcodes contain weird characters or even missing. This is what I get after scanning the same barcode for multiple times:
Uno(Master):

spxmy00012140910b
OnScanFinished: END
spxmy00012140910b
OnScanFinished: END
spxmy00012140910b
OnScanFinished: END
spxmy00012140910b
OnScanFinished: END
spxmy00012140910b
OnScanFinished: END
spxmy00012140910b
OnScanFinished: END
spxmy00012140910b
OnScanFinished: END
spxmy00012140910b
OnScanFinished: END

Slave (Mega):

Pr⸮⸮⸮ng: spxmy0001214⸮⸮10b
Printing: spxmy0001214⸮⸮10b
PrintQ⸮g: spxmy00012140910b
PrintU⸮g: spxmy00012140910b
Print⸮g: 
Printing: spxmy0001214⸮⸮

This is my sketch modified from your code:
Master (Uno):

#include <usbhid.h>
#include <usbhub.h>
#include <hiduniversal.h>
#include <hidboot.h>
#include <Wire.h>

char buff[17];
int pos = 0;

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(__attribute__((unused)) USBHID *hid, __attribute__((unused)) bool is_rpt_id, uint8_t len, uint8_t *buf) {

  if (len <= 7) {
    Serial.print(F("ERROR MyParser::Parse - length too short :"));
    Serial.println(len);
    return;
  }

  // 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 (buf[i] == UHS_HID_BOOT_KEY_ENTER) // If enter signal emitted,
      OnScanFinished();                   // scan is finished
    else                                  // If not keep recording the sentence
      OnKeyScanned(i > 2, buf[i]);        // If bit position not in 2, it's uppercase words
    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 (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 key) {
  Serial.print((char) KeyToAscii(upper, key));
  buff[pos++]= KeyToAscii(upper,key);
  
}

void MyParser::OnScanFinished() {
  Serial.println(F("\nOnScanFinished: END"));
  Wire.beginTransmission(9);
  for(int i=0; i<17; i++)
  {
    Wire.write(buff[i]);
  }
  Wire.endTransmission();
}

USB          Usb;
USBHub       Hub(&Usb);
HIDUniversal Hid(&Usb);
MyParser     Parser;

void setup() {
  Wire.begin();
  Serial.begin(115200 );
  if (Usb.Init() == -1) {
    Serial.println("OSC did not start.");
    while (true);
  }
  delay( 200 );
  Hid.SetReportParser(0, &Parser);
}

void loop() {
  Usb.Task();
}

Slave (Mega):

#include <Wire.h>

void setup() { 
// Start the I2C Bus as Slave on address 9 
Wire.begin(9); 
// Attach a function to trigger when something is received.
Wire.onReceive(receiveEvent); 
} 
void receiveEvent(int bytes) { 
String text = "";
  while (Wire.available()) {
    char c = Wire.read(); // receive a byte as character
    text += c;
  }
  Serial.print("Printing: ");
  Serial.println(text);
} 
void loop() { 
Serial.begin(115200);
}

I am not sure why the Mega will display those weird characters and even the "Printing: " using Serial.print function contains the weird characters. I am using baud rate of 115200 for both Arduinos and I also set the baud rate of the Serial monitor to 115200 for both. Do you know what is the problem?

After I tried to scanned the barcode again, this is what I get: (I enabled timeframe to see when will the Mega be receiving the barcode)
Master:

14:28:54.874 -> spxmy00530128109c
14:28:54.924 -> OnScanFinished: END
14:29:01.264 -> spxmy00530128109c
14:29:01.350 -> OnScanFinished: END
14:29:05.074 -> spxmy00530128109c
14:29:05.152 -> OnScanFinished: END
14:29:11.414 -> spxmy00530128109c
14:29:11.461 -> OnScanFinished: END
14:29:14.837 -> spxmy00530128109c
14:29:14.921 -> OnScanFinished: END
14:29:17.725 -> spxmy00530128109c
14:29:17.772 -> OnScanFinished: END
14:29:20.351 -> spxmy00530128109c
14:29:20.397 -> OnScanFinished: END
14:29:22.986 -> spxmy00530128109c
14:29:23.033 -> OnScanFinished: END
14:29:25.242 -> spxmy00530128109c
14:29:25.335 -> OnScanFinished: END
14:29:28.590 -> spxmy00530128109c
14:29:28.653 -> OnScanFinished: END

Slave:

14:28:54.939 -> Pr⸮.ng: spxmy0053012,⸮09c
14:29:11.461 -> Printing: spxmy0053012,⸮09c
14:29:20.397 -> Printing: spxmy0053012⸮⸮09c
14:29:23.017 -> Printing: spxmy0053012,⸮09c
14:29:25.335 -> Printing: spxmy0053012⸮⸮

It seems like this time the Serial.print function is working properly as the "Printing: " did not contain any weird character except for the first line. During the first scan, the Mega displayed the first few characters and only displayed the barcode on the third try. Another problem is the barcode is displaying up until "⸮⸮" and the characters behind (09c) will be displayed after the next scan. The third problem is the Uno only allows me to scan for 10 times and after scanning for the 11th time the Serial monitor is not showing the barcode anymore. I believed that the error lies in my coding but I not sure how to improve the code. Hope you can help me out. Thank you.

can you try this code:

#include <usbhid.h>
#include <usbhub.h>
#include <hiduniversal.h>
#include <hidboot.h>

const uint8_t MaxBarCodeLength = 30+1; // adjust to your needs (max barCode length + 1)

class MyParser : public HIDReportParser {
  public:
    MyParser();
    void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
    bool barCodeAvailable();
    const char* getBarCode();
  protected:
    uint8_t barCodeBufferIndex;
    bool isBarCodeAvailable;
    char barCodeBuffer[MaxBarCodeLength];
    void resetBuffer();
    uint8_t KeyToAscii(bool upper, uint8_t key);
    virtual void OnKeyScanned(bool upper, uint8_t key);
    virtual void OnScanFinished();
};

void MyParser::resetBuffer()
{
  barCodeBufferIndex = 0;
  barCodeBuffer[0] = '\0';
  isBarCodeAvailable = false;
}

MyParser::MyParser() {
  resetBuffer();
}

bool MyParser::barCodeAvailable()
{
  return isBarCodeAvailable;
}

const char* MyParser::getBarCode()
{
  return barCodeBuffer;
}

void MyParser::Parse(__attribute__((unused)) USBHID *hid, __attribute__((unused)) bool is_rpt_id, uint8_t len, uint8_t *buf) {

  if (len <= 7) {
    Serial.print(F("ERROR MyParser::Parse - length too short :"));
    Serial.println(len);
    return;
  }

  // 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 (buf[i] == UHS_HID_BOOT_KEY_ENTER) // If enter signal emitted,
      OnScanFinished();                   // scan is finished
    else                                  // If not keep recording the sentence
      OnKeyScanned(i > 2, buf[i]);        // If bit position not in 2, it's uppercase words
    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 (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 key) {
  if (isBarCodeAvailable) {  // if scanning a new barcode, loose the old one
    resetBuffer();
  }

  if (barCodeBufferIndex < MaxBarCodeLength - 1) {
    barCodeBuffer[barCodeBufferIndex++] = KeyToAscii(upper, key);
    barCodeBuffer[barCodeBufferIndex] = '\0';
  } else {
    Serial.println(F("ERROR MyParser::OnKeyScanned - buffer too short"));
  }
}

void MyParser::OnScanFinished() {
  isBarCodeAvailable = true;
}

// ----------------------

USB          Usb;
USBHub       Hub(&Usb);
HIDUniversal Hid(&Usb);
MyParser     Parser;

void setup() {
  Serial.begin(115200 );
  if (Usb.Init() == -1) {
    Serial.println("OSC did not start.");
    while (true);
  }
  delay( 200 );
  Hid.SetReportParser(0, &Parser);
}

void loop() {
  Usb.Task();

  if (Parser.barCodeAvailable()) {
    Serial.print(F("BarCode detected: ["));
    Serial.print(Parser.getBarCode());
    Serial.println(F("]"));

    // this is where you could send it out
    // ....
  }
}

(typed here, so there may be typos).

The loop should be self explanatory. In this new code, the Parser class accumulates the characters in a buffer and I provided the barCodeAvailable() method that you can use to check if the scan is complete. if so then the current barcode is obtained by calling getBarCode().

The max size of the buffer for the barcode has to be provided, I set it to 30 in this line of codeconst uint8_t MaxBarCodeLength = 30+1; // adjust to your needs (max barCode length + 1)this should be enough for the examples you have been scanning. if there is more data being scanned, then the buffer ignores the extra characters.

Give it a try and let me know what you see in the Serial monitor

J-M-L:
Give it a try and let me know what you see in the Serial monitor

I tried out your code but I get unlimited barcodes by just scanning for once. This I what I get: (just a part of it)

BaCode detected: [spxmy0001140910b]
BarCode detected: [spxmy00012140910b]
BarCode detected: [spxmy00012140910b]
BarCode detected: [spxmy00012140910b]
BarCode detected: [spxmy00012140910b]
BarCode detected: [spxmy00012140910b]
BarCode detected: [spxmy00012140910b]
BarCode detected: [spxmy00012140910b]
BarCode detected: [spxmy00012140910b]
BarCode detected: [spxmy00012140910b]
BarCode deteted: [spxmy00012140910b]

Of course, I forgot to release the barcode once you get it. Modify the getBarCode() method this way

 const char* MyParser::getBarCode()
{
  isBarCodeAvailable = false; 
  return barCodeBuffer;
}

Note that the pointer you get is the embedded class buffer that will be used for the next scan, so if you need to keep the data longer term than the place where you extract it then you need to duplicate the code and store it in your own buffer.

After I modified the getBarCode(), I get this:

BarCode detected: [spxmy00012140910b]
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
BarCode detected: [spxmy00012140910b]
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
ERROR MyParser::OnKeyScanned - buffer too short
BarCode detected: [spxmy00012140910b]

I scanned for 3 times but before the next scan the serial monitor will display 17 lines of ERROR. In the code I had also changed the MaxBarCodeLength to 17+1.

J-M-L:
Note that the pointer you get is the embedded class buffer that will be used for the next scan, so if you need to keep the data longer term than the place where you extract it then you need to duplicate the code and store it in your own buffer.

I just need the barcode for one time use only after every scan but I will keep in mind for that. :slight_smile:

Yeah. Sorry
I’m typing this on my iPhone you also need to reset the counter then it should work

const char* MyParser::getBarCode()
{
  isBarCodeAvailable = false; 
  barCodeBufferIndex = 0;
  return barCodeBuffer;
}

J-M-L:
Yeah. Sorry
I’m typing this on my iPhone you also need to reset the counter then it should work

const char* MyParser::getBarCode()

{
 isBarCodeAvailable = false;
 barCodeBufferIndex = 0;
 return barCodeBuffer;
}

Thanks!! It worked perfectly. I also managed to receive the barcode on the Mega too. Here is my code:
Master:

#include <usbhid.h>
#include <usbhub.h>
#include <hiduniversal.h>
#include <hidboot.h>
#include <Wire.h>

const uint8_t MaxBarCodeLength = 17+1; // adjust to your needs (max barCode length + 1)

class MyParser : public HIDReportParser {
  public:
    MyParser();
    void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
    bool barCodeAvailable();
    const char* getBarCode();
  protected:
    uint8_t barCodeBufferIndex;
    bool isBarCodeAvailable;
    char barCodeBuffer[MaxBarCodeLength];
    void resetBuffer();
    uint8_t KeyToAscii(bool upper, uint8_t key);
    virtual void OnKeyScanned(bool upper, uint8_t key);
    virtual void OnScanFinished();
};

void MyParser::resetBuffer()
{
  barCodeBufferIndex = 0;
  barCodeBuffer[0] = '\0';
  isBarCodeAvailable = false;
}

MyParser::MyParser() {
  resetBuffer();
}

bool MyParser::barCodeAvailable()
{
  return isBarCodeAvailable;
}

const char* MyParser::getBarCode()
{
  isBarCodeAvailable = false;
  barCodeBufferIndex = 0;
  return barCodeBuffer;
}

void MyParser::Parse(__attribute__((unused)) USBHID *hid, __attribute__((unused)) bool is_rpt_id, uint8_t len, uint8_t *buf) {

  if (len <= 7) {
    Serial.print(F("ERROR MyParser::Parse - length too short :"));
    Serial.println(len);
    return;
  }

  // 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 (buf[i] == UHS_HID_BOOT_KEY_ENTER) // If enter signal emitted,
      OnScanFinished();                   // scan is finished
    else                                  // If not keep recording the sentence
      OnKeyScanned(i > 2, buf[i]);        // If bit position not in 2, it's uppercase words
    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 (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 key) {
  if (isBarCodeAvailable) {  // if scanning a new barcode, loose the old one
    resetBuffer();
  }

  if (barCodeBufferIndex < MaxBarCodeLength - 1) {
    barCodeBuffer[barCodeBufferIndex++] = KeyToAscii(upper, key);
    barCodeBuffer[barCodeBufferIndex] = '\0';
  } else {
    Serial.println(F("ERROR MyParser::OnKeyScanned - buffer too short"));
  }
}

void MyParser::OnScanFinished() {
  isBarCodeAvailable = true;
}

// ----------------------

USB          Usb;
USBHub       Hub(&Usb);
HIDUniversal Hid(&Usb);
MyParser     Parser;

void setup() {
  Wire.begin();
  Serial.begin(115200 );
  if (Usb.Init() == -1) {
    Serial.println("OSC did not start.");
    while (true);
  }
  delay( 200 );
  Hid.SetReportParser(0, &Parser);
}

void loop() {
  Usb.Task();

  if (Parser.barCodeAvailable()) {
    Serial.print(F("BarCode detected: ["));
    Serial.print(Parser.getBarCode());
    Serial.println(F("]"));
    Wire.beginTransmission(9);
    Wire.write(Parser.getBarCode());
    Wire.endTransmission();
    
  }
}

Slave:

#include <Wire.h>

void setup()
{
  Wire.begin(9);                // join i2c bus with address #8
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(115200);           // start serial for output
}

void loop()
{
  delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  while (1 < Wire.available()) // loop through all but the last
  {
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
  }
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer
}

Here is the output:
Master:

BarCode detected: [spxmy00012140910b]
BarCode detected: [spxmy00012140910b]
BarCode detected: [spxmy00012140910b]
BarCode detected: [spxmy00530128109c]
BarCode detected: [spxmy00530128109c]

Slave:

spxmy0001214091098
spxmy0001214091098
spxmy0001214091098
spxmy0053012810999
spxmy0053012810999

The last character ‘b’ is received as “98” and ‘c’ is received as “99” on the Mega but the rest of the characters are fine. And I tried to remove the last two lines on the Mega which is receiving the barcode as an integer but the Serial monitor only prints for the first barcode and had the last character missing. How can I get the barcode in String format as I need it to use it for the if else function?

Well, you have the comments explaining it all...

==> loop through all but the last

And then

==> receive byte as an integer / print the integer

You read the last character as a number (int) not a character (char), so that’s why you see it printed as a number

So you want to receive all of them as characters.

 void receiveEvent(int howMany) {
  while (Wire.available()) { // loop through all bytes received
   char c = Wire.read(); // receive byte as a character
   Serial.print(c);         // print the character

   // ==================== 
   // if you want to rebuild the string that’s where you need to accumulate the chars
   // ====================

}
 Serial.println(); 
}

if you want to rebuild the string, I flagged where you need to accumulate the characters you receive in a buffer. Look at how I did this in the OnKeyScanned() function and Give it a try

J-M-L:
Well, you have the comments explaining it all…

==> loop through all but the last

And then

==> receive byte as an integer / print the integer

You read the last character as a number (int) not a character (char), so that’s why you see it printed as a number

So you want to receive all of them as characters.

IT IS! Sorry for not reading the comment for the while(1<Wire.available())… I did read for the comment for the receive byte as an char and integer, that’s why I removed the last 2 lines of the code that is receiving integer but that time I just managed to get the first barcode and it did not display the next barcode anymore.

zack6912:
And I tried to remove the last two lines on the Mega which is receiving the barcode as an integer but the Serial monitor only prints for the first barcode and had the last character missing. How can I get the barcode in String format as I need it to use it for the if else function?

I added few lines to accumulate the char to get the barcode string. So this is my final code for the slave:

#include <Wire.h>
int i = 0;
String barcode;

void setup()
{
  Wire.begin(9);                // join i2c bus with address #9
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(115200);           // start serial for output
}

void loop()
{

  delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  String text = "";
  while (Wire.available()) // loop through all
  {
    char c = Wire.read(); // receive byte as a character
     text += c;
}
  barcode = text;
  Serial.print(barcode);
  Serial.println();

  if(barcode == "spxmy00012140910b"){
    Serial.print("Item A received");
    Serial.println();
  }
  if(barcode == "spxmy00530128109c"){
    Serial.print("Item B received");
    Serial.println();
  }
}

And this is the output:

spxmy00012140910b
Item A received
spxmy00530128109c
Item B received
spxmy00012140910b
Item A received
spxmy00012140910b
Item A received
spxmy00530128109c
Item B received

Thank you J-M-L for your precious time. Much appreciated for your help. :slight_smile:

You went the lazy way with the String class but that’s OK :slight_smile:

Your

String text;

will only be available in the wire receive interrupt context. I would suggest to not handle the barcodes there and just raise a flag and deal with the barcode in the loop

#include <Wire.h>
int i = 0;
String barcode;
bool newBarcodeReceived = false;

void receiveEvent(int howMany)
{
  barcode = "";
  while (Wire.available()) barcode += (char)Wire.read(); // receive byte as a character
  newBarcodeReceived = true;
}

void setup()
{
  Wire.begin(9);                  // join i2c bus with address #9
  Wire.onReceive(receiveEvent);   // register event
  Serial.begin(115200);           // start serial for output
  barcode.reserve(20);            // reserve some space so that the String does not poke hole in the heap
}

void loop()
{
  if (newBarcodeReceived) {
    Serial.println(barcode);

    if (barcode == "spxmy00012140910b") {
      Serial.println(F("Item A received"));
    } else  if (barcode == "spxmy00530128109c") {
      Serial.println(F("Item B received"));
    } else {
      Serial.println(F("ERROR: Unknown Barcode"));
    }
    newBarcodeReceived = false;
  }
}

dealing with Johnson Pump Aqua Jet ? :slight_smile:

J-M-L:
Your

String text;

will only be available in the wire receive interrupt context. I would suggest to not handle the barcodes there and just raise a flag and deal with the barcode in the loop

Alright, thanks for the suggestion.

J-M-L:
dealing with Johnson Pump Aqua Jet ? :slight_smile:

Not sure what you mean by this but anyways thanks for the help again =)