Перейти к содержанию
    

Как обрабатывать сообщение REMOTE IP:

В моей программе все сообщения обрабатываются по установке флага получения нового сообщения. Анализатор флага работает так: получив CRLF (начало) - начинает ожидать CRLF(конец). Как только получен конец - флаг устанавливается. Обработчик сообщений, получив флаг, смотрит в буфер и обрабатывает пришедшее сообщение. После обработки флаг сбрасывается.

 

Алгоритм работает шикарно. Единственный его нюанс - нельзя работать с командами типа CLCC, которые возращают несколько строк и строки начиная со втрой не имеют CRLF (начало). Данные ответы имеют вид: CRLF<line1>CRLF<line2>CRLF...<lineN>CRLF OK CRLF. Проблема решается путём отказа от таких комманд - они мне не нужны.

 

Так вот с сообщением <CRLF REMOTE IP:> тоже наблюдается лажа.

Есть вариант выхода из сложившейся ситуации следующий: после соединения модулей посылать текст, который всегда будет заканчиватся на CRLF. Тогда сообщение будет иметь вид

<CRLF REMOTE IP: текст CRLF> - такое корректно обработается.

 

Но вот найти решение корректной обработки, когда приходит RING или ещё какое-то неожиданное сообщение - не могу. По сему спрашиваю здесь. Как обрабатывать REMOTE IP на тот случай, если влазит кто-то?

Изменено пользователем david_off

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В моей программе все сообщения обрабатываются по установке флага получения нового сообщения. Анализатор флага работает так: получив CRLF (начало) - начинает ожидать CRLF(конец). Как только получен конец - флаг устанавливается. Обработчик сообщений, получив флаг, смотрит в буфер и обрабатывает пришедшее сообщение. После обработки флаг сбрасывается.

 

Алгоритм работает шикарно. Единственный его нюанс - нельзя работать с командами типа CLCC, которые возращают несколько строк и строки начиная со втрой не имеют CRLF (начало). Данные ответы имеют вид: CRLF<line1>CRLF<line2>CRLF...<lineN>CRLF OK CRLF. Проблема решается путём отказа от таких комманд - они мне не нужны.

 

Так вот с сообщением <CRLF REMOTE IP:> тоже наблюдается лажа.

Есть вариант выхода из сложившейся ситуации следующий: после соединения модулей посылать текст, который всегда будет заканчиватся на CRLF. Тогда сообщение будет иметь вид

<CRLF REMOTE IP: текст CRLF> - такое корректно обработается.

 

Но вот найти решение корректной обработки, когда приходит RING или ещё какое-то неожиданное сообщение - не могу. По сему спрашиваю здесь. Как обрабатывать REMOTE IP на тот случай, если влазит кто-то?

ИМХО идея хорошая, но лучше таймаутами пользоваться. Тогда будет работать всегда и везде.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ИМХО идея хорошая, но лучше таймаутами пользоваться. Тогда будет работать всегда и везде.

 

абсолютно согласен!

получили CRLF и/или любой байт начинаем счтитать время (у меня 5-10мС при скорости 115200 ), получили следующий байт -сбросили счетчик и заново считаем... смогли досчитать до 10мС идем обрабатывать то что получили (время на свой вкус выставляй, ибо 10мС достаточно много, но для моих задач самое то что дохтор прописал)

Изменено пользователем _zag_

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня получилось что-то среднее. Алгоритм такой. Ожидаю первый символ (любой). Потом ожидается символ LF и если в течении 3 Мс нет нового символа, то считаем это признаком конца сообщения. Скорость установил 9600. Всё работает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня получилось что-то среднее. Алгоритм такой. Ожидаю первый символ (любой). Потом ожидается символ LF и если в течении 3 Мс нет нового символа, то считаем это признаком конца сообщения. Скорость установил 9600. Всё работает.

 

неплохой вариант, только я хочу уточнить. Если получен LF, а заним ещё что-то лезит, то это уже снимает проверку таймаута?

Если да, то тогда REMOTE IP, который не имеет вконце LF также не будет обработан как и в моём алгоритме.

Если нет, то тогда вообще зачем ждать LF - алгоритм становиться такой же как описан выше.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

неплохой вариант, только я хочу уточнить. Если получен LF, а заним ещё что-то лезит, то это уже снимает проверку таймаута?

 

я думаю не снимает проверку таймаута а обнуляет таймер.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

неплохой вариант, только я хочу уточнить. Если получен LF, а заним ещё что-то лезит, то это уже снимает проверку таймаута?

Восстанавливается его начальное значение.

Если да, то тогда REMOTE IP, который не имеет вконце LF также не будет обработан как и в моём алгоритме.

Не знаю на счёт "REMOTE IP", в ответах на применяемые мною команды, "LF" есть всегда. Исключение только "AT+CPOWD=1". В этом случае, проверяю полный ответ "POWER DOWN".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Думал, думал и надумал...

 

По суте у меня выбор между двумя вариантами: моим и вариант с таймаутами.

У моего есть минус, что он не ловит сообщения, которые не заканчиваются на CRLF

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

 

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

 

Для тех кто делал тайм-ауты наверно будет понятней сказать так. Буду ждать тайм-аута, но по мере поступления данных, буду проверять а нет ли внутри потока уже готового для обработки сообщения.

Изменено пользователем david_off

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гость @Ark
Думал, думал и надумал...

 

По суте у меня выбор между двумя вариантами: моим и вариант с таймаутами.

У моего есть минус, что он не ловит сообщения, которые не заканчиваются на CRLF

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

 

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

 

Для тех кто делал тайм-ауты наверно будет понятней сказать так. Буду ждать тайм-аута, но по мере поступления данных, буду проверять а нет ли внутри потока уже готового для обработки сообщения.

 

Предложу Вам такой вариант обработки:

Начало сообщения определяется по приему символа LF. Символ CR можно проигнорировать (чтобы не путать с эхом команд). После приема LF, сразу, в процессе приема, нужно начинать распознавать сообщение (как - это Вам уже известно). Как только распознавание закончено - можно считать законченной и обработку сообщения - выставлять флаг и, возможно, код сообщения. Только, конечно, не тот код, что выдает модем, а собственный, присвоенный Вами данному сообщению. Далее весь ввод игнорируется до получения начала нового сообщения. Примерно так.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Предложу Вам такой вариант обработки:

Начало сообщения определяется по приему символа LF. Символ CR можно проигнорировать (чтобы не путать с эхом команд). После приема LF, сразу, в процессе приема, нужно начинать распознавать сообщение (как - это Вам уже известно). Как только распознавание закончено - можно считать законченной и обработку сообщения - выставлять флаг и, возможно, код сообщения. Только, конечно, не тот код, что выдает модем, а собственный, присвоенный Вами данному сообщению. Далее весь ввод игнорируется до получения начала нового сообщения. Примерно так.

 

Вы предлагаете после получения КАЖДОГО байта (когда уже был LF) пытаться распознать что у нас лежит в буфере приёма?! Мне кажется это будет нерационально расходовать процессорное время.

Получается для распознования элементарного ответа IP INITIAL на команду CIPSTATUS прийдётся запустить процедуру распознования содержимого более 10 раз. И это не просто процедура инкремента, а попытка найти в буфере какую-то строку, соответсвующую определённому шаблону. Шаблоны как я понимаю должны быть приготовлены для всех вариантов ответа.

Если же всё таки начинать распознавание ответа по признаку количества принятых байт, или ещё какому-то признаку, то это не меняет концептуально подход. Просто меняется признак, по которому начинается обработка. А смысл тот же. Ждём признак, а получив - идём на распознование.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гость @Ark
Вы предлагаете после получения КАЖДОГО байта (когда уже был LF) пытаться распознать что у нас лежит в буфере приёма?! Мне кажется это будет нерационально расходовать процессорное время.

Получается для распознования элементарного ответа IP INITIAL на команду CIPSTATUS прийдётся запустить процедуру распознования содержимого более 10 раз...

Здесь, конечно, вопрос реализации... Кто и как выполняет процедуру приема... Если это делает Ваша программа (процедура), причем, асинхронно - по прерыванию на прием символа, то почему бы не совместить прием с распознованием? Где Вы увидели усложнение? Сам подход Вам не привычен? Это возможно...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Здесь, конечно, вопрос реализации... Кто и как выполняет процедуру приема... Если это делает Ваша программа (процедура), причем, асинхронно - по прерыванию на прием символа, то почему бы не совместить прием с распознованием? Где Вы увидели усложнение? Сам подход Вам не привычен? Это возможно...

Наверно вы правы в том, что мы по разному понимаем реализацию распознования.

Я когда хочу что-то распознать, то начинаю сравнивать содержимое буфера с какой-то последовательностью байт (текстовые контстанты, соответсвующие разным вариантам ответа). Сравнение происходит в цикле до появления первого расхождения в байтах.

Так вот при моей реализации распознавания получается, что после приёма нового байта, приходится снова, с самого начала буфера, попытаться найти сходство с каким-то из возможных вариантов ответа.

А как вы распознаёте?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В моей программе все сообщения обрабатываются по установке флага получения нового сообщения. Анализатор флага работает так: получив CRLF (начало) - начинает ожидать CRLF(конец). Как только получен конец - флаг устанавливается. Обработчик сообщений, получив флаг, смотрит в буфер и обрабатывает пришедшее сообщение. После обработки флаг сбрасывается.

А я так и не пойму, как при таком алгоритме можно принимать не только сообщения модема, но еще и данные, которые сыпятся по GPRS-у (или по CSD). Я уже писал об этом тут рядом.

 

У меня основа алгоритма - кольцевой приемный буфер достаточного размера, чтобы разместить мах возможный пакет данных + несколько ответов модема, включая незапрашиваемые (unsolicited).

Признак получения данных - таймаут (дырка в данных) в ~50ms

После чего начинает работать обработчик по разбору всего, что пришло (причем в это время могут начинать валится новые данные, они попадут дальше в кольцевой буфер и будут обработаны позднее)

 

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

 

Тут имейте в виду, что ответы модема не только часто состоят из нескольких строчек, но и еще в разных условиях они могут менять свой порядок. :( Я как-то об этом писал.

 

Еще добавлю, что работать с модемом без операционки я не рискую, уж больно большой гемор B)

Правда, я сам полноценную ОС не использую, а применяю ее зачаток, где кроме главного цикла и прерываний есть еще один поток, в котором выполняются модемные процедуры и можно применять "ожидания событий", во время которых крутится главный цикл (ну и прерывания ессно) :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гость @Ark
Наверно вы правы в том, что мы по разному понимаем реализацию распознования.

Я когда хочу что-то распознать, то начинаю сравнивать содержимое буфера с какой-то последовательностью байт (текстовые контстанты, соответсвующие разным вариантам ответа). Сравнение происходит в цикле до появления первого расхождения в байтах.

Так вот при моей реализации распознавания получается, что после приёма нового байта, приходится снова, с самого начала буфера, попытаться найти сходство с каким-то из возможных вариантов ответа.

А как вы распознаёте?

А Вы не пробовали действовать методом исключения? Получив первый символ, после LF, Вы сразу "отсекаете" из набора возможных сообщений все, начинающиеся с другого символа. Очень часто, после приема первых двух-трех-четырех символов, остается только один возможный вариант ответа. С этого момента, уже можно считать сообщение принятым - выставить флаг, определить код сообщения и переключиться на ожидание следующего LF. C какой задержкой придет оставшаяся часть ответа и завершающий LF (или LF нового сообщения) - уже не будет иметь значения. Прием сообщения еще не окончен, но его обработка уже завершена...

P.S. Конечно, этот алгоритм не отменяет необходимость обработки таймаутов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А я так и не пойму, как при таком алгоритме можно принимать не только сообщения модема, но еще и данные, которые сыпятся по GPRS-у (или по CSD). Я уже писал об этом тут рядом.

Не знаю что у вас за железо, но я это реализую на mega128+SIM300C. Чего то для этой парочки не слышал про какую-то ось. Что касается алгоритма обработки, то мой алгоритм отлично работал, до появления сообщения REMOTE IP и данных GPRS. Ведь именно по этому я и создал эту тему.

Тут мне подсказали сделать таймауты. После их добавления наши с вами алгоритмы стали практически близнецами. Сами судите.

У меня тот же кольцевой буфер. Размер его выбран по такому же принципу. Байты ловятся в прерывании по приёму USART. Там же стоит логика, которая отслеживает появления LF по принципу StateMachine. Появилось LF дважды (пока таймер ещё не сработал) - значит в буфере уже лежит что-то осмысленное и можно это обработать. Для всех используемых мною команд можно это использовать. При появлении команд, которые в конце не имеют LF - обработку инициирует срабатывание таймера. После начала обработки, StateMachine возращается в начальное состояние, что бы начинать отлов новых ответов с "нового листа".

 

Сам же принцип обработки тоже очень похож.

Идём по буферу, сравниваем его содержимое с готовыми шаблонами ответа. Определённые ответы выставляют особые флаги. Например нашли OK - ставим OKfound = true. Если в буфере встречается ERROR или ему подобные, то ставиться ERRORfound=true. Если не нашли нужного шаблона - значит это просто ответ - для него есть флаг ANSWERfound.

Когда есть три таких флага, то после посылки любой комады нужно дождаться либо экстернного вываливания (ERRORfound) либо нужного сочетания ANSWERfound и OKfound.

После того как в буфере обработана инфа, он так же чистится, как и у вас. Перед посылкой новой команды, все флаги сбрасываются.

 

Может это и покажется диким, но у меня как ни странно всё класно работает. Проверял, тестил сутки - сбоев не было. Отработаны команды поднятия GPRS сервиса, инициализации и приёма звонков, посылки и приёма TCP сообщений.

Алгоритм обработки не падает при вклинивании UNSOLICITED сообщений типа RING или +CMTI. При появлении их появлении, они обрабатываеются, затем в буфере происходит откат указателей и программа продолжает корректное ожидание или обработку прерванной комады - все ок.

 

А Вы не пробовали действовать методом исключения? Получив первый символ, после LF, Вы сразу "отсекаете" из набора возможных сообщений все, начинающиеся с другого символа. Очень часто, после приема первых двух-трех-четырех символов, остается только один возможный вариант ответа. С этого момента, уже можно считать сообщение принятым - выставить флаг, определить код сообщения и переключиться на ожидание следующего LF. C какой задержкой придет оставшаяся часть ответа и завершающий LF (или LF нового сообщения) - уже не будет иметь значения. Прием сообщения еще не окончен, но его обработка уже завершена...

P.S. Конечно, этот алгоритм не отменяет необходимость обработки таймаутов.

 

Пробовал, но программа получается дико несмотрибельной. При достаточном количестве команд, появлеются дикие деревья вложенных IF, Количество внеших IF стремится к размеру алфавита, а внутренних при одинаковых первых символах, также прибаляет новые внутренние ветки.

 

В итоге скорость не на много повышается, а писать не удобно. Единственное, что я сделал для ускорения, это считаю длину полученной посылки во время приёма. Процесс сравнивания сначала пытается найти похожий шаблона ответа в ответах фиксированной длины (OK, ERROR, CONNECT ...), если же после попадания в раздел нужной длины соответвий не найдено, то идем в раздел ответов неопределённой длины (+IPD, REMOTE IP: ...). Если и там ответ не найден, то получен не шаблонный ответ, который будет обработан по индивидуальному алгоритму для каждой нестандартной комады.

 

Мне кажется более гуманно. Даём модему нормально высказаться, потом поднимаем RTS и спокойно обработать полученный ответ.

А в вашем алгоритме получается не намного быстрее, но вы тем самым не даёте модему свободно выражаться. Ведь наверняка, если обработка ответа идёт во время получения, то возможно, что контроллер будет не готов к продолжению приёма к моменту получения нового байта.

Изменено пользователем david_off

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...