Has anyone successfully transmitted serial data over WiFi? My goal is to transmit bar codes that are read by a PS2/Serial bar code scanner to a computer (and eventually to a smart phone). I am still working on the library that allows the bar code scanner to function (see this thread), but once it is working, wireless communication of the text strings resulting from scanned bar codes will need to occur. I have read that this can be accomplished with the Arduino, but I want to make sure that I am using best practices for my project. I am definitely open to suggestions on how this might be accomplished in another way. Any thoughts?
There are several different ways.
If your Core will be connected to the Spark cloud or a local cloud server, the easiest and standard way would be via Spark.publish
or a Spark.variable
, but this will limit each seperate transmittable string to a max. length of 63 bytes for publish and 622 bytes for a string variable.
Otherwise you could use the TCPServer
/TCPClient
or UDP
objects.
Once you have decided what way you want to go, you’ll find any support you need here.
With the help of @kennethlimcp, I’ve got the barcode scanner up and running using serial. I’ve been reading up on the aforementioned methods of WiFi data transmission and Spark.variable() should suit my needs nicely. The usage, as described in the docs as well as in @binaryfrost 's example seems relatively straightforward and I have successfully tested it out on some analog input data from a force sensor. What I am now grappling with is how to reference serial data as a Spark.variable() string. Any thoughts on this? I will be working on this over the weekend and will post any successful attempts.
What do you mean by this?
On the Core you read your serial data into the buffer you have provided when you set up the Spark.variable
(e.g. resultstr
for binaryfrost's example)
int pos = 0; // position counter of char in string
...
while(kbddataavailable) // pseudocode - you know how to test availability
resultstr[pos++] = keyboard.read(); // read one byte
...
resultstr[i] = '\0'; // add zero terminator
Ha, exactly what I was asking, I didn’t fully understand the role of resultstr
. Thanks for the clarification, it should be helpful.
I think that I’m getting close. My entire code is below, but my problem is in the last several lines, shown here for convenience:
if (keyboard.available()) { barcodestr[pos++] = keyboard.read(); barcodestr[i] = '\0'; }
My limited knowledge of the syntax around string variables and positions is the source of my difficulty here. I am able to read barcodes successfully via serial and my other two spark variables work fine, but I am missing something on the string variable. Is my mistake obvious? Any thoughts would be a huge help - again.
#include "PS2Keyboard.h"
// Create a variable that will store the mass value
int analogmass = 0;
// Create a variable that will store the voltage value to calculate mass later
double voltage = 0.0;
//Create a varible for motion sensor
int motion = 0;
//Create a variable for barcodes
char barcodestr[64];
const int DataPin = 1;
const int IRQpin = 0;
PS2Keyboard keyboard;
void setup()
{
// Register a Spark variables here
Spark.variable("analogmass", &analogmass, INT);
Spark.variable("motion", &motion, INT);
Spark.variable("barcodestr", &barcodestr, STRING);
// Connect the load cell to A7 and configure it
// to be an input
pinMode(A7, INPUT);
// Connect the PIR to D3 and configure it
// to be an input
pinMode(D3, INPUT);
// Connect the barcode scanner to D0 and D1 and configure them
keyboard.begin(DataPin, IRQpin, PS2Keymap_US);
//keyboard.begin(DataPin, IRQpin, PS2Keymap_German);
//keyboard.begin(DataPin, IRQpin, PS2Keymap_French);
Serial.begin(9600);
Serial.println("International Keyboard Test:");
}
void loop()
{
int loadreading = 0;
int motionreading = 0;
int pos = 0;
int i = 0;
// Keep reading the sensor value so when we make an API
// call to read its value, we have the latest one
loadreading = analogRead(A7);
motionreading = digitalRead(D3);
// The returned value from the Core is going to be in the range from 0 to 4095
// Calculate the voltage from the sensor reading
//voltage = (loadreading * 3.3) / 4095;
voltage = (loadreading * 1) / 1; //placeholder constants
// Calculate the mass and update our static variable
analogmass = (voltage - 0) * 1;
if (motionreading ==HIGH) {motion = 1;}
if (motionreading ==LOW) {motion = 0;}
if (keyboard.available()) {
barcodestr[pos++] = keyboard.read();
barcodestr[i] = '\0';
}
}
As it seems you only read one byte of your string.
While my code from above uses a while
loop to read all bytes available and then add a zero-term-byte at the end of the string, you only perform keyboard.read()
once in your loop and terminate the string after each character.
Since I don’t know how long your scanner messages will be and if they have a pattern by which you could check if you have received all of your data, you also might have to test for more than only keyboard.available()
to determin the end of any single message - if you have quite long messages, you may even have to add some delay
to the read loop.
Thanks for the quick reply - that makes sense, so I would need a line for each byte. Is there another way to accomplish this without a byte per line (just curious)? As you mentioned, barcodes may vary in length, so I should make sure I allow for as many bytes as the longest code would have. Do I need to use some “if” logic to determine what the byte should be in the event that the string is shorter that the maximum length? I have been looking around a bit but I haven’t found a good resource on the syntax surrounding strings, character positions, etc. do you know of one? For instance I am not sure what the “++” following “pos” indicates, and do the numbers in
int pos = 0;
int i = 0;
represent the start and end of the string (so the second zero should be 20, etc.)?
I want to make sure I am understanding the following:
For my other two sensors and their spark variables, the data input is constant - when I make the GET request from my REST client, the data that is returned is the current value of the continuous data stream. When I scan a barcode, i.e. when a “keyboard” is available, there is only a moment for which the string would be available - as I understand it, the purpose of the barcodestr
buffer is to hold this data for retrieval as a spark variable, is this correct? Similar to the way the serial monitor holds the barcode until another is scanned.
Thanks again for all the help on this, the support on these forums is excellent.
I see, you are not very familiar with C syntax
So only the very basics for your problem (for more you’d need a C starters tutorial which you’ll find plenty online):
-
No, you don’t have to write one line per byte to read. This is done via so called loops which repeat the following code line or code block (between { and }) until some abort condition hits (hence my suggestion to use
while(condition)
which repeats as long as condition is true). -
The construct
barcodestr[pos++] = keyboard.read();
makes use of the so called “post increment”++
. This means, that afterpos
is used the value ofpos
will be incremented by one (there are also "pre increment "[++pos]
first increment & use thereafter and the same with decrement--
). You could also write
while(condition == true)
{
barcodestr[pos] = keyboard.read();
pos = pos + 1;
// or pos += 1;
// or ++pos;
// or pos++;
// all these versions do the same
}
-
Strings are not more than a bunch of characters stored in memory on after another and the memory location (address) where the first character is stored is considered to be the start or base of the string and the end is denoted by a NULL-byte (
'\0'
). Even if you have 64 byte for the string reserved, the actual string length is only counted from the base address to the last character which is NOT NULL. This also means, if you fail to have a'\0'
within your 64 byte, you might end up reading the string beyond the reserved space, giving you wrong data and maybe even corrupting other data. -
Constructs like the mentioned
int pos = 0;
do two things.
First to declare a variablepos
of typeint
(32bit integer number).
Second it sets the initial value ofpos
to zero (e.g. to start counting the position where to place the first character to be read). This is important because C does not do any initialisation by itself (you may find any “random” value inpos
that was in storage from previous usage of the same memory location).
As a quick starter you could also look into Spark docs here
http://docs.spark.io/firmware/#language-syntax
Or any “C for beginners” web search
e.g. http://www.learn-c.org/
I really appreciate you taking the time to lay this out, it is extremely helpful. You are indeed correct, I’m a noob but hungry for knowledge, thanks for pointing me in the right direction. I’ll be hitting the books over the long weekend.
Just a suggestion. When writing to a memory array, make sure you don’t overrun it. For getting data out quick it might work to continue filling the buffer, then for each read call a resetBuffer function to set the index back to 0. If you lose any data, you could double buffer it by calling a function that copies the data from your read buffer to the Spark.variable buffer, then resets the index.
#define SIZE 64
int index = 0;
char buffer[SIZE+1];
int resetBuffer()
{
index = 0;
buffer[0] = 0;
return 0;
}
void setup()
{
...all the other stuff...
Spark.function("reset", resetBuffer);
Spark.variable("barcodestr", buffer, STRING);
Spark.variable("dataAvail", index, INTEGER);
}
void loop()
{
...stuff removed...
while(keyboard.available() && index < SIZE)
{
buffer[index++] = keyboard.read();
buffer[index] = 0;
}
}
// the alternative
#define SIZE 64
int index = 0;
char buffer[SIZE+1];
char vbuffer[SIZE+1];
int copyBuffer()
{
strcpy(vbuffer, buffer);
index = 0;
vbuffer[0] = 0;
return 0;
}
void setup()
{
...all the other stuff...
Spark.function("copy", copyBuffer);
Spark.variable("barcodestr", vbuffer, STRING);
Spark.variable("dataAvail", index, INTEGER);
}
void loop()
{
...stuff removed...
while(keyboard.available() && index < SIZE)
{
buffer[index++] = keyboard.read();
buffer[index] = 0;
}
}
I agree, that was one reason for my earlier comment about the expected message lengths and "format" and the warning about exceeding 64byte in my post before.
Just one detail on top.
If you are using a Spark.variable
your buffer could actually be up to 622 bytes if you expect messages this long and don't want them split.
On the other hand, if you'd want to use Spark.publish()
instead you should only have 63byte messages, so you'd need to #define SIZE 63
.
BTW, @btheye: Ben, I don't think this is true
Since you say yourself
Noobs don't know but don't want to either - that's obviously not true in your case. That's the difference between a Noob and a Novice/Newby
We all were novices at one point, but we did and liked to learn and now help others doing so, too.
Keep your curiosity alive
Thanks to both you and @ScruffR for the guidance here - I have yet to successfully implement the reset or double buffer functionality as I am still working on the data acquisition. Currently I can scan one barcode per flash, and I must do so when the led on the core is flashing green, before it turns cyan. After it begins to breath cyan, a barcode scan only updates the first two characters. For instance, a barcode is 016000275669. When it is scanned during the blinking green window, I get 016000275669. Subsequent scans only change the first two characters, yielding for example j616000275669. The two modified characters are not accurate, and are always “j” (a prefix seen in the serial monitor for any barcode scanned) followed by a random number contained in the barcode that was scanned. If I wait until the breathing cyan phase to scan a barcode, I only get “j” followed by a random number contained in the barcode that was scanned. For example a scan of 016000275669 at this point gives j0 or j6, etc.
Please correct me if I am approaching this incorrectly, but I believe that the issue is in the keyboard.read loop portion of the code and that possible solutions might involve a delay of some type. Also, the presence of resultstr[i] = '\0';
does not seem to have any effect. My code follows, any thoughts/comments would be greatly appreciated.
#include "PS2Keyboard.h"
// Create a variable that will store the mass value
int analogmass = 0;
// Create a variable that will store the voltage value to calculate mass later
double voltage = 0.0;
//Create a varible for motion sensor
int motion = 0;
//Create a variable for barcodes
char barcodestr[128];
const int DataPin = 1;
const int IRQpin = 0;
PS2Keyboard keyboard;
void setup()
{
// Register a Spark variables here
Spark.variable("analogmass", &analogmass, INT);
Spark.variable("motion", &motion, INT);
Spark.variable("barcodestr", &barcodestr, STRING);
// Connect the load cell to A7 and configure it
// to be an input
pinMode(A7, INPUT);
// Connect the PIR to D3 and configure it
// to be an input
pinMode(D3, INPUT);
// Connect the barcode scanner to D0 and D1 and configure them
// to be an input
keyboard.begin(DataPin, IRQpin, PS2Keymap_US);
//keyboard.begin(DataPin, IRQpin, PS2Keymap_German);
//keyboard.begin(DataPin, IRQpin, PS2Keymap_French);
Serial.begin(9600);
Serial.println("International Keyboard Test:");
}
void loop()
{
int loadreading = 0;
int motionreading = 0;
int pos = 0;
int i = 64;
// Keep reading the sensor value so when we make an API
// call to read its value, we have the latest one
loadreading = analogRead(A7);
motionreading = digitalRead(D3);
// The returned value from the Core is going to be in the range from 0 to 4095
// Calculate the voltage from the sensor reading
//voltage = (loadreading * 3.3) / 4095;
voltage = (loadreading * 1) / 1;
// Calculate the mass and update our static variable
analogmass = (voltage - 0) * 1;
if (motionreading ==HIGH) {motion = 1;}
if (motionreading ==LOW) {motion = 0;}
while (keyboard.available()) {
barcodestr[pos++] = keyboard.read();
}
}
I guess it is a timing problem.
You could use a delay(25)
inside the while()
loop. The Core might be reading faster than the scanner delivers the data causing your messages to be split.
But if you want to use most of the Cores power you might consider a two-step approach, without delay.
First you collect all the data into a buffer string till you are convinced to have it all (I’d expect some kind of end-marker in the scanned code - e.g. new-line, carriage return, …).
Then once you got it all you’d strcpy()
the buffered string into your barcodestr[]
.
This way you should never have incomplete scans in your Spark.variable
.
At the moment, since you got the pos
counter inside loop()
, your varable
gets overwritten with each visit to loop()
even if the message wasn’t received completely.
But as you have revealed that you do get a start marker j
and we are not sure if you get an end marker for each scan, you could make pos
global and attach the reset of pos
to the occurance of j
(providing your scans won’t contain a j
). But if you get an end marker, it would be best to use this instead.
...
int c;
...
while(keyboard.available()) {
c = keyboard.read();
switch (c) {
case -1: // should never happen, but to be safe
break;
case '\r': // carriage return,
case '\n': // new line and
case '\0': // zero terminator denote end of scan
strcpy(barcodestr, dblbuf); // make scan available to cloud
pos = 0; // prepare for new scan
break;
case 'j': // start of new scan
pos = 0;
default:
dblbuf[pos++] = c;
break;
}
dblbuf[pos] = '\0'; // always terminate the string
}
...
Edit: Sorry, I misread the j
thing. It’s a bogus character, so forget that part of the post, but I left it in, to demonstrate how you could use a prefixed start marker, if there was one.
To find out where the 'j'
comes from I’d have to have a closer look at the lib. Can’t promise when, tho’.
Thank you for laying it out so clearly, again. Since I am on a time constraint, I’ll be using the delay for the next few days, but I will attempt to implement the two-step method this weekend. I do have a question on the start marker/bogus character distinction. The “j” does not exist at the start of any barcodes, but it does precede the barcodes when scanned. I could not find anything in the library that indicates the addition of a “j” prefix, could this be happening in the scanner itself? If it is happening within the scanner, then it could be used as a start marker, correct? I do not get an end marker - if I added an end marker via the library, would it be of any consequence? In other words, if a start or end marker is added through the library, would it be possible to use it? Another thought - if the barcodes being scanned are all the same number of characters, could I use this for a similar effect? Thanks again for all the help.
As for the “j”, I would consider this a very odd choice as a marker, since it could appear in alpha numeric barcodes at any other position too.
Adding an end marker yourself would not really help, since you’d have no way of deciding if the transmission is complete or not, so you wouldn’t know if you’d have to add the marker or not.
But if you can definetly confirm that you’re dealing with fixed length transmissions, it would be the best to use this for the task. I’d additionally add a timeout logic for the case that you only get a corrupted (too short) transmission, so that you won’t wait forever.