I've been working on an application which uses a GSM modem for one of two things; check its status using the built in HTTP stack by sending a GET request to the server, or sending data to the server (using UDP). I have tried several different methods to keep this as reliable as possible, and I'm finally ready to ask for help.
My application is written for the SIMCOM908 module and the PIC18 platform (I'm using a PIC18 Explorer for development).
So the problem is sometimes the modem is busy doing something, and misses a command. As a human, I would see that and just resend the command. Adding a facility for my MCU to timeout and resend isn't an issue.
What is an issue is that the modem sends unsolicited responses after different events. When the modem changes registration status (with the cell tower) it would respond with +CGREG: 1, ...
or when the GPS is ready GPS Ready
. These responses can happen at any time, including in the middle of a command (like creating an IP connection).
This is a problem, because I haven't thought of a way to deal with this. My application needs to send a command (to connect to the server for example, AT+CIPSTART="UDP","example.com",5000
) This command will response with 'OK', and then when the command has finished 'CONNECT OK'. However, I need to be able to react to the many other possible responses, and I haven't figured out a way of doing this. What do I need to do with my code to; wait for a response from the modem, check the response, perform an action based on that response?
I am code limited (being an 8-bit microcontroller!) and would like the keep repetition to a minimum. How can I write a response function that will take a response from the GSM module (solicited or now) and then let the rest of my program know what is happening?
Ideally, I'd like to do something with those responses. Like keep an internal state (when I hear GPS Ready
, I know I can power the GPS etc.
Maybe there are some things I should think about, or maybe there's an open source project that already solves this problem?
Here's what I have so far:
/* Command responses */
enum {
// Common
OK = 0,
ERROR,
TIMEOUT,
OTHER,
// CGREG
NOT_REGISTERED,
// CGATT
NOT_ATTACHED,
// Network Status
NO_NETWORK,
// GPRS status
NO_ADDRESS,
// HTTP ACTION
NETWORK_ERROR,
// IP Stack State
IP_INITIAL,
IP_STATUS,
IP_CONFIG,
UDP_CLOSING,
UDP_CLOSED,
UDP_CONNECTING
} gsmResponse;
int gsm_sendCommand(const char * cmd) {
unsigned long timeout = timer_getCurrentTime() + 5000;
uart_clearb(GSM_UART); // Clear the input buffer
uart_puts(GSM_UART, cmd); // Send the command to the module
while (strstr(bf2, "\r") == NULL) { // Keep waiting for a response from the module
if (timeout < timer_getCurrentTime()) { // Check we haven't timed out yet
printf("Command timed out: %s\r\n", cmd);
return TIMEOUT;
}
}
timer_delay(100); // Let the rest of the response be received.
return OK;
}
int gsm_simpleCommand(const char * cmd) {
if (gsm_sendCommand(cmd) == TIMEOUT)
return TIMEOUT;
// Getting an ERROR response is quick, so if there is a response, this will be there
if (strstr(bf2, "ERROR") != NULL)
return ERROR;
// Sometimes the OK (meaning the command ran) can take a while
// As long as there wasn't an error, we can wait for the OK
while (strstr(bf2, "OK") == NULL);
return OK;
}
A simple command is any AT command that is specifically looking for OK
or ERROR
in response. Something like AT
. However, I also use it for more advanced commands like AT+CPIN?
because it means I will have captured the whole response, and can further search for the +CPIN: READY
. However, none of this actually response to the unsolicited responses. In fact, the gsm_sendCommand()
function will return early when the unsolicited response is received.
What a good way to manage complex, occasionally unsolicited, status messages like this? Please take note that this application is written in C, and runs on an 8bit microcontroller!
newstate = oldstate [ message ]
, and maybe consider the other end to be state machine, too. – Pursuit