I am having issues with the String compareTo method. I am trying to compare the string of the scan from a barcode scanner to another string and then move my servo motor and turn a led on. However, I seem to be having issues with the string comparison part of my code. Can someone lend me a hand? My code is as follows:
Generally better to use c string than String object.
It is unnecessary to redeclare barcode in the loop - do this >1000/second
Your compare is probably not matching because there is an unprinted char at the end of scan. This is where using strncmp() is better in that you only compared the number of barcode chars you need/want.
@armor Thank you for the response. This may be a dumb question, but how do I go about including the c string library? I don’t see it when I search libraries and if I try to declare a string variable I get an error when I verify the code.
There is no library for C strings. C strings are just an array of characters terminated with a zero byte.
And C string manipulation functions are available by default.
Okay thank you, then how am I able to read the input I get form my barcode scan? Serial.read returns an int type and Serial.readString returns a String type. Is there a way to convert these to char?
I would however recommend avoiding using the String class when possible:
char scanBuffer[128]; // Hardware Serial1 buffer is 128 bytes on the boron
int counter = 0;
while (Serial1.available() > 0)
{
// Read into the buffer
scanBuffer[counter++] = Serial1.read();
}
scanBuffer[counter] = '\0'; // Terminator
For the convenience of readString() you could use an alternative provided by the Stream class which is meant for dealing with arrays and hence can also deal with C strings Serial1.readBytes().
But, this function (as well as readString()) need to timeout in order to move on, while @nrobinson2000 version would move on as soon no more data is to be read.
There are also readStringUntil() and readByteUntil()) which would allow you to terminate as soon a terminator byte was found.
The standard c-library is already included with Particle.h. I would suggest a google search for strncmp to see a reference example of how to implement it. It is something like this:
char scan[10];
then your Serial1.read() will be into the scan[] char array but since it reads 1 byte at a time you will need to place inside a while(Serial1.available() && i < 10){scan[i] = Serial1.read(); i++;} and increment the index i after setting it to 0 before the while int i = 0;
Thank you @nrobinson2000 your code implemented worked for me and thank you @ScruffR for giving me an alternative. Also, thanks @armor I tried your code as well and it also worked for me. The only problem I’m running into now is when I scan a barcode, the code is printed on my terminal multiple times and then the application seems to be stalled, i.e if I try to scan the same barcode again then nothing happens.
Your reader is probably reading the same card multiple times and will fill up the input buffer and any subsequent scan will probably not be aligned correctly.
After getting your first scan, you should flush out all data that’s left in the RX buffer to start off with a clean read.
BTW, to help you with your new code, you should probably show it again
The barcode scanner I am using operates @5V could that be an issue as to why it’s getting printed multiple times? I have the VCC wire of the scanner wired to the VBUS pin on my Boron device.
If that scanner puts 5V on the RX pin of your Boron that's no good idea as none of the GPIOs on the Boron are 5V tolerant. But it wouldn't expain the multiple reads.
Multiple reads are common for NFC readers tho' - the software should deal with such instances gracefully.
However, once you got the voltage issue sorted, this line would do the flushing of the RX buffer
while(Serial1.read() >= 0);
You may want to wrap that also in some sort of timeout routine which also informs the user that the card needs to be removed from the scanner and when a new scan attempt can be made.
BTW, you need to reset i once you have dealt with your scan, otherwise your i < 12 condition will never ever become true again
Also, (I guess this was an oversight of @armor in his suggested code) when you want to store a 12 (or 10) character string you need an extra byte in the array to also store the terminating '\0' character which you'd probably need to add manually (as our code suggestions above featured ) since the scanner won't send that (judging by the output you showed above).
Otherwise printing that string would just blurt out some extra bytes up until the first occurance of a '\0' byte in RAM following the end of the array.
@ScruffR I looked at the documentation for the scanner and it does not say anything about putting 5V on any of the pins when in use. I manually added the terminating ‘\0’ like in the suggestions above.
Where would I implement the while(Serial1.read() & = 0) code? Would I swap that out for the Serial.available() part? I originally had done that and when I did a scan this was my output?
Just for curiosity, why are you going for 12 bytes when your barcode string is only 10 characters long?
Try this
// convenience macro for literal comparison
#define STRNCMP(str, literal) strncpy(str, literal, strlen(literal))
// keeping your constants in one place makes tweaking them easier
const int scanIndicator = D7;
const int servoLatency = 250;
const int servoClosed = 134;
const int servoOpen = 32;
const char barcode[] = "X00216DEMN";
void setup() {
Serial.begin(9600);
Serial1.begin(9600);
pinMode(scanIndicator, OUTPUT); // for feedback regarding the scan
servo.attach(A0);
servo.write(servoClosed);
delay(servoLatency);
servo.detach(); // disengage servo after movement to save power
while(Serial1.read() >= 0) Particle.process(); // flush the RX buffer of any data already present
digitalWrite(scanIndicator, HIGH); // ready for first scan
}
void loop() {
// do other stuff independent of your actual scan
if (Serial1.available() < strlen(barcode)) return; // if not enough data arrived so far bail out
char scan[64];
digitalWrite(scanIndicator, LOW); // indicate a scan is being processed
Serial1.readBytes(scan, strlen(barcode)); // we know we have enough data, so read
scan[strlen(barcode)] = '\0'; // terminate the string
Serial.println(scan); // print what we got
if (STRNCMP(scan, barcode) == 0) {
servo.attach(A0);
servo.write(servoOpen);
delay(3000); // I'd rather use a timer instead of blocking delay
servo.write(servoClosed);
delay(servoLatency);
servo.detach();
}
while(Serial1.read() >= 0) Particle.process(); // flush the RX buffer while allowing for more data
// to stream in as long the scanner keeps chatting
digitalWrite(scanIndicator, HIGH); // ready for next scan
}
My bad about the char scan array size - should have been bigger than the 10 chars barcode shown in the compare to value but I was trying to give guidance not an exact solution! Printing out the c string wasn’t in the example!