Написание драйвера модема GSM?

Я работал над приложением, которое использует 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-битном микроконтроллере!

Ответ 1

Необходимость обрабатывать как незапрашиваемые сообщения, так и ответы на запросы в одном и том же потоке данных затруднена, поскольку вам потребуется демультиплексировать входящий поток и отправить результаты соответствующему обработчику. Это немного похоже на обработчик прерываний, в котором вам нужно отказаться от того, что вы делали, и обрабатывать этот другой бит информации, который вы не ожидали.

Некоторые модули имеют дополнительный последовательный порт, который также может использоваться для сообщений. Если это возможно, у вас могут быть нежелательные сообщения только на одном последовательном порту, а главный порт - для ваших AT-команд. Это может быть невозможно, и некоторые модули GSM не будут поддерживать полный набор команд на вторичном порту.

Возможно, лучший подход - просто отключить нежелательные сообщения. Большинство команд запрашивает все состояние. например, ожидая регистрации, вместо того, чтобы ждать появления незапрашиваемого регистрационного сообщения, просто опросите модуль для текущего состояния регистрации. Это позволяет вам всегда контролировать, и вам нужно обрабатывать ответы только что отправленной команды. Если вы ожидаете нескольких событий, вы можете поочередно опросить цикл для каждого элемента. Это, как правило, делает код более простым, поскольку вам нужно обрабатывать только один ответ за раз. Недостатком является то, что время отклика ограничено вашей частотой опроса.

Если вы продолжаете использовать подход к нежелательным сообщениям, я бы предложил реализовать небольшую очередь для нежелательных сообщений. Ожидая ответа на команду, если ответ не соответствует команде, просто нажмите ответ в очереди. Затем, когда вы либо получили ответ на свою AT-команду, либо вышли из строя, вы можете обработать незапрашиваемую очередь сообщений после этого.