Я работал над приложением, которое использует GSM-модем для одной из двух вещей; проверьте его статус, используя встроенный стек HTTP, отправив на сервер запрос GET или отправив данные на сервер (используя UDP). Я пробовал несколько разных методов, чтобы сделать это максимально надежным, и я, наконец, готов обратиться за помощью.
Мое приложение написано для модуля SIMCOM908 и платформы PIC18 (я использую PIC18 Explorer для разработки).
Итак, проблема в том, что модем занят чем-то занятым и пропускает команду. Как человек, я бы это увидел и просто перешлю команду. Добавление объекта для моего MCU к тайм-ауту и повторной отправке не является проблемой.
В чем проблема, так это то, что модем отправляет незапрашиваемые ответы после разных событий. Когда модем изменит статус регистрации (с башней ячейки), он ответит с помощью +CGREG: 1, ...
или когда GPS будет готов GPS Ready
. Эти ответы могут возникать в любое время, в том числе в середине команды (например, создание IP-соединения).
Это проблема, потому что я не думал о способе справиться с этим. Моему приложению необходимо отправить команду (например, для подключения к серверу, AT+CIPSTART="UDP","example.com",5000
). Эта команда будет отвечать на "OK", а затем, когда команда завершит "CONNECT OK". Тем не менее, мне нужно иметь возможность реагировать на многие другие возможные ответы, и я не понял способ сделать это. Что мне нужно сделать с моим кодом; ждать ответа от модема, проверить ответ, выполнить действие на основе этого ответа?
Я ограничен кодом (будучи 8-разрядным микроконтроллером!) и хотел бы, чтобы повторение сохранения было минимальным. Как я могу написать функцию ответа, которая будет принимать ответ от модуля GSM (запрашивается или сейчас), а затем пусть остальная часть моей программы знает, что происходит?
В идеале, я бы хотел сделать что-то с этими ответами. Как и внутреннее состояние (когда я слышу GPS Ready
, я знаю, что могу подключить GPS и т.д.
Возможно, есть некоторые вещи, о которых я должен думать, или, может быть, есть проект с открытым исходным кодом, который уже решает эту проблему?
Вот что я до сих пор:
/* 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;
}
Простой командой является любая команда AT, которая специально ищет OK
или ERROR
в ответ. Что-то вроде AT
. Тем не менее, я также использую его для более продвинутых команд, таких как AT+CPIN?
, потому что это означает, что я захватил бы весь ответ и мог бы продолжить поиск +CPIN: READY
. Тем не менее, ничто из этого не реагирует на нежелательные ответы. Фактически, функция gsm_sendCommand()
вернется раньше, когда будет получен незапрашиваемый ответ.
Какой хороший способ управлять сложными, иногда незапрашиваемыми сообщениями о статусе? Обратите внимание, что это приложение написано на C и работает на 8-битном микроконтроллере!