cancel
Showing results for 
Search instead for 
Did you mean: 

using strtok function leads to clearing token before i can use it

salar1991
Associate II

I want to design a GPS car tracker that alarms when the speed reaches a certain value and I want to first test the code with the USB to TTL module which is connected to my stm32, and simulate sim808 answers. when I send the GPS information only the first time the micro responds correctly and the second time I send the GPS information the micro doesn't respond. when I debugged the code I found out that the second time the strtok function makes token zero before getting tokens and therefore the calculated values are zero. I used strtok before for getting coordinates from sim808 string without problem I don't know what's wrong here and why it works the first time? here is the string i want to get tokens from:

AT+CGNSINF\r\r\n
+CGNSINF:1,1,20210809114956.000,36.343509,59.590779,1029.500,41.25,284.6,1,,1.0,1.3,0.8,,11,7,,,29,,\r\n
\r\n
OK\r\n
 
 
 
 
 

here is my main code :

 #include <stm32f10x.h>
#include "usart.h"
#include <string.h>
#include <stdio.h>  
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
 
char S=0x1A;
#define Enter    usart_sendchar('\n');
#define CR       usart_sendchar('\r');
#define GIM      usart_sendchar('"');
#define SUB      usart_sendchar(S);
char get_Enter = 0;
uint8_t ch;
uint8_t ch2;
 char str1[400];
 char str3[400];
int g=0;
int i=0;
char flag=0;
char str_tmp[20];
char str_tmp2[20];
char* p;
char* j;
int sec=0;
// cheraghchi street start point
float a=36.345135;
float b=59.548276;
// cheraghchi street end point 
float c=36.325215;
float d=59.628918;
// speed limit of cheraghchi 
float w=40.00;
 
 
//calling all the functions 
 
void Send_SMS(char *text);
void Send_KEY(char *text);
void del_All_SMS(void);
void CMGF_1(void);
void CMGF_KEY(void);
void CMGR (void);
void CGNSPWR(void);
void CGNSINF(void);
void CGNSINF_t(void);
void Send_CAUTION(char *text);
void AT(void);
void Delay (uint32_t Time);
void USART1_IRQHandler(void);
void interrupt_activation(void);
void EXTI3_IRQHandler(void);
void EXTI1_IRQHandler(void);
void EXTI2_IRQHandler(void);
 
 
void Delay (uint32_t Time)
{
    uint32_t i;
    
    i = 0;
    while (Time--) {
        for (i = 0; i < 5000; i++);
    }
}
 
void timer_init(void) {
    
RCC->APB2ENR |= (1<<3);
GPIOB->CRL &=~0xF;
GPIOB->CRL |= 0x3;            //////// GPIOB.0  output push pull
RCC->APB2ENR |= (1<<11);             /* enable clock for TIM1    */
 
TIM1->PSC   = ( 7200 - 1);   /* set prescaler   = 10KHz  */
TIM1->ARR   = ( 5000 - 1);   /* set auto-reload = 500 ms */
 
TIM1->DIER = (1<<0);   /* Update Interrupt enable  */
 
 
TIM1->CR1  |= (1<<0);   /* 0x0001 timer enable       */
    
NVIC_SetPriority(TIM1_UP_IRQn,1);
    
}
 
 
void TIM1_UP_IRQHandler (void) 
{
sec++;
if (TIM1->SR & (1<<0))
    {
    
    if (sec==10)
    {
 
    str_tmp[0]='\0';      
  strcpy(str_tmp,"AT+CGNSINF");       
  usart_sendstring(str_tmp);
  Enter
    CR 
                     
        
    }
    else if (sec==20)
    {
    
    if (p)
{
 
 
float e[7];
float m; //for latitude
float n; //for longitude 
float z; //for speed
    
char str2[80];
   const char s[2] = ",";
   char *token;
   // getting the lattitude and longitude 
   token = strtok(p, s);
   
    for (int i=0;i<7;i++){ 
      sprintf( str2," %s", token );   
        e[i]=atof(str2);
    token = strtok(NULL, s);
      
    } 
    
   
    token=NULL;
    m=e[3];// latitude
    n=e[4]; // longitude
    z=e[6]; // speed
          if (m<a && m>c && n>b && n<d)   {
          
               if  (z>w)
                 {
                 
                 Send_CAUTION("CAUTION ! illegal speed ");
                     sec=0; // for illegal speed 
                     p=NULL;
                    for (int i=0;i<7;i++){
                    
                    e[i]=0;
                    
                    }
                 }
             sec=0;  // for normal speed 
          }
        sec=0;    // for out of range streets
    
    }
    
    
    }
    
 
}
TIM1->SR &= ~0x1;   
}
 
void CMGF_CAUTION(void)
 {
    str_tmp[0]='\0';     
    strcpy(str_tmp,"AT+CMGF=1");
    usart_sendstring(str_tmp);
    Enter
    CR  
    
 }
 
 
void Send_CAUTION(char *text)
{
CMGF_CAUTION(); 
       
str_tmp[0]='\0';
       
 
strcpy(str_tmp,"AT+CMGS=");
       
usart_sendstring(str_tmp);
GIM
str_tmp[0]='\0';
      
 
strcpy(str_tmp,"+98905xxx6399");
       
usart_sendstring(str_tmp);
GIM
Enter
CR
           
 
 usart_sendstring(text);
Enter
CR
str_tmp[0]='\0';
       
SUB
 
 
del_All_SMS();
}
 
 
 
 
void Send_SMS(char *text)
{
CMGF_1(); 
Delay(500);       
str_tmp[0]='\0';
Delay(100);       
 
strcpy(str_tmp,"AT+CMGS=");
Delay(500);       
usart_sendstring(str_tmp);
GIM
str_tmp[0]='\0';
Delay(100);       
 
strcpy(str_tmp,"+98905xxx6399");
Delay(500);       
usart_sendstring(str_tmp);
GIM
Enter
CR
 
Delay(500);           
 
 usart_sendstring(text);
Enter
CR
str_tmp[0]='\0';
Delay(500);       
SUB
 
Delay(100);
del_All_SMS();
}
 
 
 
 
 
 
 
void USART1_IRQHandler(void) {
 
        ch = USART1->DR & 0xFF; 
          ch2 = USART1->DR & 0xFF; 
       
    if (str1[346]!=NULL)                 {
             
            for (int j=0;j<400;j++)
        {
        
        str1[j]=0;
        
        
        }
        i=0;
    }   
    else if (str3[240]!=NULL)
        for (int g=0;g<400;g++)
    {
    str3[g]=0;
    }
 else {     
            str1[i]= ch;
              str3[g]=ch2; 
            i++;
              g++;
 }
 
 
 
 }
 
 
            
             
             
             
             
             
                 
 
 
    void CGNSINF_t(void)
 {
    str_tmp[0]='\0';      
    strcpy(str_tmp,"AT+CGNSINF");       
    usart_sendstring(str_tmp);
  Enter
    CR      
 }
 
 
    void CMGF_1(void)
 {
    str_tmp[0]='\0';
    Delay(100);       
    strcpy(str_tmp,"AT+CMGF=1");
    Delay(500);       
    usart_sendstring(str_tmp);
  Enter
    CR  
    
 }
 
 
 void del_All_SMS(void)
 {
str_tmp[0]='\0';
Delay(100);
strcpy(str_tmp,"AT+CMGD=1,4");
Delay(500);       
usart_sendstring(str_tmp);
Enter
CR   
}
 
 
    void CMGR(void)
 {
    str_tmp[0]='\0';
  
    Delay(100);      
    strcpy(str_tmp,"AT+CMGR=1");
  Delay(500);    
    usart_sendstring(str_tmp);
  Enter
    CR  
    
 }
    void CGNSINF(void)
 {
    str_tmp[0]='\0';
    Delay(100);       
    strcpy(str_tmp,"AT+CGNSINF");
    Delay(500);       
    usart_sendstring(str_tmp);
  Enter
    CR      
    
 }
void CGNSPWR_1(void)
 {
    str_tmp[0]='\0';
    Delay(100);       
    strcpy(str_tmp,"AT+CGNSPWR=1");
        Delay(500);
    usart_sendstring(str_tmp);
    Enter
    CR  
    
 }
 
 void AT(void)
 {
    str_tmp[0]='\0';  
    Delay(100);  
    strcpy(str_tmp,"AT");
        Delay(500);
    usart_sendstring(str_tmp);
    Enter
    CR  
    
 }
 
 
 
 
 
 
    
    
int main() 
    {
    SystemInit();
    usart_init();   
    timer_init();           
        AT();  
        
         
            check:AT();
  
        Delay(2000);
        
        p=strstr(str1,"OK");   
        if(p==NULL) goto check;
        
             
  CMGF_1();
    Delay(500);
 
    CGNSPWR_1();
    
    Delay(500); 
  del_All_SMS();
    
    Delay(500);
     p=NULL;
 NVIC_EnableIRQ(TIM1_UP_IRQn);
        
while (1)
{
    
   
 
            
        if (flag==0){
                
       ////waiting for +CMTI: from sim800
 
         do {
                 
                  
                 p=strstr(str3,"+CGNSINF:");
                
                 
                 }
         while(!(strstr(str1,"+CMTI:")));
         Delay(1000);
                // sending AT+CMGR=1 command
           
                    CMGR();
            
                    Delay(2500);
                flag=1;
           
        
    if (flag==1) {
        p=strstr(str1,"+CMGR");
              j=strstr(str1,"loc");
            if (p&&j){                           
CGNSINF();
    Delay(300);
}
else 
{
del_All_SMS();
flag=0;
    
}
p=strstr(str1,"+CGNSINF:");
if (p)
{
 
 
float a[5];
          
char str2[80];
   const char s[2] = ",";
   char *token;
   // getting the lattitude and longitude 
   token = strtok(p, s);
   
    for (int i=0;i<5;i++){
      sprintf( str2," %s\n", token );
        a[i]=atof(str2);
    
      token = strtok(NULL, s);
    } 
 
sprintf(str2,"https://maps.google.com/?q=%.6f,%.6f",a[3],a[4]);
Send_SMS(str2);
p=NULL;
Delay(5000);        
del_All_SMS();
 
    flag=0;
 
for (int k=0;k<80;k++){
str2[k]=0;
}
 
 
    } 
 
 
 
      } 
            
            
        } 
        
             
             
        } 
            
            }   
  
    

6 REPLIES 6
Paul1
Lead

Haven't used STRTOK much.

I'd suggest trying sscanf, as it could extract the fields to final data types (floats, ints, strings, etc) which seams more appropriate for the data,

and could do all that in a single call, and return the actual number of converted fields.

Paul

All rather messy. Such a lot of dead-space, and inconsistent formatting makes it hard to read. Spend some time cleaning it up, removing a lot of the unnecessary clutter, and getting it indented properly.

Generally I'd avoid strtok() and use strsep() instead, it works better with empty fields and is thread safe.

You should avoid use of blocking functions in the timer interrupt.

Sending things to the modem in the main loop and interrupt, probably going to step on each other, and stop the modem working properly.

Perhaps use a state-machine implementation in the main loop, rather than using delays/interrupts, so the processing can occur in a linear fashion.

If you're changing it under interrupt, p should be volatile

  1. str_tmp[0]='\0';
  2. strcpy(str_tmp,"AT+CGNSINF");
  3. usart_sendstring(str_tmp);
  4. Enter
  5. CR

Couldn't you just use

usart_sendstring("AT+CGNSINF\r\n");

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

while I was searching for examples of sscanf for strings with "," I couldn't find one but I came across another function for tokenizing the string which worked but after the second time I send the GPS info the micro hangs and when I debugged it was because of a hard fault error I don't know why.

the function is as shown below :

int strCSV2Float(float *strFloatArray , char *myCSVStringing)
{
 
int strLen = 0;
int commaCount =0; // count the number of commas
int commaCountOld =0; // count the number of commas
int wordEndChar = 0;
int wordStartChar = -1;
int wordLength =0;
 
for(strLen=0; myCSVStringing[strLen] != '\0'; strLen++) // first get the string length
   {
 
       if ( (myCSVStringing[strLen] == ',')  || ( myCSVStringing[strLen+1] == '\0' ))
        {
           commaCount++;
           wordEndChar = strLen;
        }
       if ( (commaCount - commaCountOld) > 0 )
        {
          int aIter =0;
          wordLength = (wordEndChar - wordStartChar);
          char word[55] = "";
          for (aIter = 0;  aIter < wordLength; aIter++)
          {
            word[aIter] = myCSVStringing[strLen-wordLength+aIter+1];
          }
 
          if (word[aIter-1] == ',') 
           word[aIter-1] = '\0';
 
          //  printf("\n");
          word[wordLength] = '\0';
          strFloatArray[commaCount-1] = atof(&word[0]);
 
          wordLength = 0;
          wordStartChar = wordEndChar;
          commaCountOld = commaCount;
 
        }  
  }
 
  return commaCount;
 
}

and I use it as follows :

float floatArr[10]; // specify size here 
    int totalValues = 0;
totalValues = strCSV2Float(&floatArr[0] , p); // call the function here
   // getting the lattitude and longitude 
 
   
	
	m=floatArr[3];// latitude
	n=floatArr[4]; // longitude
	z=floatArr[6]; // speed
		  if (m<a && m>c && n>b && n<d)   {
		  
			   if  (z>w)
				 {
				 
				 Send_CAUTION("CAUTION ! illegal speed ");
					 sec=0; // for illegal speed 
					 p=NULL;

thanks for your answer I tried using strsep but my compiler doesn't recognize it although I added string. h header probably because this function is new. I tried defining p as volatile but it didn't change anything.

a. It is hard to follow your code, maybe change your editor to insert tabs instead of spaces as tab size may differ here from your editor? True also when copying code to other systems.

b. The second code block doesn't seem to use the first? actually both code blocks seem to be missing some beginning/end lines.

1. Add more debug till it works.

i.e. printf of strlen and char read [%c] and asc of char read [0x%02x] so can see what char and length crashing on, as they may indicate things like end of file, end of buffer, end of line, special char, etc.

2. For is stopping on NUL, but what about if no NUL and going past end of buffer? That would be a fault.

In "for" add something like: && (strLen+1)<sizeof(myCSVStringing) //to ensure not past end of buffer

3. Merge first two ifs, don't need "if ( (commaCount - commaCountOld) > 0 )" since just incremented commaCount.

4. Actually did you intend to increment commaCount upon NUL? Recommend making the NUL check its own if since checking a different char index.

5. Might be easier to test this sscanf code on a windows or online C compiler. Easier diag printf.

Online C = C++ Shell: http://cpp.sh/

6. Here is a sample SSCANF that pulls tokens separated by whitespace, and nulls any unused fields:

    sCfgLine.iExtractedFields = sscanf(pcLine, "%64s%64s%64s%64s%64s%64s%64s%64s", 
            sCfgLine.ppcFields[0], sCfgLine.ppcFields[1], 
            sCfgLine.ppcFields[2], sCfgLine.ppcFields[3], 
            sCfgLine.ppcFields[4], sCfgLine.ppcFields[5],
            sCfgLine.ppcFields[6], sCfgLine.ppcFields[7]);//Return = EOF=Fail, or Number of Converted Fields
    if(sCfgLine.iExtractedFields < 1){sCfgLine.ppcFields[0][0]=ASC_NUL;}
    if(sCfgLine.iExtractedFields < 2){sCfgLine.ppcFields[1][0]=ASC_NUL;}
    if(sCfgLine.iExtractedFields < 3){sCfgLine.ppcFields[2][0]=ASC_NUL;}
    if(sCfgLine.iExtractedFields < 4){sCfgLine.ppcFields[3][0]=ASC_NUL;}
    if(sCfgLine.iExtractedFields < 5){sCfgLine.ppcFields[4][0]=ASC_NUL;}
    if(sCfgLine.iExtractedFields < 6){sCfgLine.ppcFields[5][0]=ASC_NUL;}
    if(sCfgLine.iExtractedFields < 7){sCfgLine.ppcFields[6][0]=ASC_NUL;}
    if(sCfgLine.iExtractedFields < 8){sCfgLine.ppcFields[7][0]=ASC_NUL;}

7. For commas should be able to use: "%64s,%64s,%64s,%64s,%64s,%64s,%64s,%64s",

but be careful as may have issues if some commas missing, or surrounded by whitespace.

Paul

8. Option: Since your feed string doesn't have space chars, you could pre-scan the your string data and change commas to spaces, then sscanf will work easily.

Paul