#include "parsing.h"
#define MAXVALUES 20
int strPos;
void init_com(commande &com)
{
int i = 0 ;
for (i ; i < MAXVALUES ; i++)
{
com.parsedFunction[i] = '\0' ;
com.parsedParameter[i] = '\0' ;
}
}
char* parseFunction(char strInput[], commande &com)
{
strPos = 0;
for(strPos ; strInput[strPos] != '@'; strPos++)
{
com.parsedFunction[strPos] = strInput[strPos];
}
return com.parsedFunction;
}
char* parseParameter(char strInput[], commande &com)
{
strPos++ ;
int strPos0 = strPos ;
for(strPos; strInput[strPos] != '!'; strPos++)
{
com.parsedParameter[strPos-strPos0] = strInput[strPos];
}
return com.parsedParameter;
}
int strToInt(char num[])
{
int t = sizeof(num)/sizeof(char) ;
int s = 0 ;
for (int i = 0 ; i <= t ; i++)
{
s *= 10 ;
s += (int) (num[i]-'0') ;
}
return s ;
}
And here is the way I want to use it with my Arduino (that's a beginning, starting by trying to display the results and then using them).
#include "WiFly.h"
#include "Servo.h"
#include "parsing.h"
#define MAXVALUES 20
char passphrase[] = "a269c7a7297a99669ee443af29";
char ssid[] = "Alice-dbde";
Server server(80);
Servo myservo;
Servo myservo2;
void setup() {
Serial.begin(9600);
Serial.println("Setting up");
WiFly.begin();
Serial.println("WiFly started");
if (!WiFly.join(ssid, passphrase)) {
while (1) {
Serial.print("Error");
}
}
Serial.print("IP: ");
Serial.println(WiFly.ip());
myservo.attach(5);
myservo2.attach(4);
server.begin();
}
void initArray(char array[])
{
int i = 0 ;
for (i ; i < MAXVALUES ; i++)
{
array[i] = '\0';
}
}
void cloneArray(char a[], char b[])
{
int i = 0;
for (i ; i < MAXVALUES ; i++)
{
b[i] = a[i];
}
initArray(a);
}
void loop() {
Client client = server.available();
char buffer[MAXVALUES];
char commande[MAXVALUES];
initArray(buffer);
initArray(commande);
int i = 0;
if (client) {
boolean current_line_is_blank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (c=='!')
{
cloneArray(buffer,commande);
i=0;
}
if((c != '\n') && (c != ';') && (c != '!'))
{
buffer[i] = c;
i++;
}
Serial.println(commande);
actions(commande);
}
}
delay(100);
client.stop();
}
}
void actions(char comm[])
{
commande com;
Serial.println("Creation commande : OK");
init_com(com);
Serial.println("Init commande : OK");
parseFunction(comm, com) ;
Serial.println("ParseFunction commande : OK");
parseParameter(comm, com);
Serial.println("ParseParameter commande : OK");
}
And here is the output:
Setting up
WiFly started
Joining Alice-dbde
IP: 192.168.1.4
// HERE I SEND A COMMAND,LIKE UP@80!
Creation commande : OK
Init commande : OK
WiFly started
Setting up
WiFly started
Joining Alice-dbde
IP: 192.168.1.4
// HERE I SEND A COMMAND,LIKE UP@80!
Creation commande : OK
Init commande : OK
WiFly started
Setting up
WiFly started
Joining Alice-dbde
IP: 192.168.1.4
etc...
I think that's odd, it's as if my parseFunction() method reboot the Wifi Shield... Did I do anything that bad ? I think my functions are pretty simple and would never cause such behaviors O.o
Every time you read a character you send the 'commande' to actions(). Since the commande initially contains no '@' or '!' you will run off the end of the buffer and crash.
johnwasser:
Every time you read a character you send the 'commande' to actions(). Since the commande initially contains no '@' or '!' you will run off the end of the buffer and crash.
Oh yes, that makes sense.
I modified my code to this according to your advise :
if (c=='!')
{
cloneArray(buffer,commandes);
i=0;
actions(commandes);
}
And here is my output:
Setting up
WiFly started
Joining Alice-dbde
IP: 192.168.1.4
// HERE I SEND SALUT@80!
Creation commande : OK
Init commande : OK
salut
ParseFunction commande : OK
80
ParseParameter commande : OK
WiFly started
Joining Alice-dbde
Checkpoint 1
IP: 192.168.1.4
Well, now it works and it gets the function name and parameter, but it seems to reboot though...
@Grag38 : I don't think there is a problem since these are local variables (except the structure), so I can name then the way I want I guess.
NNzz:
I modified my code to this according to your advise :
You should put the '!' into the buffer before you try to parse the parameter.
if (c=='!')
{
bufer[i] = c;
cloneArray(buffer,commandes);
i=0;
actions(commandes);
}
In the loop where you are parsing and copying characters you should put in a check for the buffer length. If you don't your program will crash if you accidentally leave out the '@'.
I'd highly recommend making use of the C library string functions already available from the avr-libc library: avr-libc: <string.h>: Strings
Your parsing functions have a number of holes in them. I realize you have it working now, but it only works with valid commands. Send a variety garbage text to the unit and it will likely reset on you again. Not robust at all.
Thank you for your advice. I will try to do that, I don't know much about C++ and most of the tutorials on internet are just too difficult to understand for me, LOL. My commands will always be function@parameter!, I just want to get the function name and the parameter (which I cast into integer after), which functions of the string.h library would you recommand for that ? strtok() maybe ?
Googling each individual function should provide some useful links on their usage (beyond the simple descriptions of their usages on the avr-libc reference page).
A note on strtok(). This function modifies the existing C string (inserting NULL terminators where it finds the specified delimiters, and returning pointers to the start of each 'token' within the string). This isn't in line with your existing design that copies the parameters from the command string into your command struct. For that design, you should probably looking at strchr() and strcpy().
The most important is to define a good protocol between the different componants of your project (ie arduino and computer with server).
As you did your are using '@' and '!' symbols in your protocol to define an separator between command and data and an final order character.
Its works as you succeed of doing to work !
Things can sometimes be quite simple when the protocol is well constrcuted.
I just give you a way of how I proceed in my sketch and computer programs.
The rules are simple.
Every command begin with a '#' character
Each command name is 4 characters
Datas that follows are in ascii readable characters as "10"
Each command finish with the '!' characters
Example I use a command to send a gain value (from 0 to 72) of selected channel (from 1 to 96) for an audio preamplifier. Lets say that the name of this command is SETG (for Set Gain)
the command is then :
#SETG1072! -> SETGain to 10 of the channel 72.
so from it easy to implement a process to decode it :
char buff[128]; // a buffer of enough characters/digits
if (Serial.available()>0)
{
static int bufPos=0; // a Static buffer position index
byte ch; // last character read
ch=Serial.read(); // Get it
switch(ch)
{
case '#': // It is a new command start from the begining of the buffer
bufPos=0;
break;
case '!': // it is the last command : I put 0x00 so I can work with string functions
buff[bufPos]='\x0';
break;
default: // for all of the other store the character into the buffer and increment the position.
buff[bufPos++]=ch; // It's better to check that bufPos never exceed 127 ! to avoir overflow.
}
if (ch=='!') // ok we've got an full command the 4 First characters are the name of the command
{
byte index, channel, gain;
if (strstr(buff, "SETG")) // is it the SETG command ?
{
gain = (buff[4]-'0')*10 + (buff[5]-'0');
channel = (buff[6]-'0')*10 + (buff[7]-'0');
ad->SetGain(channel, gain);
}
if (strstr(buff, "RECA")) // Recall the memory of the audio
{
index = (buff[4]-'0')*10 + (buff[5]-'0');
ad->RecallFromMemory(index);
}
if (strstr(buff, "STOR")) // Store the memory of the audio
{
index = (buff[4]-'0')*10 + (buff[5]-'0');
ad->StoreToMemory(index);
}
}
Its easy, you did it. But I prefer to use :
1 start character : it means set the position of the buffer to 0
1 end character : it means ok, I ve got the command so proceed with datas.