I have a problem. Believe me, I started using this strtok() function at 1 or 2AM. and it is 4:22AM now. >.<
The problem is this:
1. WHEN I INPUT A "blue", the three tokens are okay.
2. When I input a "red" or a "green", the three tokens are NULL :( .
const char s[2] = "~"; //for cutting;
char inData[100]; // Allocate some space for the string
char *token;
char *token2;
char *token3;
char x1[100];
char x2[100];
char x3[100];
char Comp(char* This) {
while (Serial.available() > 0) // Don't read unless
// there you know there is data
{
if(index < 99) // One less than the size of the array
{
inChar = Serial.read(); // Read a character
inData[index] = inChar; // Store it
index++; // Increment where to write next
// inData[index] = '\0'; // Null terminate the string
}
}
token = strtok(inData, s);
strcpy(x1,token);
token2 = strtok(NULL, s);
strcpy(x2,token2);
token3 = strtok(NULL, s);
strcpy(x3,token3);
if (strcmp(x1,This) == 0) {
Serial.println(x1);
Serial.println(x2);
Serial.println(x3);
for (int i=0;i<99;i++) {
inData[i]=0;
}
index=0;
return(0);
}
else {
return(1);
}
}
How I call the function Comp:
if(Comp("blue")==0){
Serial.println("BLUE SELECTED");
analogWrite(9, 0);
analogWrite(10,255);
analogWrite(11,255);
}
if(Comp("green")==0){
Serial.println("GREEN SELECTED");
analogWrite(10,0);
analogWrite(11,255);
analogWrite(9,255);
}
if(Comp("red")==0){
Serial.println("RED SELECTED");
analogWrite(10,255);
analogWrite(11,0);
analogWrite(9,255);
}
OUTPUTS:
when I input: "blue~lalalalal~kakakakaekkewew"
it outputs:
blue
lalalalal
kawawawawewew
blue selected
when I input: "red~123~321
it outputs:
red
red selected
when I input: "green~123~321"
it outputs
green
green selected
this is the way I solved the bug.
changed the way I receive the data.
char Comp(char* This) {
while(Serial.available()) {
inChar = Serial.read();
inData.concat(inChar);
}
strcpy(inData2, inData.c_str());
token = strtok(inData2, s);
strcpy(x1,token);
token = strtok(NULL, s);
strcpy(x2,token);
token = strtok(NULL, s);
strcpy(x3,token);
if (strcmp(x1,This) == 0) {
Serial.println(x1);
Serial.println(x2);
Serial.println(x3);
inData = "";
inChar = '\0';
return(0);
}
else {
return(1);
}
}
Related
I'm coding a parser for my Arduinoproject. I have a long charArray that contains multiple "packages" in the form of:
# package beginns
adress
; seperating character
adress
; seperating character
command
; seperating character
data
* package ends
One input could be:
#A0001;B0001;A;2456;*#A0002;B0002;B;7615;*#A0003;B0003;C;8943;*
The goal is to write a Parser that takes a charArray and splits it at one char ('#') and than a second time with another char (';'). The problem is that the outer splitting is only done once and than stopps. I think it has something to do with the pointer, but don't know what to do.
My Code:
void setup() {
Serial.begin(9600);
char test[] = "#A0001;B0001;A;2456;*#A0002;B0002;B;7615;*#A0003;B0003;C;8943;*";
Serial.print("Test: ");
Serial.println(test);
Serial.println("--------------------");
parseCurrentStream(test);
Serial.println("-----------END_OF_CODE------------");
}
void parseCurrentStream(char* input){
int commandCount = getCountOfCharInString(input, '*');
package packageList[commandCount];
commandCount = 0;
char* piece = strtok(input, "#");
while (piece != NULL){
Serial.println(piece);
package pack = getPackage(piece);
printPackage(pack);
commandCount++;
piece = strtok(NULL, "#");
}
}
package getPackage(char* packageString){
Serial.println("---Start_Parsing---");
Serial.print("StringInput: ");
Serial.println(packageString);
bool corruptedData = false;
if(!isEndCharExisting(packageString)){
corruptedData = true;
}
// final Fields
char* receiver;
char* transmitter;
char command;
char* data;
bool empty;
char* piece = strtok(packageString, ";");
int counter;
while (piece != NULL && !corruptedData){
Serial.print(corruptedData);
Serial.print(" | Piece ");
Serial.print(counter);
Serial.print(": ");
Serial.println(piece);
switch(counter){
case 0:
if(strlen(piece) == 5){
receiver = piece;
} else {
corruptedData = true;
}
break;
case 1:
if(strlen(piece) == 5){
transmitter = piece;
} else {
corruptedData = true;
}
break;
case 2:
if(strlen(piece) == 1){
command = piece[0];
} else {
corruptedData = true;
}
break;
case 3:
if(strlen(piece) == sizeOfCommand(command)){
data = piece;
} else {
corruptedData = true;
}
break;
case 4:
if(!(strlen(piece) == 1 && piece[0] == '*')){
corruptedData = true;
}
break;
default:
corruptedData = true;
break;
}
counter++;
piece = strtok(NULL, ";");
}
struct package finalPackage;
if(corruptedData){
finalPackage = {receiver, transmitter, command, data, true};
} else {
finalPackage = {receiver, transmitter, command, data, false};
}
Serial.println("---End_Parsing---");
return finalPackage;
}
Output:
Test: #A0001;B0001;A;2456;*#A0002;B0002;B;7615;*#A0003;B0003;C;8943;*
--------------------
A0001;B0001;A;2456;*
---Start_Parsing---
StringInput: A0001;B0001;A;2456;*
0 | Piece 0: A0001
0 | Piece 1: B0001
0 | Piece 2: A
0 | Piece 3: 2456
0 | Piece 4: *
---End_Parsing---
Package:
A0001
B0001
A
2456
0
-----------------
-----------END_OF_CODE------------
You can see that for the first iteraton it works perfectly, but the second "string" (#A0002;B0002;B;7615;*) is not parsed...
When i'm not using my function getPackage() the substrings are printed as expected. I have found some advice to copy the char before inserting it to the function but this also didn't help.
char pieceCopy[strlen(piece)];
strcpy(pieceCopy, piece);
Because you are splitting for different tokens at the same time (both in parseCurrentStream and in getPackage), you are messing up the internal state of strtok. However, using one strtok_r for each tokenization, you can provide a pointer to a char pointer, that each different strtok_r can use to save its current state. See the example in the link provided. strtok_r is especially useful in multi-threaded environments.
char *strtok_r(char *str, const char *delim, char **saveptr);
char input[] = "the quick brown fox";
char* token;
char* rest;
char* str = input;
while ((token = strtok_r(str, " ", &rest))) {
str = NULL;
printf("%s\n", token);
}
Thanks for all of your support!!!
For me the solution of #Gerhardh worked perfectly.
The strsep() was availbale for me.
My code looks like this now:
void parseCurrentStream(char* input){
int commandCount = getCountOfCharInString(input, '*');
char* piece;
char* string;
string = strdup(input);
while( (piece = strsep(&string,"#")) != NULL ){
if(strlen(piece) > 0){
package pack = getPackage(piece);
printPackage(pack);
}
}
}
package getPackage(char* packageString){
Serial.println("---Start_Parsing---");
Serial.print("StringInput: ");
Serial.println(packageString);
bool corruptedData = false;
// final Fields
char* receiver;
char* transmitter;
char command;
char* data;
bool empty;
//char* piece = strtok(packageString, ";");
int counter = 0;
char* piece;
char* string;
string = strdup(packageString);
while ((piece = strsep(&string,";")) != NULL){
Serial.print(corruptedData);
Serial.print(" | Piece ");
Serial.print(counter);
Serial.print(": ");
Serial.println(piece);
switch(counter){
case 0:
if(strlen(piece) == 5){
receiver = piece;
} else {
corruptedData = true;
}
break;
case 1:
if(strlen(piece) == 5){
transmitter = piece;
} else {
corruptedData = true;
}
break;
case 2:
if(strlen(piece) == 1){
command = piece[0];
} else {
corruptedData = true;
}
break;
case 3:
if(strlen(piece) == sizeOfCommand(command)){
data = piece;
} else {
corruptedData = true;
}
break;
case 4:
if(!(strlen(piece) == 1 && piece[0] == '*')){
corruptedData = true;
}
break;
default:
corruptedData = true;
break;
}
counter++;
}
#include <stdio.h>
#include <string.h>
void myFgets(char str[], int n);
int main(int argc, char** argv)
{
if (argc < 2)
{
printf("Usage: csv <csv file path>\n");
return 1;
}
else
{
char ch = ' ', search[100], dh = ' ';
int row = 1;
printf("Enter value to search: ");
myFgets(search, 100);
FILE* fileRead = fopen(argv[1], "r");
if (fileRead == NULL)
{
printf("Error opening the file!\n");
return 1;
}
while ((ch = (char)fgetc(fileRead)) != EOF)
{
char str[100];
int i = 0, pos = ftell(fileRead);
while ((dh = (char)fgetc(fileRead)) != ',')
{
str[i] = dh;
i++;
}
fseek(fileRead, pos + 1, SEEK_SET);
if (strstr("\n", str) != NULL)
{
row++;
}
if (strstr(search, str) != NULL)
{
printf("Value was found in row: %d\n", row);
break;
}
}
}
getchar();
return 0;
}
/*
Function will perform the fgets command and also remove the newline
that might be at the end of the string - a known issue with fgets.
input: the buffer to read into, the number of chars to read
*/
void myFgets(char* str, int n)
{
fgets(str, n, stdin);
str[strcspn(str, "\n")] = 0;
}
in line 39 im getting an error but idk why it seems like im doing everything fine
im trying to loop through the rows and split them by the ',' so i could check if search == to it but its not wokring
im using function strstr to compare 2 strings with each other it works fine and all but the only problem is at the dh
i did fseek after the dh so i dont write in the wrong place in the ch loop
You forgot to terminate the string.
while ((dh = (char)fgetc(fileRead)) != ',')
{
str[i] = dh;
i++;
}
str[i] = '\0'; /* add this to terminate the string */
Also it looks like if (strstr(search, str) != NULL) should be if (strstr(str, search) != NULL) to search for the value to search from the contents of the file.
I want to fill a label with some text read from a file.msg. I think i've somehow managed to read from the file but now i need to fill the label with what i've read.
void __fastcall TErrorPanel::lblOpMsgErClick(TObject *Sender)
{
char OutBuf[500];
char OutBuf2[500];
static int Func_exec = 0;
if (Func_exec == 0)
{
Func_exec = 1;
if (tpgm_cfg.TestMod.RejectModule == 0)
{
GetMessage(1, SYSMSGIMG, OutBuf, gPathMsgFile);
}
else
{
GetMessage(2, SYSMSGIMG, OutBuf2, gPathMsgFile);
}
Func_exec = 0;
}
return;
}
The GetMessage custom function, at the moment it shows MsgNF, it looks like it isn't picking up the content of the OutBuf
void GetMessage(int Code,char *Section, char *OutBuf, char *PathMsgFile, int InsErrCode)
{
char buff[512],Msg[500],sCode[10];
char *p;
int cmpres;
long rOffset = 0;
itoa(Code,sCode,10);
::GetPrivateProfileString(Section, sCode, "MsgNf", buff, sizeof(buff), PathMsgFile);
rOffset = ::GetPrivateProfileInt(Section, "Offset", 0, PathMsgFile);
cmpres=strcmp("MsgNf",buff);
if (cmpres==0)
{
sprintf(Msg,"Message[%ld]: Not Found !",Code + rOffset);
}
do
{
p = strchr (buff , '|');
if(p != NULL)
{
*p = '\n';
}
}while(p != NULL);
strcpy(OutBuf, buff);
if (strcmpi(SYSERRORMSG,Section)==0)
{
sprintf(buff,"Error[%ld]-%s", Code + rOffset, OutBuf);
strcpy(OutBuf,buff);
rmLastErrorCode = Code;
}
return;
}
This is how you generally set the text to display:
label_name->Caption = "Text to display";
However, I don't know how to fit that into the code you've shown.
I'm working on an Arduino sketch and I'm trying to change a variable with serial. I'm using some example code that I found on arduino.cc to start with. I'm trying to modify the code with an "if statement" to update a variable timevar with integerFromPC; the problem I'm having is if I type a number higher than 4 digits like 99999 it prints out the wrong data and the variable timevar doesn't get updated correctly? I'm not sure what to do?
unsigned long timevar = 1000000;
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
// variables to hold the parsed data
char messageFromPC[numChars] = {0};
int integerFromPC = 0;
int ifpc = 0;
float floatFromPC = 0.0;
boolean newData = false;
//============
void setup() {
Serial.begin(9600);
Serial.println("This demo expects 3 pieces of data - text, an integer and a floating point value");
Serial.println("Enter data in this style <HelloWorld, 12, 24.7> ");
Serial.println();
}
//============
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
showParsedData();
newData = false;
}
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars,","); // get the first part - the string
strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
integerFromPC = atoi(strtokIndx);
strtokIndx = strtok(NULL, ",");
floatFromPC = atof(strtokIndx); // convert this part to a float
}
//============
void showParsedData() {
if (strcmp(messageFromPC, "set time") == 0)
timevar = integerFromPC;
Serial.print("Time Set To ");
Serial.println(integerFromPC);
Serial.println(timevar);
}
//do other stuff
You declare int integerFromPC. int on Arduino is 16 bits. 99999 doesn't fit into 16 bits, so will appear mod 2^16 as 34463. Use long instead as you do for timeVar and it will be ok for up to +/- 2^31 .
The following code works, but is about twice as inefficient compared to when I use a (linux) pipe that gives unzipped data to the (modified) program. I need a steady stream within the program which I can keep splitting by \n. Is there a way to do this using a (string?) stream or any other trick?
int main(int argc, char *argv[]) {
static const int unzipBufferSize = 8192;
long long int counter = 0;
int i = 0, p = 0, n = 0;
int offset = 0;
char *end = NULL;
char *begin = NULL;
unsigned char unzipBuffer[unzipBufferSize];
unsigned int unzippedBytes;
char * inFileName = argv[1];
char buffer[200];
buffer[0] = '\0';
bool breaker = false;
char pch[4][200];
Read *aRead = new Read;
gzFile inFileZ;
inFileZ = gzopen(inFileName, "rb");
while (true) {
unzippedBytes = gzread(inFileZ, unzipBuffer, unzipBufferSize);
if (unzippedBytes > 0) {
unzipBuffer[unzippedBytes] = '\0'; //put a 0-char after the total buffer
begin = (char*) &unzipBuffer[0]; // point to the address of the first char
do {
end = strchr(begin,(int)'\n'); //find the end of line
if (end != NULL) *(end) = '\0'; // put 0-char to use it as a c-string
pch[p][0] = '\0'; \\ put a 0-char to be able to strcat
if (strlen(buffer) > 0) { // if buffer from previous iteration contains something
strcat(pch[p], buffer); // cat it to the p-th pch
buffer[0] = '\0'; \\ set buffer to null-string or ""
}
strcat(pch[p], begin); // put begin (or rest of line in case there was a buffer into p-th pch
if (end != NULL) { // see if it already points to something
begin = end+1; // if so, advance begin to old end+1
p++;
}
if(p>3) { // a 'read' contains 4 lines, so if p>3
strcat(aRead->bases,pch[1]); // we use line 2 and 4 as
strcat(aRead->scores,pch[3]); // bases and scores
//do things with the reads
aRead->bases[0] = '\0'; //put them back to 0-char
aRead->scores[0] = '\0';
p = 0; // start counting next 4 lines
}
}
while (end != NULL );
strcat(buffer,pch[p]); //move the left-over of unzipBuffer to buffer
}
else {
break; // when no unzippedBytes, exit the loop
}
}
Your main problem is probably the standard C string library.
With using strxxx() funcions, you are iterating through the complete buffer multiple times each call, first for strchr(), then for strlen(), then for each of the strcat() calls.
Using the standard library is a nice thing, but here, it's just plain inefficient.
Try if you could come up with something simpler that touches each character only once like (code just to show the principle, do not expect it working):
do
{
do
{
*tp++ = *sp++;
} while (sp < buffer_end && *sp != '\n');
/* new line, do whatever it requires */
...
/* reset tp to beginning of buffer */
} while (sp < buffer_end);
I am trying to get this to work, but all it does is giving a Segmentation Fault at runtime:
do {
unzippedBytes = gzread(inFileZ, unzipBuffer, unzipBufferSize);
if (unzippedBytes > 0) {
while (*unzipBuffer < unzippedBytes) {
*pch = *unzipBuffer++;
cout << pch;
i++;
}
i=0;
}
else break;
} while (true);
What am I doing wrong here?