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