String have no null terminated?

Hi all,

I'm working on serial communication with UNO and SIM900
Here is my full code. Sorry if too long or not practical.

/*
 * A sketch for Arduino UNO board
 * - Get cell data from tower
 * - Parsing and tokenizing
 * - Send data to server
 */
 
#include <SoftwareSerial.h>

const unsigned long Period = 20000ul;     // every 20 seconds
int bGetCellData = 1;                    // control bit to get data or send data
static char IMEI[15];

SoftwareSerial ConnectSerial(7, 8);      // instantiate serial object, connecting the the GSM Serial hardware

void setup() {
  ConnectSerial.begin(19200);            // GPRS shield baud rate
  Serial.begin(115200);
  delay(500);
  ConnectSerial.println("AT+CENG=3");    // activate engineering mode
  delay(100);
  ConnectSerial.println("AT+GSN");
  delay(100);
}


void loop() {
  static unsigned long tempo = millis();
  static char celldata[256];
  static char jsonString[600];
  static int i = 0;

  if (bGetCellData == 1) {
    if (millis() - tempo > Period) {
      findingIMEI(celldata, IMEI);
      ConnectSerial.println("AT+CENG?"); // reading information
      i = 0;
      tempo = millis();
      memset(celldata,0,sizeof(celldata));
      memset(jsonString,0,sizeof(jsonString));
    }
    
    while(ConnectSerial.available()) {
      celldata[i++] = ConnectSerial.read();
    }
    
    if ((i > 0) && strstr(celldata,"+CENG:0") && strstr(celldata,"OK")) {
      getLocInfo(celldata, jsonString, IMEI);
      i = 0;
      bGetCellData = 0;
    }
    
  }
  else {
    if (millis() - tempo > Period) {
      Serial.println(jsonString);
      tempo = millis();
      bGetCellData = 1;
    }
  }
}

/*
 * function to process receiving data
 * including parsing and tokenizing
 */

void getLocInfo(char * celldata, char * returnString, char * imei) {
  char lines[7][60];
  char temp[128];
  int line = 0;
  int c = 0;
  int i = 0;
  long mcc;
  long mnc;
  long lac;
  long cid;
  long rxl;
  memset(lines,0,sizeof(lines));
  char * str = strstr(celldata,"+CENG:0");
  
  while (*str != '\0') {
    if (line > 6)
      break;
    if (*str == '\n') {
      line++;
      c = 0;
    }
    else {
      lines[line][c] = *str;
      c++;
    }
    str++;
  }
  sprintf(temp, "{\"celldata\":{\"cells\":[");
  strcat(returnString, temp);
  while (i < 7) {
    tokenize(lines[i], &mcc, &mnc, &lac, &cid, &rxl);
    sprintf(temp, "{\"cell\":\"%d\",\"mcc\":\"%ld\",\"mnc\":\"%ld\",\"lac\":\"%ld\",\"cid\":\"%ld\",\"rxl\":\"%ld\"}", i, mcc, mnc, lac, cid, rxl);
    strcat(returnString, temp);
    if (i < 6){
      strcat(returnString, ",");
    }
    i++;
  }
  sprintf(temp, "]},\"ID\":\"%s\"}", imei);
  strcat(returnString, temp);
}

/*
 * function to tokenize from line of data separated by comma
 */

void tokenize(char * line, long * mcc, long * mnc, long * lac, long * cid, long * rxl) {
  char * token = NULL;
  char storeCENG[10];
  char mcc_char[6];
  char mnc_char[6];
  char lac_char[6];
  char cid_char[6];
  char bsic_char[6];
  char rxl_char[6];


  /* 
   *  use strtok to separate each parameter
   *  use strtol to convert from string to long
   */
  strcpy(storeCENG, strtok(line,","));
  *mcc = strtol(strcpy(mcc_char, strtok(NULL,",")),NULL,10);
  *mnc = strtol(strcpy(mnc_char, strtok(NULL,",")),NULL,10);
  *lac = strtol(strcpy(lac_char, strtok(NULL,",")),NULL,16);
  *cid = strtol(strcpy(cid_char, strtok(NULL,",")),NULL,16);
  strcpy(bsic_char, strtok(NULL,","));
  *rxl = strtol(strcpy(rxl_char, strtok(NULL,",")),NULL,10);  
}

/*
 * function to get IMEI number as a ID number
 */

void findingIMEI(char * input, char * returnIMEI) {
  int j = 0;
  char * ptr = strstr(input, "AT+GSN\r");
  while (*ptr != '\0') {
    if (*ptr == '\n' || *ptr == '\r' || *ptr == 'A' || *ptr == 'T' || *ptr == '+' || *ptr == 'G' || *ptr == 'S' || *ptr == 'N') {
      ptr++;
    }
    else {
      returnIMEI[j++] = *ptr;
      if (j == 15) {
        break;  
      }
      ptr++;
    }
  }
}

I get the result on monitor as shown below.

{"celldata":{"cells":[{"cell":"0","mcc":"520","mnc":"18","lac":"14011","cid":"7879","rxl":"40"},{"cell":"1","mcc":"520","mnc":"18","lac":"14011","cid":"4688","rxl":"18"},{"cell":"2","mcc":"520","mnc":"18","lac":"14011","cid":"7877","rxl":"17"},{"cell":"3","mcc":"520","mnc":"18","lac":"14011","cid":"7878","rxl":"13"},{"cell":"4","mcc":"0","mnc":"0","lac":"0","cid":"0","rxl":"21"},{"cell":"5","mcc":"0","mnc":"0","lac":"0","cid":"0","rxl":"21"},{"cell":"6","mcc":"0","mnc":"0","lac":"0","cid":"0","rxl":"20"}]},"ID":"013950007xxxxxx220000,16,21
+CENG:6,000,00,0000,000

At "ID": "013950007xxxxxx"} <- This should end here with bracket.

My question is why the place that should be a close bracket } has more string instead? How can I fix this?

Thanks

while(ConnectSerial.available()) {
      celldata[i++] = ConnectSerial.read();
    }

what is preventing you from overflowing the boundaries of celldata?

BulldogLowell:
what is preventing you from overflowing the boundaries of celldata?

I reset i=0 every time it enter the condition. So that should start over from the beginning of the array. Is that correct?

I reset i=0 every time it enter the condition

OK, but what if you get more than the 256 bytes of data that celldata can hold ?

UKHeliBob:
OK, but what if you get more than the 256 bytes of data that celldata can hold ?

I have low memory issue so I try to reduce the size. I have tested many times and 256 is the size the can contain my data with no overflow.

Is 1 character equal to 1 byte?

ino_beginner:
Is 1 character equal to 1 byte?

yes.

So why not post a prototype of the data you are trying to parse?

Do you see the expected full string of data if you print it as it is received rather than saving it in celldata ?

UKHeliBob:
Do you see the expected full string of data if you print it as it is received rather than saving it in celldata ?

Yes. It is the same as what I expect. However, it seem there are some extra character too. I means the unreadable like jำ.

Actually, the first time I run this program, the result is satisfied. Is it possible that the problem was on the board?

BulldogLowell:
yes.

So why not post a prototype of the data you are trying to parse?

Here what I need to parse

AT+CENG?

+CENG: 3,0

+CENG:0,520,18,36bb,1ec7,73,37
+CENG:1,520,18,36bb,17cd,22,18
+CENG:2,520,18,36bb,1ec6,64,13
+CENG:3,520,18,36bb,1ec5,12,12
+CENG:4,520,18,36bb,17cb,61,11
+CENG:5,520,18,36bb,1f12,16, 9
+CENG:6,520,18,36da,1ed7,52, 9

OK

Hi guys,

Thank you for your opinions and suggestions.
I have found the problem. The IMEI string is not enough to store value. I thought we can store the value exactly to the size of char. I increase the size from 15 to 16 and the problem is gone.

Here where I edit

//static char IMEI[15];
static char IMEI[16];

Explanation would be appreciated here. :slight_smile:

Cheers.

ino_beginner:
Explanation would be appreciated here. :slight_smile:

First you need to post the code that works and point out clearly what was changed from 15 to 16.

My wild guess is that you needed to make space for the terminating '\0' character

...R

Robin2:
First you need to post the code that works and point out clearly what was changed from 15 to 16.

My wild guess is that you needed to make space for the terminating '\0' character

Sorry for being unclear.
So the string must always have \0 to tell where the end is I see. I forgot that.

Thanks