2021-09-02 05:12 AM
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;
}
}
}
}
}
}
2021-09-02 05:31 AM
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
2021-09-02 06:08 AM
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
Couldn't you just use
usart_sendstring("AT+CGNSINF\r\n");
2021-09-02 09:48 AM
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;
2021-09-02 09:59 AM
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.
2021-09-02 10:24 AM
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
2021-09-02 10:41 AM
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