Управление GSM модулем с AVR (часть 2)

Теперь о получении команд с модуля.
Модуль отправляет множество команд. Например, OK, RING, ERROR…
Иногда нужно, чтобы при получении команды контроллер смог опознать её и выполнить какое-то действие. Например, получен входящий звонок. Модуль при этом отправляет в контроллер:
RING
RING
RING
В зависимости от настроек модуля, может отправлять ещё и номер того, кто звонит. Пока нет никакой программы, контроллер ничего с этим сделать не сможет (в лучшем случае) или (в худшем) сделает что не то, а то и вовсе зависнет (не сможет выйти из прерывания).
Требования к коду обработки:
1. Минимальное количество времени на сохранение полученных команд. Никаких задержек в программе прерывания быть не должно. Потом уже с полученным массивом будем делать что угодно.
2. Сохранение всех полученных команд в одном буфере. Для разделения отдельных будем использовать символ $.
3. Распознавание распространенных команд в числовые коды. Например, OK будет 1, ERROR — 4, RING — 2.
Приведу заголовки из предыдущей статьи с поправками:
#define BUF_SIZE 128 //Исходящий буфер
#define BUF_MASK (BUF_SIZE-1)
#define IN_BUF_SIZE 64 //Входящий буфер
#define IN_BUF_MASK (IN_BUF_SIZE-1)
volatile char buffer[BUF_SIZE]="";
volatile char inbuf[IN_BUF_SIZE]="$"; //inner buffer of USART
volatile uint8_t ind_in=0, ind_out=0, rxind_out=0, rxind_in=0, mess = 0;
volatile uint8_t com_detect=0; //сюда будет записана обнаруженная команда
#define TIMEOUT 100 //на случай если команда так и не принята
Пишем обработчик прерывания приёма данных:
//recieving Data from RS232
ISR (USART_RXC_vect)
{
uint8_t tmp;
tmp = UDR;
if (tmp == 0x0D) //получен конец команды - <enter>
{
mess++; //one more message
inbuf[rxind_in++] = '$'; //вставляем разделитель в буфер
rxind_in &= IN_BUF_MASK;
}
else
{
if (tmp != 0x0A) //очистка непонятного символа с модуля
{
inbuf[rxind_in++] = tmp; //записываем в буфер
rxind_in &= IN_BUF_MASK;
}
}
sei ();
}
Теперь у нас все команды записаны в буфере. Можно в свободное время проверить переменную mess и если она не равна нулю запустить обработчик команды. В самом проекте были добавлены команды для LCD экрана. Здесь я их пропущу за ненадобностью.
void rx_check_in (void)
{
uint8_t count=0;
com_detect = 0; //обнуление команды (чтобы не мешал предыдущий мусор)
while (1)
{
if (inbuf[rxind_out] != '$') //обнаружен конец команды (разделитель)
{
com_detect ^= inbuf[rxind_out++]; //делаем XOR полученным символам
rxind_out &= IN_BUF_MASK;
count++; //считаем, сколько символов в команде
}
else
{
rxind_out++;
rxind_out &= IN_BUF_MASK;
code_com (count); //!! важная часть - раскодировать команду
break;
}
}
}
Полученные символы мы пропускаем через мясорубку. Делаем XOR операцию. Получаем таким образом уникальный код (не уверен на счёт уникальности, но пока не подводило). R^I^N^G нам даст 0x12. O^K даст 0x04. Этот код и количество символов (в команде) сохранены в переменных com_detect (глобальная) и count. Теперь запустим обработчик:
void code_com (uint8_t count)
{
switch (com_detect)
{
case (0x12): if (count == 4) com_detect = 2; break; //R^I^N^G
case (0x58): if (count == 5) com_detect = 3; break; //ERROR
case (0x04): if (count == 2) com_detect = 1; break; //OK
case (0x5C): if (count == 3) com_detect = 4; break; //ATI
default: com_detect = 0;
}
}
Распознали команду. Количество символов я ввёл для надёжности на случай если в длинной команде XOR код совпадёт. Распознаваемые команды можно добавлять. Нужно только подсчитать (или макросом) XOR код желаемой команды и присвоить ей цифру.
Теперь в com_detect у нас полученная команда. Теперь устройство может отреагировать SMS сообщением на полученный звонок:
while (1)
{
if (mess != 0) //if we have mess in buffer
{
// code
mess--; //minus one
rx_check_in (); //распознаём отдельную команду
if (com_detect == 2) //если была команда RING (код 2)
{ //Посылаем сообщение
// и принимаем входящие команды (OK)
if (!send_sms (1,NUM0)) ErrMes (); //если после отправки не было команды OK
} //тогда выдать сообщение о ошибке протокола
com_detect = 0; //обнуляем команду
}
Так можно обрабатывать разные полученные команды.
Итог: устройство умеет отправлять сообщение на телефон и умеет реагировать на различные команды от GSM модуля.
Спасибо за внимание.
Готовый проект для Pinboard II выкладываю как пример.
- +2
- 23 сентября 2013, 17:00
- ilus
- 4
Оригинально Вы придумали — сравнивать не строку ответа а хеш от строки. Немного смущают несколько моментов
1. Магические цифры — case (0x04). Но от этого можно уйти (например через макрос)
2. Вероятность коллизии хеш.
3. Вы ожидаете, что ответ не будет содержать дополнительных символов (в принципе так и должно быть послали АТ получили ОК). Но, например, в модеме SIM300D есть полезная штука — indications. Indications – это когда модем самостоятельно инициирует вывод в консоль, по какому-то событию. Этот режим можно выключить, но иногда он полезен. Например, при получении SMS, модем посылает (без запроса) хосту что-то типа «+CMTI: ….». Причем, это может случится в любой момент, даже тогда когда мы ожидаем ответ. Тобиш, может возникнуть ситуация, когда мы послали АТ, а в ответ получили
В этом случае хеш не сойдется, хотя ОК мы получили.
Но идея интересная, спасибо за статью.
1. Магические цифры — case (0x04). Но от этого можно уйти (например через макрос)
2. Вероятность коллизии хеш.
3. Вы ожидаете, что ответ не будет содержать дополнительных символов (в принципе так и должно быть послали АТ получили ОК). Но, например, в модеме SIM300D есть полезная штука — indications. Indications – это когда модем самостоятельно инициирует вывод в консоль, по какому-то событию. Этот режим можно выключить, но иногда он полезен. Например, при получении SMS, модем посылает (без запроса) хосту что-то типа «+CMTI: ….». Причем, это может случится в любой момент, даже тогда когда мы ожидаем ответ. Тобиш, может возникнуть ситуация, когда мы послали АТ, а в ответ получили
+CMTI: …
ОК
В этом случае хеш не сойдется, хотя ОК мы получили.
Но идея интересная, спасибо за статью.
Вообще, у модуля есть команда ATV Set result code format mode, которая позволяет перевести его в режим ответа Numeric format и тогда вместо ОК будет приходить 0, вместо CONNECT — 1, вместо RING — 2 и т.д. Их гораздо проще отлавливать и парсить.
а причем тут сообщение? как я понял речь идет о том как ответы типа ОК, ERROR и пр. отличить друг от друга используя минимум ресурсов хоста. Может я не так понял.
Всё верно, режим, конечно, полезный. И вполне подходит к устройству.
Я имел ввиду, если, например, понадобится распознать сообщение или номер входящего звонка. (приведённая в топе программа не делает этого)
Я имел ввиду, если, например, понадобится распознать сообщение или номер входящего звонка. (приведённая в топе программа не делает этого)
Всмысле отловить сообщение, текст которого (вернее его хеш) заложен в программе? Или номер звонящего сравнить с разрешенным номером? Если да — то конечно что-то в этом есть, но XOR наверно мало, хотя бы двухбайтовую контрольную сумму считать нужно. А так великовата вероятность совпадения)). Это варианты ответа модуля можно все посчитать и увидеть что XOR у них разный, с неизвестным заранее текстом такое может и не прокатить.
Странная это идея — команды ловить управляющему контроллеру. Ведь он их сам и шлёт.
Ответы надо обрабатывать, а не свои же команды. И не xor-ом уж точно.
Ответы надо обрабатывать, а не свои же команды. И не xor-ом уж точно.
Он не свои команды получает, а именно те ответы, что с модуля приходят. К примеру, получено сообщение или получен входящий звонок. Или ответы на команды — OK или ERROR.
Можно не xor'ом. Тогда чем? Сравнивать все входящие команды с эталонными? Много памяти программы уйдёт. Может подскажешь другой алгоритм?
Можно не xor'ом. Тогда чем? Сравнивать все входящие команды с эталонными? Много памяти программы уйдёт. Может подскажешь другой алгоритм?
Он не свои команды получает, а именно те ответы, что с модуля приходят.А, понял…
Можно не xor'ом.xor ну никак не годится.
Тогда чемНу допустим на команду должно прийти несколько ответов — OK, ERROR, NO CARRIER. Тогда с этими строками и сравнивать.
Много памяти программы уйдёт.Для SMS/GPRS/CSD и прочего и 1кБ вроде как не ушло у меня в программе. Хотя в m16 процент заметный. Но оно и понятно что такие вещи других МК требуют. У меня раньше была mega128, сейчас xmega192 с 16кБ ОЗУ.
у меня на самом устройстве mega8 стоит. Это ещё меньше памяти. Сейчас у меня где-то 2 кб программы — это ещё без функции получения смс сообщений.
Полностью согласен, что лучше всё-таки сравнивать с записанными в память. Но чем xor тут плох? Я пересчитал больше 20 разных команд и ни разу не совпал по xor сумме. Вдобавок я проверяю длинну команды.
Полностью согласен, что лучше всё-таки сравнивать с записанными в память. Но чем xor тут плох? Я пересчитал больше 20 разных команд и ни разу не совпал по xor сумме. Вдобавок я проверяю длинну команды.
Комментарии (18)
RSS свернуть / развернуть