strcat a char array is cutting off the output

In the function endrace() I am trying to create an http request using the char array hts - I am combining some known text with another char array FullURL. The strcat section looks like this

strcat(hts,FullURL);
strcat(hts," HTTP/1.1\n");
strcat(hts,“Host: .azurewebsites.net\n”);
strcat(hts,“Connection: close\n\n”);

FullURL will be text that looks like this “/adddata?first=d5ba7ad4&second=ds933fds”

The next line I am trying to print the full request to serial to check if it looks good. But everytime that execute the Serial.print(hts) the output is cut off after HTTP, meaning I dont see the 1.1 or host or connection: close text that should be concatenated.

#include <SPI.h>
#include <MFRC522.h>
#include <SoftwareSerial.h> 
#include <SparkFunESP8266WiFi.h>
#include <Wire.h>


// PIN Numbers : RESET + SDAs
#define RST_PIN         4  
#define SS_1_PIN        10
#define SS_2_PIN        7
#define SS_3_PIN        5
#define SS_4_PIN        6


const char mySSID[] = "SSID";
const char myPSK[] = "password";
const char destServer[] = "<website>.azurewebsites.net";



#define NR_OF_READERS   4
byte ssPins[] = {SS_1_PIN, SS_2_PIN,SS_3_PIN, SS_4_PIN};
// Create an MFRC522 instance :
MFRC522 mfrc522[NR_OF_READERS];

char Cars[][11] = 
{
  "",
  "",
  "",
  ""
};
//first line is lane, second is place - use 0 if there if lane is not used
//Communiction from second arduino will be needed to populate
int FinishOrder[2][4];

int p = 0; //Used to keep track of each item sent through the wire and place it in the appropriate spot in the array
boolean gameover; //if true reset


/**
   Initialize.
*/
void setup() {
  Wire.begin(8);                // join i2c bus with address #8
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // Initialize serial communications with the PC
  while (!Serial);              // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)

  SPI.begin();                  // Init SPI bus
  
  //connect to WiFi
  initializeESP8266();
  connectESP8266();
  displayConnectInfo();


  /* looking for MFRC522 readers */
  for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) {
    mfrc522[reader].PCD_Init(ssPins[reader], RST_PIN);
    Serial.print(F("Reader "));
    Serial.print(reader);
    Serial.print(F(": "));
    mfrc522[reader].PCD_DumpVersionToSerial();
    //mfrc522[reader].PCD_SetAntennaGain(mfrc522[reader].RxGain_max);
  }

}

/*
   Main loop.
*/

void loop() {
  
 for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) {

    // Looking for readers who get a single
    if (mfrc522[reader].PICC_IsNewCardPresent() && mfrc522[reader].PICC_ReadCardSerial()) {

      String rfid_uid = "";
      for (byte i = 0; i < mfrc522[reader].uid.size; i++) {
        String uid_part = String(mfrc522[reader].uid.uidByte[i], HEX); 
        rfid_uid += uid_part;
      }
      char rfid[11];
      
      rfid_uid.toCharArray(rfid, 11);
      RecordRacer(reader,rfid); //send lane/car ID to be recorded
      //Clear the rfid char for use when the next car is placed on reader                  
      //memset(rfid, 0, sizeof(rfid)); //reset rfid char
      
      // Halt PICC
      mfrc522[reader].PICC_HaltA();
      // Stop encryption on PCD
      mfrc522[reader].PCD_StopCrypto1();
    } //if (mfrc522[reader].PICC_IsNewC..
  } //for(uint8_t reader..
}

void receiveEvent(int howMany) {
  int wiredata; 
  for (int i = 0; i < howMany; i++)
    {
      wiredata = Wire.read();    // receive byte as an integer      
      RecordResults(wiredata);
    }
}


//go is a variable that if set to true will record the race
void RecordRacer(int track, char* car)
{
         
//Which car is on which track, fill the array 
switch (track) {
  case 0:
      strcpy(Cars[track],car);
      Serial.print(F("Car: "));
      Serial.println(Cars[track]);
      Serial.print(F("Track: "));
      Serial.println(track);
    break;
  case 1:
      strcpy(Cars[track],car);
      Serial.print(F("Car: "));
      Serial.println(Cars[track]);
      Serial.print(F("Track: "));
      Serial.println(track);

    break;
  case 2:
      strcpy(Cars[track],car);
      Serial.print(F("Car: "));
      Serial.println(Cars[track]);
      Serial.print(F("Track: "));
      Serial.println(track);

  break;
  case 3:
      strcpy(Cars[track],car);
      Serial.print(F("Car: "));
      Serial.println(Cars[track]);
      Serial.print(F("Track: "));
      Serial.println(track);
  
  break;
  default:
    // statements
  break;
    }
}
void endrace()
{

    
        
    char FullURL[100] = "/adddata";

    char hts[200] = "GET ";

    
   //Loop through each lane
    for (int i = 0; i < 4; i++) {
    
      if(i == 0)//first variable in URL is ? //others are &
      {
        
        strcat(FullURL,"?");
      }
      else
      {
          if(strlen(Cars[FinishOrder[0][i]])== 0)
            {
            } 
          else
            {
              strcat(FullURL,"&");
            }
        
      }
       
        //printing for debuging
        Serial.println("Create URL");
        Serial.print("Place: ");
        Serial.println(FinishOrder[0][i]);
        Serial.print("Lane: ");
        Serial.println(FinishOrder[1][i]);
        Serial.print("Car: ");
        Serial.println(Cars[FinishOrder[0][i]]);
        Serial.print("URL Call: ");   
        Serial.println(FullURL);
      //Look in the array for the finish order of each lane
     switch (FinishOrder[0][i]) {
        case 1: //Lane 1
          if(strlen(Cars[FinishOrder[0][i]])== 0)
          {
    
          Serial.println("No first place");
          }    
          else
          {
             strcat(FullURL,"first=");
             strcat(FullURL,Cars[FinishOrder[0][i]]);   
          }
          break;
       case 2:
 
         if(strlen(Cars[FinishOrder[0][i]])== 0)
         {
          Serial.println("No second place");
         }    
         else
         {
            strcat(FullURL,"second=");
            strcat(FullURL,Cars[FinishOrder[0][i]]);  
         }
         break;
       case 3:

         if(strlen(Cars[FinishOrder[0][i]])== 0)
         {
          Serial.println("No third place");
         }    
         else
         {
           strcat(FullURL,"third=");
           strcat(FullURL,Cars[FinishOrder[0][i]]);
         }
         break;
       case 4:

        if(strlen(Cars[FinishOrder[0][i]])== 0)
        {
          Serial.println("No fourth place");
        }    
        else
        {
          strcat(FullURL,"fourth=");
          strcat(FullURL,Cars[FinishOrder[0][i]]);
        }
         break;
        default:
          // statements
        break;
      }
     }
      
      strcat(hts,FullURL);
      strcat(hts," HTTP/1.1\n");
      strcat(hts,"Host: <website>.azurewebsites.net\n");
      strcat(hts,"Connection: close\n\n"); 
           
  
      Serial.print(hts); //this is not printing to serial as I would expect
    
      ESP8266Client client;
      
   
      client.print(hts);

  
      if (client.connected())
        client.stop(); // stop() closes a TCP connection.
    
       
    //    resetFunc();  //call reset
         // Serial.println(F("add to http"));
          //This will display wierd characters in what use to be the FullURL part of the now bigger string
         // Serial.println(hts); 
        
     //Reset our variables for the next race
      gameover = true;
      p = 0;
      memset(FinishOrder, 0, sizeof(FinishOrder));
      memset(FullURL, 0, sizeof(FullURL));
      memset(Cars, 0, sizeof(Cars));
      memset(hts, 0, sizeof(hts));
      gameover = false;

}


void RecordResults(int num)
{
  //Serial.println("Getting info from other arduino");
  if(num == 99)
  {
    Serial.println("Race is over");
    endrace();
  }
  else
  {
    
   switch (p) {
        case 0: //Place 1
          FinishOrder[0][0] = num;
          Serial.print(F("Place: "));
          Serial.println(FinishOrder[0][0]);
         p++;
          break;
        case 1: //What lane
          FinishOrder[1][0] = num;
          Serial.print(F("Lane: "));
          Serial.println(FinishOrder[1][0]);
          p++;
          break;
        //rest of code removed for space
   }
  } 
}

Try printing out the bytes of your char array in hex after doing all the strcat calls to see what's really in there. Maybe even do that after every strcat call.

char Cars[][11] =
{
  "",
  "",
  "",
  ""
};

Kind of useless creating an array but reserving no space.

      strcpy(Cars[track],car);

You just sh*t all over memory you don't own.

ANYTHING that happens after this is undefined behavior.

PaulS: char Cars[][11] = {   "",   "",   "",   "" };

Kind of useless creating an array but reserving no space.

      strcpy(Cars[track],car);

You just sh*t all over memory you don't own.

ANYTHING that happens after this is undefined behavior.

44 bytes of reserved space, I make it. Have I missed something?

Each item that goes into that array should be 10 characters. Did I initialize it correctly or not? And if not what would the proper way to initialize it be?

If you just wanted four names, as strings, each a maximum of ten characters long, I'd've just left it at char Cars[4][11];.

I don't know what point PaulS was trying to make.

I don't know what point PaulS was trying to make.

It was late in the day. I say the empty strings, and made an erroneous assumption about the amount of memory being reserved.

However, there is no proof that the data being copied into the array is only 10 characters. strncpy() would be a better choice of functions to call, to ensure that you do not write beyond the end of the array.

Thanks for helping me debug this. Its been driving me nuts for a week :slight_smile:

I added the following code to view the array

 for ( byte i = 0; i < sizeof( hts ); i++ )
  {
    Serial.print( F( "Char '" ));
    Serial.print( hts[ i ] );
    Serial.print( F( "' converts to " ));
    Serial.print((byte)(hts[ i ]), HEX );
    Serial.print( F( " Hex = " ));
    Serial.print((byte)(hts[ i ]));
    Serial.println( F( " decimal" ));
 

  }

I can see that all of the characters are in the array properly

the FullURL char array prints
/adddata?first=67d113f5&second=d5ba7ad4
The numbers are what are sitting in the Cars char array so I know I am not overrunning the Cars array

This is what the end of the hts char array looks like (I added \n instead of \n because as I was printing out the array I could see that \n was not showing up, I am not sure if this is correct or not)

Char 'n' converts to 6E Hex = 110 decimal
Char 'n' converts to 6E Hex = 110 decimal
Char 'e' converts to 65 Hex = 101 decimal
Char 'c' converts to 63 Hex = 99 decimal
Char 't' converts to 74 Hex = 116 decimal
Char 'i' converts to 69 Hex = 105 decimal
Char 'o' converts to 6F Hex = 111 decimal
Char 'n' converts to 6E Hex = 110 decimal
Char ':' converts to 3A Hex = 58 decimal
Char ' ' converts to 20 Hex = 32 decimal
Char 'c' converts to 63 Hex = 99 decimal
Char 'l' converts to 6C Hex = 108 decimal
Char 'o' converts to 6F Hex = 111 decimal
Char 's' converts to 73 Hex = 115 decimal
Char 'e' converts to 65 Hex = 101 decimal
Char '\' converts to 5C Hex = 92 decimal
Char 'n' converts to 6E Hex = 110 decimal
Char '\' converts to 5C Hex = 92 decimal
Char 'n' converts to 6E Hex = 110 decimal
Char '' converts to 0 Hex = 0 decimal //this line repeats until it gets to the end of the allocated amount for the char array

When I try to print the full hts char array I get this
GET /adddata?first=67d113f5&second=d5ba7ad4 HTTP/1.1

What else I can I do to debug?

Makes me queasy to see arrays of this size created on the stack:

void endrace()
{

    
        
    char FullURL[100] = "/adddata";

    char hts[200] = "GET ";
.
.
.

It's not technically wrong but and may not be related to your issue, of course. But for me, with arrays of that size, I'd rather just create them statically as globals or dynamically on the heap during setup and verifying their pointers before continuing:

byte
    *hts;
byte
    *FullURL;

void setup( void )
{
.
.
.
    hts = (byte *)malloc( 200 ); 
    FullURL = (byte *)malloc( 100 );
    if( hts == NULL )
    {
        Serial.println( "Failed allocating hts." );    
        while(1);
    }

    if( FullURL == NULL )
    {
        Serial.println( "Failed allocating FullURL." );    
        while(1);
    }
.
.
.

Thanks - I am still trying to wrap my head around pointers and hose to use them. If I get a chance I will try to fix this, but I am not convinced that this is the issue that I am facing.

ghornet:
Thanks - I am still trying to wrap my head around pointers and hose to use them. If I get a chance I will try to fix this, but I am not convinced that this is the issue that I am facing.

Just use

.
.
.
char hts[200];
FullURL[100];
.
.
.

as globals and remove their declarations from endrace().

I’m not really convinced it’s the issue either but it’s not hard to try to rule out stack issues.

Okay I removed their declaration from the endrace function and added them to the top of the program

#include <SPI.h>
#include <MFRC522.h>
#include <SoftwareSerial.h> 
#include <SparkFunESP8266WiFi.h>
#include <Wire.h>
#include <string.h>

// PIN Numbers : RESET + SDAs
#define RST_PIN         4  
#define SS_1_PIN        10
#define SS_2_PIN        7
#define SS_3_PIN        5
#define SS_4_PIN        6


const char mySSID[] = "<ssid>";
const char myPSK[] = "<pass>";
const char destServer[] = "hotwheelracing.azurewebsites.net";

char hts[150];
char FullURL[75];

Note that I made them a bit smaller as I was aggressively overestimating the amount of space I needed.

Instead of declaring them in the function I started the endrace function with

    strcpy(FullURL, "/adddata");
    strcpy(hts, "GET ");

Unfortunately I still only get this printed to serial

GET /adddata?first=77e4df5 HTTP/1.1

It is very wierd that I can see all of the characters in the array printed out one by one, but the very next step is the Serial.print and it shortens what I am suppose to be printing.

Just for another data point when I compile the program it lets me know the following

Global variables use 1697 bytes (82%) of dynamic memory, leaving 351 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.

Can you show the contents of hts from the beginning, not the ending? It seems like either there's a NULL (0x00) somehow making its way into the array after the "1.1" or the ESC sequence '\n' is doing something.

attached is the full output

charoutput.txt (4.08 KB)

One thing is jumping out at me here - the \n's are not being converted to a newline character, but are stored in the array as a \ and an n. Shouldn't they be getting turned into newline characters?

Why does the output cut off at char 99? Oh, because it hit the null at the end...

Also, did you just post your home WiFi password? You shouldn't do that....

Does anything change if you modify the stuff under "//printing for debuging" and wrap F() around the string literals you're printing? That would be a quick test for a non-obvious memory problem - if that changes anything, it's a memory problem (I don't see any dynamic memory allocation, but I don't know what those libraries are doing)

It is impossible to tell you what is wrong with your program based on some incomplete snippets. Post ALL of your code.

So I had a version of this code working before I hooked up the second arduino to trigger the end of the race. I did a quick test and removed the wire.read() functionality and I got the dang thing to work correctly.

So something in this code is causing the issue

void receiveEvent(int howMany) {
  int wiredata; 
  for (int i = 0; i < howMany; i++)
    {
  //    wiredata = Wire.read();    // receive byte as an integer      
   //   RecordResults(wiredata);
    }
}

All of the code is posted in the initial post with the exception to the standard wifi functions - but for full clarity I have attached the code to this post

ForPosting.ino (14.2 KB)

It might be time to post an MCVE. That's the smallest possible code that actually compiles and demonstrates the problem. It's a lot easier to provide help if you don't have to wade your way to 14KB of unrelated clutter.

Thanks for the help - I am not sure how to post a smaller version of the code that can compile - it is all dependent of the RFID readers it is attached to and the secondary arduino. But on the plus side I have think I have narrowed it down to the fact that it is for sure a memory problem. With the full program compiling the compiler tells me

Global variables use 1536 bytes (75%) of dynamic memory

but if I comment out the creation of the ESP8266Client client; to create my wifi client it compiles with this

Global variables use 1404 bytes (68%) of dynamic memory

And the char array hts prints out as I would expect.

I am currently studying and reading on how to reduce my memory footprint.