Skip to main content
salar1991
Associate II
September 2, 2021
Question

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

  • September 2, 2021
  • 2 replies
  • 3689 views

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;
}
 
 
 } 
 
 
 
 } 
 
 
 } 
 
 
 
 } 
 
 } 
 
 

This topic has been closed for replies.

2 replies

Paul1
Senior III
September 2, 2021

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

salar1991
salar1991Author
Associate II
September 2, 2021

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;

Paul1
Senior III
September 2, 2021

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

Tesla DeLorean
Guru
September 2, 2021

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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
salar1991
salar1991Author
Associate II
September 2, 2021

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.