Sending data from a text file

My project that I am working on is using the Xbox kinect along with the Arduino. All I’m doing is using the kinect to sense the motions that I am doing, and depending on what motion I do, it sends certain data to the Arduino from a text file.

To do this I am using a simple protocol. To start the protocol I send ‘S’ to the Arduino using the Serial library with Processing. After sending the ‘S’ I send a number associated with which motion I am doing. Then after the number, I send the data from the text file.

I included the setup(), loop(), and the function getProtocol() which is where I am having my problem. Also since running the serial monitor while something is writing to it never seems to work for me, I debug by using the blinkLED() function.

MAIN PROBLEM:
When Processing sends data to my Arduino, the Arduino does not get all the correct values. I get the very first 3 in the text file, but then after that it doesn’t work. Am I doing something wrong when I read the data from the Serial, or is it Processing that is sending some weird values? Am I completed off and is it a simple solution? I feel like I have over thought the problem and it’s a simple answer. If anymore information is needed I will gladly provide it, sorry if it’s not posted already.

Thanks in advance.

Arduino Code:

decode_results results;

struct Code {
  int codeType; // NEC, SONY, RC5, UNKNOWN
  unsigned long codeValue; // Decoded value
  int codeBits; // Number of bits in decoded value
  unsigned int *codeBuf; // Raw intervals in .5 us ticks
  int codeLength; // Number of records in rawbuf.
};

int indexStore = 0;
int indexSend = 0;
int indexPrint = 0;
int upper = 6;
int numCodes = 0;
Code dasCode[6];
// Instantiate Messenger object with the message function and the default separator (the space character)
Messenger message = Messenger(); 

void setup()
{
  Serial.begin(57600);
  irrecv.enableIRIn(); // Start the receiver
  pinMode(BUTTON_PIN, INPUT);
  pinMode(STATUS_PIN, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(2, OUTPUT);
  
  //message.attach(messageCompleted);
  
}

int lastButtonState;
int val;

void loop() {
  // If button pressed, send the code.
  int buttonState = digitalRead(BUTTON_PIN);
  if (lastButtonState == HIGH && buttonState == LOW) {
    Serial.println("Released");
    irrecv.enableIRIn(); // Re-enable receiver
  }

  if (buttonState) {
    Serial.println("Pressed, sending");
    //digitalWrite(STATUS_PIN, HIGH);
    //sendCode(lastButtonState == buttonState);
    sendArray(lastButtonState == buttonState);
    printArray();
    //blinkLED();
    //digitalWrite(STATUS_PIN, LOW);
    delay(50); // Wait a bit between retransmissions
  } 
  else if (irrecv.decode(&results)) {
    digitalWrite(STATUS_PIN, HIGH);
    //storeCode(&results);
    irrecv.resume(); // resume receiver
    digitalWrite(STATUS_PIN, LOW);
  }
  lastButtonState = buttonState;
  
  if(Serial.available() > 2) {
    
    val = Serial.read();
    
    if(val == 'S') {
      val = Serial.read();
      
      switch(val) {
        case -1:
          Serial.println("POWER OFF");
          
          break;
        case 0:
          Serial.println("POWER ON");
          
          break;
        case 1:
          Serial.println("CH UP");
          
          //digitalWrite(5, HIGH);
          getProtocol();
          //digitalWrite(5, LOW);
          
          break;
        case 2:
          Serial.println("CH DOWN");
          
          break;
        case 3:
          Serial.println("VOL UP");
          
          break;
        case 4:
          Serial.println("VOL DOWN");
          
          break;
        case 5:
          Serial.println("MUTE");
          
          break;
  }
      
    }
  }
  
}


void getProtocol() {
  
  //digitalWrite(5, HIGH);
  
  numCodes = Serial.read();
  
  if(numCodes == 3) {
    //blinkLED(3, 2);
    //return;
  }
  
  
  for(int i = 0; i < 3; i++) {
    
    blinkLED(1, 5);
    
    dasCode[i].codeType = Serial.read();
    dasCode[i].codeValue = Serial.read();
    dasCode[i].codeBits = Serial.read();
    dasCode[i].codeLength = Serial.read();
    
    if(dasCode[i].codeLength < 100) {
      blinkLED(1, 2);
      //return;
    }
    
    for(int k = 1; k <= dasCode[i].codeLength - 1; k++) {
      //digitalWrite(5, HIGH);
      dasCode[i].codeBuf[k] = Serial.read();
      //digitalWrite(5, LOW);
    }
    //digitalWrite(5, LOW);
  }
  
  blinkLED(1, 2);
  
  //digitalWrite(5, LOW);
  
}

As far as the Processing code goes, I am basically detecting each motion and send the integer associated with that motion to the sendCode() function. I send the code from the text file in case 1.

Processing Code:

void sendCode(int gest) {
  switch(gest) {
    case -1:
      
      break;
    case 0:
      
      break;
    case 1:
      println("-----START SENDING POWER-----");
      
      txtLines = loadStrings("PowerCode.txt");
      
      for(int i = 0; i < txtLines.length; i++) {
        subText = splitTokens(txtLines[i], ", ");
        //nums[] = 
        counter = 0;
        while(counter < subText.length) {
          myPort.write(Integer.parseInt(subText[counter]));
          //println(Integer.parseInt(subText[counter]));
          
          counter++;
        }
        //println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");
      }
      
      //myPort.write(3);
      //myPort.write(-1);
      //myPort.write(Integer.parseInt(subText[0]));
      //println(Integer.parseInt(subText[0]));
      
      println("-----DONE SENDING POWER-----");
      break;
    case 2:
      
      break;
    case 3:
      
      break;
    case 4:
      
      break;
    case 5:
      
      break;
  }
  
  
}

And when I use println(Integer.parseInt(subText[counter])) it prints exactly what is in the text file with no commas, and a line break after each number.

PowerCode.txt

3
-1, 0, 0, 18
9401, 6, 16, 5, 34, 4, 15, 5, 56, 5, 25, 5, 26, 4, 24, 4, 54, 4
-1, 0, 0, 18
261, 4, 18, 5, 36, 5, 37, 4, 15, 5, 15, 4, 57, 4, 15, 4, 15, 5
1, 551489775, 32, 0

Also since running the serial monitor while something is writing to it never seems to work for me, I debug by using the blinkLED() function.

Of course it doesn’t. Only one application can access the serial port at a time. That can be the Serial Monitor OR the Processing application.

You can send serial data from the Arduino to the Processing application, though, and simply have the Processing application print() what it receives.

        subText = splitTokens(txtLines[i], ", ");
        //nums[] = 
        counter = 0;
        while(counter < subText.length) {
          myPort.write(Integer.parseInt(subText[counter]));

Here, you are converting the strings to ints, and then converting the ints to strings. Why? Why not just send the strings?

The Processing application sends a stream of data. There are no breaks between values. There is nothing to indicate when the data is complete.

That will make collecting and parsing on the Arduino end more difficult than it needs to be.

On the Arduino side, you assume that all the data has arrived, even though sending serial data is ssslllooowww. You wait for at least 2 bytes, then proceed to read everything that was supposedly sent, even though most of it hasn’t arrived yet.

You are also assuming that the data was sent as ints, rather than strings. Not a valid assumption, I’m afraid.

Of course it doesn't. Only one application can access the serial port at a time. That can be the Serial Monitor OR the Processing application.

I apologize for not knowing that.

The Processing application sends a stream of data. There are no breaks between values. There is nothing to indicate when the data is complete.

Are you saying that somewhere in the text document I should have a value that tells it when to end? Or I need to go back and forth between Processing and the Arduino to tell Processing when Arduino has successfully stored the value?

That will make collecting and parsing on the Arduino end more difficult than it needs to be.

Please enlighten me on what your suggestion would be to do.

On the Arduino side, you assume that all the data has arrived, even though sending serial data is ssslllooowww. You wait for at least 2 bytes, then proceed to read everything that was supposedly sent, even though most of it hasn't arrived yet.

So is streaming data not the best way to go about doing this?

You are also assuming that the data was sent as ints, rather than strings. Not a valid assumption, I'm afraid.

Thank you for that, I had not noticed that before. I got rid of the Integer.parseInt() in the Processing code, and I found an ASCII to int conversion function to use in the Arduino code.

I can usually get the first value in my data (the number 3) but that's the only accurate part. I tried using the Serial.parseInt() function and changed my text document to just numbers and commas without having sets of data on separate lines. This had gotten me a little further, but when I get to my second for-loop, it seems to pause like the Serial.parseInt() no longer works.

Do you have any recommendations on communication between Processing and Arduino?

Are you saying that somewhere in the text document I should have a value that tells it when to end?

Look at what you wrote. See the breaks between words (values)? See the punctuation mark that indicates that the end of the sentence has been reached?

See how much easier my reply was to read than this?

LookatwhatyouwroteSeethebreaksbetweenwords(values)?Seethepunctuationmarkthatindicatesthattheendofthesentencehasbeenreached?

So is streaming data not the best way to go about doing this?

Streaming data is fine. if you define breaks between the values, and an end-of-packet marker.

I got rid of the Integer.parseInt() in the Processing code, and I found an ASCII to int conversion function to use in the Arduino code.

Posting the new code would be useful.

I tried using the Serial.parseInt() function and changed my text document to just numbers and commas without having sets of data on separate lines. This had gotten me a little further, but when I get to my second for-loop, it seems to pause like the Serial.parseInt() no longer works.

I'm not sure what the "having sets of data on separate lines" means. Show what the text file contains.

Do you have any recommendations on communication between Processing and Arduino?

Yes, and I am sharing them.

Look at what you wrote. See the breaks between words (values)? See the punctuation mark that indicates that the end of the sentence has been reached?

See how much easier my reply was to read than this?

LookatwhatyouwroteSeethebreaksbetweenwords(values)?Seethepunctuationmarkthatindicatesthattheendofthesentencehasbeenreached?

Firstly, I do not understand why you’re posting condescending comments. All I am here to do is get some help, learn, and hopefully help others. A simple yes would have sufficed. I found nothing constructive or helpful in this post.

This is the code I found to convert a string into an int. However, it seems as though Serial.read() returns a char, so I just modified it. The original code can be found here: http://soynerdito.blogspot.com/2012/02/how-to-convert-string-to-integer-in.html

int8_t satoi( char str ){  
  int8_t r = 0;  
   //Check if this is a number  
   if ( str < ':' && str > '/'){  
     // is a ASCII number, return it  
     r = r * 10;  
   r += (str - '0');  
   }else{  
    //i = len; //exit!  
    r = -1;  
   }    
  return r;   
 }

Here is the Arduino code:

void getProtocol() {
    
  numCodes = getData();
  
  
  for(int i = 0; i < numCodes; i++) {


    dasCode[i].codeType = getData();
    dasCode[i].codeValue = getData();
    dasCode[i].codeBits = getData();
    dasCode[i].codeLength = getData();
    
    
    for (int k = 0; k < dasCode[i].codeLength; k++) {
      //blinkLED(1, 5);
      
      if ((k % 2)) {
        // Mark
        dasCode[i].codeBuf[k] = (getData())*USECPERTICK - MARK_EXCESS;
      } 
      else {
        // Space
        dasCode[i].codeBuf[k] = (getData())*USECPERTICK + MARK_EXCESS;     
      }
      
   }
    
    
  }
  
}

int getData() {
  //blinkLED(1, 2);
  
  //return Serial.parseInt();
  //return satoi(Serial.parseInt());
  return satoi(Serial.read());
  
}

Here is how I modified the text document to see how it worked with Serial.parseInt().

3, -1, 0, 0, 18, 9401, 6, 16, 5, 34, 4, 15, 5, 56, 5, 25, 5, 26, 4, 24, 4, 54, 4, -1, 0, 0, 18, 261, 4, 18, 5, 36, 5, 37, 4, 15, 5, 15, 4, 57, 4, 15, 4, 15, 5, 1, 551489775, 32, 0

This is how it was before:

3
-1, 0, 0, 18
9401, 6, 16, 5, 34, 4, 15, 5, 56, 5, 25, 5, 26, 4, 24, 4, 54, 4
-1, 0, 0, 18
261, 4, 18, 5, 36, 5, 37, 4, 15, 5, 15, 4, 57, 4, 15, 4, 15, 5
1, 551489775, 32, 0

And here is the processing code. Not much has changed.

void sendCode(int gest) {
  switch(gest) {
    case -1:
      
      break;
    case 0:
      
      break;
    case 1:
      println("-----START SENDING POWER-----");
      
      txtLines = loadStrings("PowerCode.txt");
      
      for(int i = 0; i < txtLines.length; i++) {
        
        // Used along with Serial.parseInt() function for the Arduino
        // and commented out the while loop below.
        //myPort.write(txtLines[i]);
        
        subText = splitTokens(txtLines[i], ", ");
        counter = 0;
        while(counter < subText.length) {
          myPort.write(subText[counter]);
          //println(Integer.parseInt(subText[counter]));
          
          counter++;
        }
        
        //println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");
      }
      
      println("-----DONE SENDING POWER-----");
      break;
    case 2:
      
      break;
    case 3:
      
      break;
    case 4:
      
      break;
    case 5:
      
      break;
  }
  
  
}
int8_t satoi( char str ){

In spite of the name, that function tries to convert a single character to an int, not a string. The input argument, again in spite of the name, is a char, not a NULL terminated array of char, also known as a string.

The call passes it an int, which is not the correct type of value to pass the function.

PaulS: int8_t satoi( char str ){

In spite of the name, that function tries to convert a single character to an int, not a string. The input argument, again in spite of the name, is a char, not a NULL terminated array of char, also known as a string.

The call passes it an int, which is not the correct type of value to pass the function.

I'm not quite sure what your point is, but okay.

I'm assuming you mean the function definition should look like this then:

int8_t atoi( int asciiInteger )

And as I told you before, I had modified the code I found to convert a single character to an integer. I'm sorry I forgot to change the function name and parameters, even though a char and int are generally the same. But, I'm sure you know that.

However, it seems as though Serial.read() returns a char, so I just modified it.

I've noticed that Serial.read() is returning a char, or the integer value of an ASCII character, for me. That is why I kept the parameter as a char, which should not make a difference unless I was getting a normal int value.

Does anybody have any suggestions, please?

I’m not quite sure what your point is, but okay.

My point was that a function that takes a char should, in general, not be passed an int.

The conversion of a character that contains a numeric value that corresponds to a number can be converted to the number quite easily, by simply subtracting ‘0’ from it. That code requires looking at an ASCII table to see that it is defined correctly.

   //Check if this is a number  
   if ( str < ':' && str > '/'){

There wold be no need to look at an ASCII table if the code were written:

   //Check if this is a number  
   if ( str >= '0' && str <= '0'){

even though a char and int are generally the same.

A char is one byte. An int is two bytes. In terms of the data that each can store, they can hardly be considered the same.

I’ve noticed that Serial.read() is returning a char, or the integer value of an ASCII character, for me. That is why I kept the parameter as a char, which should not make a difference unless I was getting a normal int value.

The function needs to return an int, because it needs to be able to indicate that an error occurred. All the non-error indication data that it returns fits in one byte. If you call Serial.available() first, then the output from Serial.read() can safely be stored in a byte.

Does anybody have any suggestions, please?

Please summarize what your problem is. It seems most likely that you don’t understand that serial transmission of data is slow. Therefore, when reading the data, one must never assume that Serial.available() returning 0 means that the end of the packet has arrived. An explicit end-of-packet marker MUST be sent, and the receiver needs to read data until the end of packet marker arrives.

PaulS:
My point was that a function that takes a char should, in general, not be passed an int.

That’s fair.

The conversion of a character that contains a numeric value that corresponds to a number can be converted to the number quite easily, by simply subtracting ‘0’ from it. That code requires looking at an ASCII table to see that it is defined correctly.

   //Check if this is a number  

if ( str < ‘:’ && str > ‘/’){




There wold be no need to look at an ASCII table if the code were written:


//Check if this is a number 
   if ( str >= ‘0’ && str <= ‘0’){

All you did was change the upper and lower bounds of the conditions. It’s the exact same thing as what I was doing. What difference does it make if I went to an ASCII table. The original code was written with hexadecimal values. I looked at an ASCII table to verify and just changed the hexadecimal values to their corresponding characters.

A char is one byte. An int is two bytes. In terms of the data that each can store, they can hardly be considered the same.

I had a feeling you were going to use that data argument. My point was saying that a char is just an integer that represents a certain character on an ASCII table.

The function needs to return an int, because it needs to be able to indicate that an error occurred. All the non-error indication data that it returns fits in one byte. If you call Serial.available() first, then the output from Serial.read() can safely be stored in a byte.

Please summarize what your problem is. It seems most likely that you don’t understand that serial transmission of data is slow. Therefore, when reading the data, one must never assume that Serial.available() returning 0 means that the end of the packet has arrived. An explicit end-of-packet marker MUST be sent, and the receiver needs to read data until the end of packet marker arrives.

Okay. So say my text file looks like this:

0, 1, 222, ;

And when my Processing code breaks it down and sends it, it will look like this:

0
1
222
;

Is the Serial going to read it as 0, 1, and 222? Or is it going to read it as 0, 1, 2, 2, and 2? And is the semi-colon at the end of the data what you mean by an end-of-packet marker?

And I call Serial.available() in my getData() function. Is this an appropriate use of the Serial.available() function?

int getData() {
  
    
  while(Serial.available() <= 0) {
    delay(50);
  }
    
  return atoi((Serial.read()));
  
}

All you did was change the upper and lower bounds of the conditions. It’s the exact same thing as what I was doing.

Except that mine is obvious and yours is not. Yours requires research to determine that the bounds are correct. Mine does not.

And when my Processing code breaks it down and sends it, it will look like this:Is the Serial going to read it as 0, 1, and 222? Or is it going to read it as 0, 1, 2, 2, and 2? And is the semi-colon at the end of the data what you mean by an end-of-packet marker?

Neither. The serial data will look like “01222;”. The Arduino needs to look for the ; as the end of packet marker. It needs to look for the or the (’\n’ and ‘\r’) as the end of value markers. Each value string then gets converted to ant int using atoi() unless you are converting the value on the fly. If you are, then the or indicates that it it time to store and reset the current value.

Is this an appropriate use of the Serial.available() function?

The Serial.available() function can never return a negative value. When there is nothing to read, there is no need to diddle around (the delay call) for a fixed period of time. The loop will simply end as soon as there is a character to read.

Ok. I will let you know if that works.