DUE. Problems with Serial.Read/Serial.Available?

I have problems getting a code working on the DUE, that works on the UNO with no problems. I am trying to read a HTTP-request from a 3G-shield (by Cooking-Hacks) through Serial.Read.

However, when I run this code, it does’t return any values to data. I read that the DUE sometimes has problems with serial.available/serial.read and needs a firmware update. Is this also the case with the 3rd revision board I just bought? Or is it something else that blocks it? I also use the atoi(), that I tried to comment out.

Here is my code for reference:

// 

int8_t answer;
int onModulePin = 2, aux;
int data_size = 0;
int end_file = 0;
char *p, *i;
char *text;
char *filename;
char *date;
char *time2; 


char aux_str[50];

char data[400];
int http_x;
int http_status;   // 0: end, 1 waiting data with header, 2 waiting data without header, 3 timeout waiting data, 4 unknow response
int x = 0;
long previous;


//Write here you SIM data
const char pin_number[] = "1001";
const char apn[] = "internet";
const char user_name[] = "";
const char password[] = "";

//


char url[ ]="www.infraordinary.dk";
int port= 80;
char request[ ]="GET /display_vars.php?test HTTP/1.1\r\nHost: www.infraordinary.dk\r\nContent-Length: 0\r\n\r\n";



void setup(){

  pinMode(onModulePin, OUTPUT);
  Serial.begin(115200);

  Serial.println("Starting...");
  power_on();

  delay(3000);

  //sets the PIN code
  sprintf(aux_str, "AT+CPIN=%s", pin_number);
  sendATcommand(aux_str, "OK", 2000);

  delay(3000);

  while( (sendATcommand("AT+CREG?", "+CREG: 0,1", 500) ||
    sendATcommand("AT+CREG?", "+CREG: 0,5", 500)) == 0 );


  // sets APN, user name and password
  sprintf(aux_str, "AT+CGSOCKCONT=1,\"IP\",\"%s\"", apn);
  sendATcommand(aux_str, "OK", 2000);

  sprintf(aux_str, "AT+CSOCKAUTH=1,1,\"%s\",\"%s\"", user_name, password);
  sendATcommand(aux_str, "OK", 2000);



}
void loop(){

  // request the url
  sprintf(aux_str, "AT+CHTTPACT=\"%s\",%d", url, port);
  answer = sendATcommand(aux_str, "+CHTTPACT: REQUEST", 60000);

  // Sends the request
  Serial.println(request);
  // Sends <Ctrl+Z>
  Serial.write(0x1A);
  http_status = 1;

  while ((http_status == 1) || (http_status == 2))
  {
    answer = sendATcommand("", "+CHTTPACT: ", 60000);
    if (answer == 0)
    {
      http_status = 3;
    }
    else
    {
      // answer == 1
      while(Serial.available()==0);
      aux_str[0] = Serial.read();

      if ((aux_str[0] == 'D') && (http_status == 1))
      {
        // Data packet with header
        while(Serial.available()<4);
        Serial.read();  // A
        Serial.read();  // T
        Serial.read();  // A
        Serial.read();  // ,

        // Reads the packet size
        x=0;
        do{
          while(Serial.available()==0);
          aux_str[x] = Serial.read();
          x++;
        }
        while((aux_str[x-1] != '\r') && (aux_str[x-1] != '\n'));

        aux_str[x-1] = '\0';
        data_size = atoi(aux_str); // ATOI COULD BE THE PROBLEM

        // Now, search the end of the HTTP header (\r\n\r\n)
        do{
          while (Serial.available() < 3);

          data_size--;
          if (Serial.read() == '\r')
          {
            data_size--;
            if (Serial.read() == '\n')
            {
              data_size--;
              if (Serial.read() == '\r')
              {
                data_size--;
                if (Serial.read() == '\n')
                {
                  // End of the header found
                  http_status = 2;
                }
              }
            }   
          }
        }
        while ((http_status == 1) && (data_size > 0));

        if (http_status == 2)
        {
          // Reads the data
          http_x = 0;
          do{
            if(Serial.available() != 0){
              data[http_x] = Serial.read();
              http_x++;
              data_size--;
            }
            else
            {
              delay(1);
            }
          }
          while(data_size > 0);
          data[http_x] = '\0';
        }
      }
      else if ((aux_str[0] == 'D') && (http_status == 2))
      {
        // Data packet with header
        while(Serial.available()<4);
        Serial.read();  // A
        Serial.read();  // T
        Serial.read();  // A
        Serial.read();  // ,

        // Reads the packet size
        x=0;
        do{
          while(Serial.available()==0);
          aux_str[x] = Serial.read();
          x++;
        }
        while((aux_str[x-1] != '\r') && (aux_str[x-1] != '\n'));

        aux_str[x-1] = '\0';
        data_size = atoi(aux_str);

        do{
          if(Serial.available() != 0){
            data[http_x] = Serial.read();
            http_x++;
          }
          else
          {
            delay(1);
          }
        }
        while(data_size > 0);
        data[http_x] = '\0';

      }
      else if (aux_str[0] == '0')
      {
        // end of the AT command
        http_status = 0;
      }
      else
      {
        // unknow response
        http_status = 4;
        Serial.print(char(aux_str[0]));
        Serial.print(char(Serial.read()));
        Serial.print(char(Serial.read()));
        Serial.print(char(Serial.read()));
        Serial.print(char(Serial.read()));
        Serial.print(char(Serial.read()));
        Serial.print(char(Serial.read()));
        Serial.print(char(Serial.read()));
        Serial.print(char(Serial.read()));
      }         
    }      
  }

  if (http_status == 0)
  {
    Serial.print(F("HTTP data: "));
    Serial.println(data);
    Serial.print("Data_Size: ");
    Serial.println(data_size);
    Serial.print("HTTP_x: ");
    Serial.println(http_x);
    Serial.print("Serial buffer: ");
    Serial.println(SERIAL_BUFFER_SIZE);
        Serial.print("aux_str: ");
    Serial.println(aux_str);
    
  }
  else
  {
    Serial.print(F("http_status: "));
    Serial.println(http_status, DEC);
  }



  //delay(1000);

}

void power_on(){

  uint8_t answer=0;

  // checks if the module is started
  answer = sendATcommand("AT", "OK", 2000);
  if (answer == 0)
  {
    // power on pulse
    digitalWrite(onModulePin,HIGH);
    delay(3000);
    digitalWrite(onModulePin,LOW);

    // waits for an answer from the module
    while(answer == 0){
      // Send AT every two seconds and wait for the answer
      answer = sendATcommand("AT", "OK", 2000);
    }
  }

}


int8_t sendATcommand(   char* ATcommand,
char* expected_answer1,
unsigned int timeout)
{

  return sendATcommand2(   ATcommand, 
  expected_answer1, 
  expected_answer1, 
  timeout);
}

int8_t sendATcommand2(   char* ATcommand,
char* expected_answer1,
char* expected_answer2,
unsigned int timeout)
{

  uint8_t x=0,  answer=0;
  char response[100];
  unsigned long previous;

  memset(response, '\0', 100);    // Initialize the string

  delay(100);

  while( Serial.available() >= 2) Serial.read();    // Clean the input buffer

  Serial.println(ATcommand);    // Send the AT command


    x = 0;
  previous = millis();

  // this loop waits for the answer
  do{

    if(Serial.available() != 0){
      response[x] = Serial.read();
      x++;
      // check if the desired answer is in the response of the module
      if (strstr(response, expected_answer1) != NULL)
      {
        answer = 1;
      }
      // check if the desired answer is in the response of the module
      if (strstr(response, expected_answer2) != NULL)
      {
        answer = 2;
      }
    }
    // Waits for the asnwer with time out
  }
  while((answer == 0) && ((millis() - previous) < timeout));

  return answer;
}

On the UNO I had to increase the buffer to 400. I tried the same in RingBuffer.h for due DUE (Using IDE 1.5.4 and 1.6.1), without it helping.

I would really appreciate if someone out there have any ideas to what might cause the problem.

Thanks!

HTTP_Terminal_get_var_DUE_test3.ino (7.65 KB)

This kind of serial input processing should not rely on the built-in buffer. Make your own buffer. Read into that as quickly as possible (make sure your main loop does a read operation frequently enough to read chars into your buffer before the built-in one fills up)

Then you can check if the incoming chars are 'A' 'T' 'A' ',' without stripping them off the buffer until you're ready.

I read that the DUE sometimes has problems with serial.available/serial.read and needs a firmware update. Is this also the case with the 3rd revision board I just bought?

There's no firmware on the board. The firmware is in the Arduino folder on your computer. You can try updating to the latest version but it probably isn't the cause of your problem.

Hi MorganS,

Thanks for your feedback!

I am not sure how to make my own buffer. I thought data was a kind of buffer.

How does the built-in buffer differ between the UNO and the DUE?

My code works on the UNO when changing:

#if (RAMEND < 1000) 
#define SERIAL_BUFFER_SIZE 32 
#else 
#define SERIAL_BUFFER_SIZE 256 
#endif

to

#if (RAMEND < 1000) 
#define SERIAL_BUFFER_SIZE 400 
#else 
#define SERIAL_BUFFER_SIZE 400 
#endif

But when I increase the RingBuffer.h to 400 on the DUE it doesn’t work.

Thanks.

Just had a small break through. As suggested it was these lines of code, that somehow worked differently on the DUE:

        // Now, search the end of the HTTP header (\r\n\r\n)
        do{
          while (Serial.available() < 3);
          Serial.print("5");
          data_size--;
          if (Serial.read() == '\r')
          {
            data_size--;
            if (Serial.read() == '\n')
            {
              data_size--;
              if (Serial.read() == '\r')
              {
                data_size--;
                if (Serial.read() == '\n')
                {
                  // End of the header found
                  http_status = 2;
                }
              }
            }   
          }
        }

When blocking it out, the small HTTP-request went through! I will now try to bump data (and RingBuffer) up to 5000 and see what happens…

The ‘problem’ is that you’re leaving stuff in the serial hardware buffer until you get enough characters to do the next bit of processing, for example:

while (Serial.available() < 3);

Ordinarily, this would be quite acceptable and it probably isn’t your problem in this case. But on the Arduino variants with USB native serial, this may never finish, due to the way that the USB communication sends packets.

If you have to increase the ringbuffer size, then it means your program is doing a lot of time-consuming processing elsewhere and not emptying the serial buffer often enough. Sometimes that’s an acceptable solution if you can’t split up that process to make it check serial more often.

The best practice is to keep your own buffer, of a size appropriate to the actual data you’re trying to read. NMEA messages are usually defined to be 80 characters or less, so you don’t need a big buffer. You read Serial.read() very often in your main loop and when you detect the start of a ‘wanted’ message, start copying into your buffer. Do this one character at a time, so your main task isn’t interrupted for long periods. Then when you detect the valid end of data, process that buffer or set a flag “data is ready” so when your main task finishes, you can process the message you received.

Thanks a lot for this, MorganS. I really help me understand the problem. I will revise my code over the coming days and see if I can get messages larger than data[2000], since this is where it stalls now.

Thanks again.