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