Общий вид "общения" с модемом:
1. Отправляется команда
2. Ответ модема на команду (может отсутствовать)
3. Строка "OK", что мол команда выполнена.
Соответственно есть команды, которые возвращают значение состояния модема, например:
AT+CREG?
+CREG: 0, 1
OK
А есть, которые просто выдают строчку ОК, что команда принята и все, например:
AT
OK
Собственно и нужно отслеживать каждый ответ модема и разбирать его, сейчас я сделал что-то подобное. Функция отправки простой AT команды модему:
Код
uint8_t modem_check_at(void) {
uint32_t flag, rc;
uart3_ex_send_string("AT\r\n");
rc = tn_event_wait(&modem_event, MODEM_SAY_OK, TN_EVENT_WCOND_OR, &flag, 300);
if (rc != TERR_NO_ERR) {
dbg_send("AT fail\r\n");
return ACTION_FAIL;
}
dbg_send("AT ok\r\n");
tn_event_clear(&modem_event, ~(MODEM_SAY_OK));
return ACTION_OK;
}
uint32_t flag, rc;
uart3_ex_send_string("AT\r\n");
rc = tn_event_wait(&modem_event, MODEM_SAY_OK, TN_EVENT_WCOND_OR, &flag, 300);
if (rc != TERR_NO_ERR) {
dbg_send("AT fail\r\n");
return ACTION_FAIL;
}
dbg_send("AT ok\r\n");
tn_event_clear(&modem_event, ~(MODEM_SAY_OK));
return ACTION_OK;
}
А в самом прерывании, если от модема пришла строка содержащее слово ОК, то выставляется флаг MODEM_SAY_OK:
Код
if (strncmp(modem_buffer, "OK", 2) == 0) {
tn_event_iset(&modem_event, MODEM_SAY_OK);
return;
}
tn_event_iset(&modem_event, MODEM_SAY_OK);
return;
}
С простыми командами так проходит, но сложность возникает с теми командами, в которых нужно разбирать ответ модема.
Например команда: AT+CREG?
После отправки модему она возвращает строку с определенными параметрами и после уже слово ОК, что команда выполнена.
Поэтому простой проверкой на слово ОК не обойтись, нужно разбирать, то что ответил модем.
Сделал таким образом: все строчки, которые пришли от модема складываются в очередь, которую уже должна обработать функция, которая отправляла данную команду модему, опять же пример:
Код
uint8_t modem_creg(void) {
uint32_t rc, flag, number_queue;
uart3_ex_send_string("AT+CREG?\r\n");
rc = tn_queue_receive(&queue_modem_buffer, (void**)&number_queue, 300);
if (rc != TERR_NO_ERR) {
dbg_send("CREG fail!\r\n");
return ACTION_FAIL;
}
dbg_send("Answer CREG - ");
dbg_send(modem_queue_buffer[number_queue]);
dbg_send_rn();
}
uint32_t rc, flag, number_queue;
uart3_ex_send_string("AT+CREG?\r\n");
rc = tn_queue_receive(&queue_modem_buffer, (void**)&number_queue, 300);
if (rc != TERR_NO_ERR) {
dbg_send("CREG fail!\r\n");
return ACTION_FAIL;
}
dbg_send("Answer CREG - ");
dbg_send(modem_queue_buffer[number_queue]);
dbg_send_rn();
}
Да момент такой еще, есть один линейный буфер, в который пишутся приходящие символы в прерывании, в том случае когда эту строчку нужно отправить через очередь, содержимое этого линейного буфера копируется в другой буфер, который представляем из себя "массив буферов" и собственно позицию в этом массиве и передается через очередь.
Но в таком случае в очередь может отправится ЭХО модема и вместо ответа "+CREG: 0,2" в функции увидим "AT+CREG?", как вариант прогонять очередь до тех пор пока не попадется нужный нам ответ:
Код
do {
rc = tn_queue_receive_polling(&queue_modem_buffer, (void**)&number_queue);
if (strncmp(modem_queue_buffer[number_queue], "+CREG", 5) == 0) {
return number_queue;
}
} while (rc == TERR_NO_ERR);
rc = tn_queue_receive_polling(&queue_modem_buffer, (void**)&number_queue);
if (strncmp(modem_queue_buffer[number_queue], "+CREG", 5) == 0) {
return number_queue;
}
} while (rc == TERR_NO_ERR);
Но это кажется сильно натянутым решением...
Эхо от модема отключать не желательно,хотя это отчасти и решило бы проблему, но опять же не полностью.
И кроме однострочных команд, модем может выдать много строчные команды.
В общем, у кого-нибудь был опыт работы с АТ командами, кто как реализовал? Заранее благодарен за любой совет/пинок в нужную/правильную сторону.