Receiving integer from Serial, then using it in a Do:While Loop?

Forgive me if I don’t use all of the correct terms, I’m pretty new at this.

My Goal:

  1. The sketch sends 0x01 (1) over Serial, then waits until it receives 4 bytes in return, then stores those bytes in an array. For this testing purpose those bytes are 2,0,1,3 (ie, the year). This works.

  2. The sketch then sends 0x02 (2) over Serial, then waits until it receives 1 byte and then stores that byte as an integer. This byte is supposed to correspond to the number of bytes that will be received in Step 3. For this testing purpose that integer needs to be 8, but when the sketch is in use that number could be any number between and including 1 and 32. This is where I’m having problems.

  3. The sketch then sends 0x03 (3) over Serial, then waits until it receives the number of bytes set out in Step 2. It then stores those bytes in a character array. For testing purposes, in this case I use: J,i,m, ,B,e,a,n.

  4. This step prints the two arrays and one integer to Serial to confirm that it worked. In the larger code that this will be used in, the integer and arrays will be written to a RFID card.

I can manually define int nameLength = 8; and then everything prints out as it should. However, if I define nameLength as 0, and then try to use the received byte from Serial, it doesn’t work. I’m sure I’m missing something simple, but I’m just not seeing it.

The code is as follows:

#include <SoftwareSerial.h>

#define A_SIZEOF(array)     (sizeof(array)/sizeof(array[0]))

const uint8_t   pinTX                   = 6;                     // SoftwareSerial transmit pin
const uint8_t   pinRX                   = 7;                     // SoftwareSerial receive pin
const uint8_t   RFID_READ               = 0x01;                  // Parallax RFID read command
const uint8_t   RFID_WRITE              = 0x02;                  // Parallax RFID write command
const uint8_t   GET_CODE                = 0x01;
const uint8_t   GET_NAMELENGTH          = 0x02;      
const uint8_t   GET_NAME                = 0x03;
uint8_t         buffID[sizeof(long)];                            // tag ID array
uint8_t         buffCODE[sizeof(long)];                          // pass code array
uint8_t         nameLength              = 0;                     // amount of characters to be passed to buffNAME
uint8_t         writeindex              = 0;                     // reference index for buffNAME
char            buffNAME[33];                                    // array of up to 32 characters
SoftwareSerial  serialRFID(pinRX, pinTX);                        // define SoftwareSerial

//---------------------------------------------------------------------------------------

void setup()
{
  Serial.begin(9600);

  // ... software serial I/O pins ...

  pinMode(pinTX, OUTPUT);
  pinMode(pinRX, INPUT);
  serialRFID.begin(9600);
}

// DEBUGGING------------------------------------------------------------------------------

void debug()
{
  for(int i = 0; i < A_SIZEOF(buffCODE); i++)      
  {
    Serial.write(byte(buffCODE[i]));
  }
  Serial.print("\n");

  Serial.print(nameLength);
  Serial.print("\n");

  for(int i = 0; i < nameLength; i++)     
  {
    Serial.write(byte(buffNAME[i]));
  }
  Serial.print("\n");
} 

// RECEIVE INFO TO WRITE  -----------------------------------------------------------------------------------------------------

void getTagINFO()
{
  (void)Serial.read();
  Serial.print(GET_CODE);
  Serial.print("\n");
  while(Serial.available() < 4);
  int count = 0;
  do                                            
  {
    buffCODE[count++] = Serial.read();
  }
  while(count < 4);
  //-------------------------------------------
  (void)Serial.read();
  Serial.print(GET_NAMELENGTH);
  Serial.print("\n");
  while(Serial.available() < 1);
  do                                            
  {
    nameLength = Serial.read();
    count++;
  }
  while(count < 1);
  //nameLength = 8;
  //-------------------------------------------
  (void)Serial.read();
  Serial.print(GET_NAME);
  Serial.print("\n");
  while(Serial.available() < nameLength);
  int count2 = 0;
  do
  {
    buffNAME[writeindex++] = Serial.read();
    count2++;
  }
  while(count2 < nameLength);
}

//MAIN PROGRAM LOOP -------------------------------------------------------------------------------------------------------

void loop()
{
  if ( Serial.available() > 0 )
  {
    int command = Serial.read();
    switch (command)
    {     
    case 'w':   
      getTagINFO();
      debug();
      break;

    default:
      break;
    }
  }
}

Thank you in advance.
Connor

while(Serial.available() < 1);

Do you really mean that you only want to do the next part when Serial.available() is 0 or negative?

Henry_Best:

while(Serial.available() < 1);

Do you really mean that you only want to do the next part when Serial.available() is 0 or negative?

No, because of the semi colon at the end, that line means wait and do nothing while Serial.available() is 0 or negative. Once a single byte becomes available it moves on to the next part of code. That part works.

(void)Serial.read();

What exactly do you think these statements are doing?

Arrch: (void)Serial.read();

What exactly do you think these statements are doing?

I thought I was flushing the Serial buffer to avoid reading unintended bytes still in the buffer, but judging by your statement I'm not doing much of anything ? :blush:

  while(Serial.available() < 1);
  do                                            
  {
    nameLength = Serial.read();
    count++;
  }
  while(count < 1);

Why do you need a do/while loop to loop once?

Have you tried printing what is in nameLength?

Serial.print("nameLength: ");
Serial.println(nameLength);

If you are sending 8, I suspect that you will see that nameLength is 56. Consult an ASCII table to find out why, and for a hint at how to solve the “problem”.

Charte author=PaulS link=topic=171191.msg1272789#msg1272789 date=1370856418]

If you are sending 8, I suspect that you will see that nameLength is 56. Consult an ASCII table to find out why, and for a hint at how to solve the “problem”.

And that, sir, is what I was missing. Thank you very much. I used atoi() to convert back to an integer and all is good. Here is the updated code for posterity.

#include <SoftwareSerial.h>

#define A_SIZEOF(array)     (sizeof(array)/sizeof(array[0]))

const uint8_t   pinTX                   = 6;                     // SoftwareSerial transmit pin
const uint8_t   pinRX                   = 7;                     // SoftwareSerial receive pin
const uint8_t   RFID_READ               = 0x01;                  // Parallax RFID read command
const uint8_t   RFID_WRITE              = 0x02;                  // Parallax RFID write command
const uint8_t   GET_CODE                = 0x01;
const uint8_t   GET_NAMELENGTH          = 0x02;      
const uint8_t   GET_NAME                = 0x03;
char            buffCODE[5];                                     // pass code array
uint8_t         nameLength              = 0;                     // amount of characters to be passed to buffNAME
char            buffNAME[33];                                    // array of up to 32 characters
SoftwareSerial  serialRFID(pinRX, pinTX);                        // define SoftwareSerial

//---------------------------------------------------------------------------------------

void setup()
{
  Serial.begin(9600);

  // ... software serial I/O pins ...

  pinMode(pinTX, OUTPUT);
  pinMode(pinRX, INPUT);
  serialRFID.begin(9600);
}

// DEBUGGING------------------------------------------------------------------------------

void debug()
{
  for(int i = 0; i < A_SIZEOF(buffCODE); i++)      
  {
    Serial.write(byte(buffCODE[i]));
  }
  Serial.print("\n");

  Serial.println(nameLength);

  for(int i = 0; i < nameLength; i++)     
  {
    Serial.write(byte(buffNAME[i]));
  }
  Serial.print("\n");
} 

// RECEIVE INFO TO WRITE  -----------------------------------------------------------------------------------------------------

void getTagINFO()
{
  while(Serial.available() > 0)
    {
      (void)Serial.read();
    }
  Serial.print(GET_CODE);
  Serial.print("\n");
  while(Serial.available() < 4);
  int count = 0;
  do                                            
  {
    buffCODE[count++] = Serial.read();
  }
  while(count < 4);
  //-------------------------------------------
  while(Serial.available() > 0)
    {
      (void)Serial.read();
    }
  Serial.print(GET_NAMELENGTH);
  Serial.print("\n");
  while(Serial.available() < 2);
  int count2 = 0;
  char buffer[3];
  do
  {
    buffer[count2++] = Serial.read();
  }
  while (count2 < 2);
  nameLength = atoi(buffer);
  //-------------------------------------------
  while(Serial.available() > 0)
    {
      (void)Serial.read();
    }
  Serial.print(GET_NAME);
  Serial.print("\n");
  while(Serial.available() < nameLength);
  int count3 = 0;
  int writeindex = 0;
  do
  {
    buffNAME[writeindex++] = Serial.read();
    count3++;
  }
  while(count3 < nameLength);
}

//MAIN PROGRAM LOOP -------------------------------------------------------------------------------------------------------

void loop()
{
  if ( Serial.available() > 0 )
  {
    int command = Serial.read();
    switch (command)
    {     
    case 'w':   
      getTagINFO();
      debug();
      break;

    default:
      break;
    }
  }
}

Code edited to reflect changes.

      (void)Serial.read();

Why do you feel the need to cast a value that you are going to discard to another type?

  do                                            
  {
    buffCODE[count++] = Serial.read();
  }
  while(count < 4);

When this is done, buffCODE is a char array. It is NOT a string.

  int count2 = 0;
  char buffer[2];
  do
  {
    buffer[count2++] = Serial.read();
  }
  while (count2 < 2);

When this is done, buffer is a char array. It is NOT a string. It should NOT be passed to a function that expects a string.

A string is a NULL terminated array of chars. You are NOT NULL terminating your arrays of chars, so you do not have strings, so you should not be passing them to functions that expect strings.

That you seem to have gotten away with it so far does not make it OK to continue.

PaulS:
Why do you feel the need to cast a value that you are going to discard to another type?

Sorry, I’m feeling my way through this, trying to understand examples and how to apply it to what I need.
Could you further explain what you are asking?

  int count2 = 0;

char buffer[2];
 do
 {
   buffer[count2++] = Serial.read();
 }
 while (count2 < 2);



When this is done, buffer is a char array. It is NOT a string. It should NOT be passed to a function that expects a string.

So if I understand you I need to expand the defined array(s) by one index to allow for NULL termination because the data that is being received from Serial is a string and therefore needs to be passed to a string?

Could you further explain what you are asking?

(void)Serial.read();

(void) is a cast, used to explicitly convert data of one type (int, in this case) to another (void in this case).

Why are you casting to void? Why are you casting a value that you are not saving? Why are you casting at all?

So if I understand you I need to expand the defined array(s) by one index to allow for NULL termination because the data that is being received from Serial is a string and therefore needs to be passed to a string?

The data arriving from the serial port is a collection of characters. If you want a string, then, yes the array needs to be one element larger to hold the terminating NULL.

But, that has nothing to do with the question.

I hate do/while loops. They are often used incorrectly, since the body will be executed at least once, a opposed to a for or while loop, which might not be execute any times.

In this case, a for loop would be a better choice, since the number of times the loop is to iterate is known. On the other hand, the number of times is one. So, the real question is why loop at all? That is what I was asking.

PaulS: Why are you casting to void? Why are you casting a value that you are not saving? Why are you casting at all?

The only reason I can see for that is to suppress compiler warnings about unused return values, when the value was being deliberately discarded.