This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hello,
I've been trying (with not very much success) to send SMS to my TM4C MCU via a SIMCom SIm900 GSM module.
They are connected through UART2 (PD6 and PD7), sending UART data to the GSM module works without issues, also sending SMS messages...
I managed to put together a program to receive (read) and parse SMS messages, it works but with quite a lot of bugs, it doesn't have a predictable output and it very important in the application where I would like to integrate this.
As I seen so far the content of the RX data is the issue.
I'll paste my initialization functions and sms processing functions here. Maybe someone can help me out with a tip.
UART2 Init Function, that uses UART STDIO from TIVAWARE
void UART2_Init(void){ uint32_t uart_config_read = 0; SysCtlPeripheralEnable(SYSCTL_PERIPH_UART2); //Enable clock on UART2 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); //Enable clock on port D //PD6 and PD7 will be RX and TX to GSM module while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UART2)); //wait for UART2 to initialize while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOD)); //wait for PortD to initialize GPIO_PORTD_LOCK_R = 0x4C4F434B; //Unlock GPIO PD7 GPIO_PORTD_CR_R |= 0xC0; //Allow changes to PD6,7 IntDisable(INT_UART2); UARTIntDisable(UART2_BASE,UART_INT_RX|UART_INT_TX|UART_INT_RT); //Disable UART2 Interrupts UARTDisable(UART2_BASE); //Disable UART2 while configuration GPIOPinConfigure(GPIO_PD6_U2RX); //PCTL GPIOPinConfigure(GPIO_PD7_U2TX); GPIOPinTypeUART(GPIO_PORTD_BASE, GPIO_PIN_6 | GPIO_PIN_7); //DIR, PAD, UARTClockSourceSet(UART2_BASE, UART_CLOCK_SYSTEM); //Set the clock source for UART2 UARTParityModeSet(UART2_BASE, UART_CONFIG_PAR_NONE); UARTFIFOEnable(UART2_BASE); //Enable the UART FIFO UARTStdioConfig(GSM_UART_PORT, GSM_BAUD_RATE, SysCtlClockGet()); UARTEchoSet(false); UARTIntRegister(UART2_BASE,&UARTStdioIntHandler); UARTConfigGetExpClk(UART2_BASE, SysCtlClockGet(), &GSM_Baud_Rate_Read, &uart_config_read); //Get the Baud Rate }
Initialization function of GSM module:
void PowerOnGSM(void){ uint8_t lineCount = 0; uint16_t i = 0; uint8_t uart2_dump[1024] = ""; UARTprintf("AT+CMGF=%u\r\n",1); //message format text SysCtlDelay(Millis2Ticks(100)); //Interrupts are NOT disabled and OS is NOT stoped during delay! lineCount = GSMgetResponse(); UARTprintf("AT+CSDH=%u\r\n",0); //do not show complete message header SysCtlDelay(Millis2Ticks(100)); lineCount = GSMgetResponse(); UARTprintf("AT+CNMI=%u%u%u%u%u\r\n",0,0,0,0,1); //set new message indication mode //Messages are stored on GSM module, no indication is provided //AT+CMGR=msgNum will read the messages when user triggers GSMprocessMessage(msgNum) SysCtlDelay(Millis2Ticks(100)); lineCount = GSMgetResponse(); }
SMS Processing functions: void GSMprocessMessage(uint8_t msgNum), uint8_t GSMgetResponse(void), bool GSMparseMessage(uint8_t lineCount)
//***************************************************************************** // // PROCESS SMS FOR ENVELOPE AND CONTENT // //***************************************************************************** void GSMprocessMessage(uint8_t msgNum) { bool msgPresent = 0; // Flag to ignore deleted messages int lineCount=0; // Hold the number of lines // Request the message and get the lines of the response (includes envelope, nulls, SIM responses) UARTprintf("AT+CMGR=%u\r\n",msgNum); //read request for msgNum SysCtlDelay(Millis2Ticks(10)); // Start message retrieval lineCount = GSMgetResponse(); // Make sure there's message content, process for envelope and content msgPresent = GSMparseMessage(lineCount); // Show the user what we found PC_Display_Message("\n\r>>> MESSAGE :",msgNum," "); if (msgPresent) { PC_Display_Message("> FROM: ",0,msgSender); //TODO: Try to send a BS to delete the 0 PC_Display_Message("> AT:",0,msgDate); PC_Display_Message("> ON: ",0,msgTime); PC_Display_Message("> TEXT :",0,msgContent); } else PC_Display_Message("> NOT PRESENT!",0," "); } //***************************************************************************** // // STORE A GSM RESPONSE TO ARRAY responseLine[] // //***************************************************************************** uint8_t GSMgetResponse(void) { bool readResponse = true; // Keeps the loop open while getting message int readLine = 0; // Counts the lines of the message char *GSMresponse = NULL; // Use to grab input char g_cInput[128]; // String input to a UART PC_Display_Message("> Started message reading", 0," "); while(readResponse&&(readLine<10)) { //TODO, do not hardcode, use macro // Grab a line //UART2_GetString(g_cInput,sizeof(g_cInput)); //grabs string untill character != CR or LF if(UARTRxBytesAvail() > 2) UARTgets(g_cInput,sizeof(g_cInput)); // Stop after newline strcpy(responseLine[readLine],g_cInput/*GSMresponse*/); //PC_Display_Message(">>> Line nr: ", readLine, g_cInput); //PC_Display_Message(">>> Line nr: ", readLine, responseLine[readLine]); // If this line says OK we've got the whole message if((strncmp(responseLine[readLine],"OK",2)==0)|| (strncmp(responseLine[readLine],"ERROR",5)==0)){ readResponse = false; } else readLine++; } return (readLine+1); } //***************************************************************************** // // PARSE GSM MESSAGE FOR ENVELOPE AND MESSAGE CONTENT // Stores message envelope and constant to global variables, OR returns true // for message present, false for no message // //***************************************************************************** bool GSMparseMessage(uint8_t lineCount) { uint8_t activeLine = 0; // Counter for line being processed char *msgEnvelope = NULL; // Message envelope holder msgContent = NULL; // Clear out the old message // Parse the new message while (activeLine < lineCount) //lineCount is larger by 1 than responseLine [index] { PC_Display_Message("Processed line: ",activeLine,responseLine[activeLine]); // CASE FOR ENVELOPE (which will look like:) // +CMGR: "REC READ","+40712334501","","17/04/12,22:53:48+12" if ( strstr(responseLine[activeLine],"+CMGR:") != '\0' ) //if message received { // Start parsing msgEnvelope = responseLine[activeLine]; PC_Display_Message("> Envelope is: ",0,msgEnvelope); msgSender = strtok(msgEnvelope,","); // Go to first comma, skipping status msgSender = strtok(NULL,","); // Grab the number msgSender += 3; // Skip the prefix from the phone number and qautation marks msgSender[10] = '\0'; // Store the number (with null terminator) msgDate = strtok(NULL,","); // Go to next comma, skipping phonebook entry msgDate = strtok(NULL,","); // Grab the date msgDate += 1; //remove qautation marks msgDate[8] = '\0'; // Store the date (with null terminator) msgTime = strtok(NULL,","); // Grab the time msgTime[8] = '\0'; // Store the time (with null terminator) } // CASE FOR MESSAGE CONTENT // If we already found the envelope, and the line's not blank... else if (( msgEnvelope != NULL) && (responseLine[activeLine] != NULL)) { // ... and we haven't found any content, this is the first line. if (msgContent == NULL) {msgContent = responseLine[activeLine];} // ... otherwise, add a space and append this line. else if ( activeLine+2 <= lineCount ) { //+2 because of emply line before OK and last line with OK. strcat(msgContent, " "); strcat(msgContent, responseLine[activeLine]); } } activeLine++; // Proceed to next line } if (msgEnvelope == NULL) { // If we didn't find an envelope, there's no message return false; } else { // Otherwise, return true. return true; } }
Global data and defines:
// Data from most recent incoming message stored here char responseLine[10][160]; // Use to store UART inputs static char *msgContent = NULL; // Message content holder static char *msgSender = NULL; // Message sender static char *msgDate = NULL; // Message date static char *msgTime = NULL; // Message time #define BAUD_RATE (115200) #define GSM_BAUD_RATE (115200) #define GSM_UART_PORT (2) #define UART2_INT_PRIO (2)
I call GSMprocessMessage(msgNum) from a GPIO ISR, when I want to read a SMS (specifying the msgNum I want to read).
The program as it is works, but gets a valid result (correct SMS retriaval and parsing) ~ 2 out of 10 times.
If you have any suggestions, tips please let me know.
Regards,
Alex Gaal
Hello Alex. Don't worry. Your code is O.K. but do this: connect to the GSM/GPRS module with let's say puTTY over serial*. Send all the needed AT+ commands to the module and wait for the response. Note response times and response messages. Then inside your source create some time depended reading loops and wait for the known answers when AT+ commands are send through your code. If you do it just carefully, then your code will go rock-n'-rolling. SIM900/800 modules and the other known, when triggered over serial have those delay answering problems. You either code proper time waiting and check loops, or you go a step further and you download the module's SDK and you write an applet that loads directly onto the GSM/GPRS module's flash, thus creating your own deterministic serial communication schema. BUT, also have in mind that there is set of AT+ commands that minimize the useless responses from the GSM modules and that alone speed things up very much and also makes the whole communication schema more deterministic.
*--Note that TTL of GSM module is about 3.5 volt while PC's serial is +/- 12v. You need an RS-232-to-TTL 3.3V converter for directly connecting module with PC' serial.
Good luck,
John
P.S. Instead strncmp use indexof