|
|
  |
Принцип построения консоли управления устройством, Поделитесь опытом кто как делает :) |
|
|
|
Aug 12 2009, 08:43
|

Профессионал
    
Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409

|
Стоит задача разаработать устройство которое должно иметь возможность управляться через UART. Думаю встроить отладочную консоль чтобы можно было посылать в устройство комманды и получать ответы. Комманды в виде одиночных символов реализовал. Теперь хочу расширить функциональность консоли и реализовать длинные команды (наподобие АТ-комманд). Причём хочется сделать аппаратно-независимую консоль чтобы можно было переносить из проекта в проект меняя только низкоуровневые функции приёма/отправки символовов через UART. Подскажите кто как делает подобные консоли. Интересует прежде всего как осуществляется поиск комманд в потоке принимаемых символов (выделение слов длиной 2 и более символа)? Какие стандартные библиотеки можно использовать? Сейчас реализована входная FIFO-UART которая заполняется в прерываниях и функция считывания символа из FIFO которая возвращает -1 если нет данных или принятый символ. Одиночные символы отлавливать легко (считал - обработал), два - уже сложнее но пока реализую устанавливая флаги. Как отловить три и более символа - вот тут нужны идеи
|
|
|
|
|
Aug 12 2009, 10:26
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Собираете словарь команд (ASCIIZ), например Код const char cmd0[] ="READ"; const char cmd1[] ="ERASE"; const char cmd2[] ="WRITE"; const char *command_set[3] = {&cmd0,&cmd1,&cmd2}; Затем, поочередно сравниваете принятый токен со строками словаря, до тех пор, пока следующий символ из словаря не будет равен \0. Дальше - все зависит от синтаксиса - допускаете ли Вы у себя разделители токенов или нет... Если разделители необязательны - возвращаете индекс, соответствующий command_set[j] указателю на распознанную команду, и текущую позицию в буфере, подразумевающую дальнейший разбор аргументов. Далее - switch() и тд произвольной сложности. Игнорирование регистра символа делаете?
|
|
|
|
|
Aug 12 2009, 11:24
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(_Pasha @ Aug 12 2009, 13:26)  Собираете словарь команд (ASCIIZ), например С размахом  Код int command( struct Cmd *cmd ) { //--------------------------------------------------------------------------- case 'sst ': ... break;
case 'psst': .... break;
//--- Dummy arguments print ----------- case 'aa ': printf( "\nargc=%i ls='%s'\r", cmd->argc, cmd->command_line ); for( int i=0; i<= cmd->argc; i++ ) printf( "argn[%i]=%08lX\r", i, cmd->argn[i] ); break; Команды - по первым четырем (для 32битника) символам. Стандартная разборка на аргументы делается заранее.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Aug 12 2009, 15:44
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(Goodefine @ Aug 12 2009, 17:31)  Зато обеспечивают детерминированное поведение системы, при значительном потоке символов... Сказано мощно. Это что, длинные команды как средство нейтрализации ошибок реализации протокола?  Автору. Передерите какой-нить стандартный протокол, слишком много аспектов существуют в протоколах.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Aug 12 2009, 17:21
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(Goodefine @ Aug 12 2009, 18:50)  В качестве контрпримера можно рассмотреть поведение управляемого объекта, с односимвольным набором команд, на вход которого постоянно что-то приходит. Без ошибок. При прочих равных, разумеется... И что, как контрпример себя ведет? Использую односимвольные наборы команд в обе стороны. Никаких проблем. Очень удобно - в одну сторону идут коды нажатых клавиш, а в другую - коды символов, подлежащих отображению. Полный дуплекс, физический и логический. Если русский язык не нужен, коды управления дисплеем помещаются в правую сторону ASCII без проблем. Тут главное - не пытаться придумывать что-то посредине между "простым" протоколом и "нормальным" протоколом, в результате получится зависающая хрень.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Aug 12 2009, 17:49
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Dog Pawlowa @ Aug 12 2009, 23:21)  Очень удобно - в одну сторону идут коды нажатых клавиш, а в другую - коды символов, подлежащих отображению. Полный дуплекс, физический и логический. Но это вроде немного не то, что хотел топикстартер? Я лично применяю более-менее полноценную консоль, типа такого: CODE // обработчик команды. typedef int (* CmdHandler)(char * args);
// структура с информацией о команде typedef struct { char * command_name; // имя CmdHandler handler; // обработчик } Command;
const Command CommandTable[] = { {"GET", GetCommandHandler}, {"SET", SetCommandHandler}, {"TERM", TermHandler}, ... };
int parse_command_line(char * buf) { char *lt; char *token; int i;
token = GetToken(buf, <); if (!token) return FALSE;
for (i=0; i<sizeof(CommandTable) / sizeof(CommandTable[0]); i++) if (!strcmp(CommandTable[i].command_name, token)) { if (!CommandTable[i].handler) return FALSE; return CommandTable[i].handler(lt); }
return FALSE; }
void interpreter(void) { char buf[81]; for (;;) { rs_puts("\r\n=>"); rs_gets(buf, 80); if (!parse_command_line(buf)) rs_puts("ERR"); } } Гораздо приятнее писать "SET PARAM1=23.4", чем "sA34", имея заодно возможность отредактировать строку при неверном вводе. Да и не накладно это особо.
Причина редактирования: Уменьшение видимого размера цитаты исходника.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Aug 12 2009, 19:06
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Dog Pawlowa @ Aug 13 2009, 00:27)  Если уж пошла речь о том, что приятнее, то я пришел к выводу, что лучше ПиСишное приложение, одно на все устройства, а из устройства может быть прочитано, какой физический смысл имеет PARAM1. Типа SNMP. Согласен, так тоже неплохо. Но есть, как мне кажется, пара аргументов против. Первый - универсальность. Линукс/виндовз/что-то там ещё, разные версии... Ну и можно банально забыть писишную программу  Терминалка же есть везде. И второй аргумент - в терминале можно не только конфигурировать устройство (SET/GET), но и выполнять что-то специфическое. Например, непрерывный вывод значения АЦП до нажатия любой кнопки, дрыгание заданной ножкой с заданной частотой. Интерактив, короче. Для таких применений сложно придумать универсальную программу для ПиСи, имхо.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Aug 12 2009, 19:32
|

Местный
  
Группа: Свой
Сообщений: 211
Регистрация: 6-08-07
Из: Приднестровье, Тирасполь
Пользователь №: 29 581

|
Цитата(Dog Pawlowa @ Aug 12 2009, 20:21)  И что, как контрпример себя ведет? Использую односимвольные наборы команд в обе стороны. Никаких проблем. Очень удобно - в одну сторону идут коды нажатых клавиш, а в другую - коды символов, подлежащих отображению... У Вас все просто: все что отдал - сканкод, все что принял - подлежит отображению... Я другое имел ввиду. К примеру возьмем дисплей с управляемой внешне подсветкой. Скажем, увеличить на одну градацию - символ "h", уменьшить - "l" . Остальное - отображаем. Как тогда контроллер отреагирует на на сообщение "hello world", если не использовать детерминацию ни по длине строки, ни по времени между поступлениями символов? Если же команды будут длинными, типа "light_background_down" / "light_background_up", то лишними проверками можно себя не утруждать - шанс, что потребуется отобразить именно такую строку, минимален. В этом суть моего первого замечания...
--------------------
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
|
|
|
|
|
Aug 13 2009, 02:18
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(Goodefine @ Aug 12 2009, 22:32)  В этом суть моего первого замечания... Понятно. Пожалуй, мы ушли далеко от обычного определения консоли. Если устройство выдает "промпт", а человек как-то реагирует в пределах предоставленных ему возможностей, то подобные коллизии исключаются.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Aug 13 2009, 05:02
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(zltigo @ Aug 12 2009, 14:24)  Код .... case 'sst ': ... case 'psst': .... case 'aa ': .... Команды - по первым четырем (для 32битника) символам. А все-таки, если у человека тупо буфер, нету манагера кучи для построения деревьев в ОЗУ - АВР средненький, короче, - так построить интерпретатор команд не получится! Цитата(AHTOXA @ Aug 12 2009, 22:06)  Ну и можно банально забыть писишную программу Интерактив, короче. Для таких применений сложно придумать универсальную программу для ПиСи, имхо. Ага, ОРС-серверы всякие не забывают, а тут-досада  Ничего сложного в универсальной программе - все действия реализуются через регистровую модель. В одном регистре - временной интервал выборки, в другом - адрес источника, в третьем - размер данных. К терминалке это уже не будет иметь отношение - это личное дело девайса - поддержит он данную функцию или нет. Цитата(Goodefine @ Aug 12 2009, 22:32)  Как тогда контроллер отреагирует на на сообщение "hello world" Это все бессмысленно без а) строгого разделения команд без аргументов, хотя бы пробелами. б) минимального синтаксического разбора команд с аргументами.
|
|
|
|
|
Aug 13 2009, 05:45
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(_Pasha @ Aug 13 2009, 11:02)  Ничего сложного в универсальной программе - все действия реализуются через регистровую модель. В одном регистре - временной интервал выборки, в другом - адрес источника, в третьем - размер данных. К терминалке это уже не будет иметь отношение - это личное дело девайса - поддержит он данную функцию или нет. ОРС-серверы - это для устройств, постоянно находящихся на связи. Тут действительно, забыть проблематично  Если же терминал применяется изредка, то шансы возрастают. Цитата(_Pasha @ Aug 13 2009, 11:02)  Ничего сложного в универсальной программе - все действия реализуются через регистровую модель. В одном регистре - временной интервал выборки, в другом - адрес источника, в третьем - размер данных. К терминалке это уже не будет иметь отношение - это личное дело девайса - поддержит он данную функцию или нет. Как реализовать через регистровую модель мини-DOS для флеш-карточки, например?
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Aug 13 2009, 06:41
|

Профессионал
    
Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409

|
Цитата(AHTOXA @ Aug 13 2009, 09:17)  Насколько я понял, автор темы хочет консоль управления/отладки... Именно. Мне нужна консоль в устройстве чтобы посылая определённые команды из терминала можно было изменить настройки, перепрошить устройство, считать текущие параметры и т.д. Ничего сверхумного и сверхсложного не нужно. Может быть я даже неправильно назвал тему - скорее нужно было назвать "как отловить из потока симмволов команды длиной более 2х символов". Но пару идей в дискуссии по тому как это сделать (ну и как собственно организовать консоль и систему команд) я уже приметел  Все спасибо за дисскуссию. Надеюсь она не остановится и ещё прозвучит ещё много идей  По поводу длинных команд - буквы F, E, L не так информативны как WFLASH, EFLASH, WLOCK и т.п. Сразу видно что я хочу записать флэш, стереть её, записать лок-биты. Вобщем небольшое увеличение длины команды позволяет сразу переходить на необходимую подпрограмму обработки. Будет и самому интуитивно понятнее и система команд значительно расширяется.
Сообщение отредактировал mempfis_ - Aug 13 2009, 06:46
|
|
|
|
|
Aug 13 2009, 07:02
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(AHTOXA @ Aug 13 2009, 09:17)  Насколько я понял, автор темы хочет консоль управления/отладки. Тогда здесь регистровая модель(у нас с Вами болтовня именно с нее началась) - никаким макаком. Но, вернемся к периодическому опросу АЦП или чего другого. Очевидно, что хотя бы период опроса может быть регулируемым. Цитата(mempfis_ @ Aug 13 2009, 09:41)  Именно. Мне нужна консоль ... Будет и самому интуитивно понятнее и система команд значительно расширяется. И обязательная команда help (лучше "?")для всех приборов. А еще страшнее - контекстная помощь, например help WFLASH или ?WFLASH - как по мне, то лучше в постфиксной форме Код WFLASH ? . Объясню: "?" может рассматриваться как стандартный аргумент команды, минимум писанины. Дополнительные хинты уже зависят от принятой команды. И еще раз скажу: просто команды - это уже обговорили. А как же быть с аргументами?  Они ж тоже переменной длины!
|
|
|
|
|
Aug 13 2009, 07:23
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(_Pasha @ Aug 13 2009, 13:02)  Но, вернемся к периодическому опросу АЦП или чего другого. Очевидно, что хотя бы период опроса может быть регулируемым. Дык, какие проблемы? Аргументы (всё что после команды) передаются обработчику. Там может быть и период: >POOLADC 0 0 20 - опросить АЦП, число опросов 0 (до нажатия кнопы), канал 0, интервал 20 мс. Цитата(_Pasha) И обязательная команда help (лучше "?")для всех приборов. А еще страшнее - контекстная помощь, например help WFLASH или ?WFLASH - как по мне, то лучше в постфиксной форме Код WFLASH ? . +1, кроме постфиксной формы. Зачем делать это в каждой команде, проще централизованно  Типа : Код typedef struct { char *const command_name; // command name CmdHandler handler; // command handler char *const help_text; // command description }Command;
const Command CommandTable[] = { {"GET", GetCommandHandler, "get variable (VARS for list)"}, {"SET", SetCommandHandler, "set variable (VARS for list)"}, {"HELP", HelpHandler, "display this help"}, ... };
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Aug 13 2009, 09:30
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(_Pasha @ Aug 13 2009, 13:33)  Ага. Не увидел сразу. Ну, сразу и не было, я убрал, чтоб не загромождать идею  Цитата(_Pasha @ Aug 13 2009, 13:33)  ? без параметров вываливает список команд из CommandTable[] Ага. Плюс к этому есть такой же массив описаний переменных, с именем перемнной, ф-ями Get/Set, типом переменной границами и описанием (для хелпа). Я таскаю это хозяйство по всем проектам, очень помогает.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Aug 13 2009, 16:01
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(mempfis_ @ Aug 13 2009, 09:41)  "как отловить из потока симмволов команды длиной более 2х символов". Так в принципе, ничего нового не выдумано, насколько я понимаю. Всё тоже как и 30 лет назад. 1) если идёт сплошной поток, то префикс команды (Байтстафинг). Как вы уже отметили в модемах используется. Префикс AT (за малым исключением). То есть "hgjghjhati3" будет квалифицировано как команда "i3" - идентификация устройства. Префикс может быть любым, в том числе и односимвольным. Я обычно использую "Ъ".  Естественно префикс из простого потока данных изымается (заменяется на комбинацию), либо удваивается. Один из вариантов WAKE. 2) Применяется пауза (в том числе определённой длительности) перед началом команды. 3) Применяется комбинация 1 и 2. Есть ещё битстафинг (я применял), но он неподходит для UARTа.
|
|
|
|
|
Aug 14 2009, 06:54
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(rezident @ Aug 13 2009, 22:03)  В дополнение ко всему хотел бы заметить, что конфигурирование устройства и его отладка это немного разные вещи. Конфигуратор на основе текстового меню легко делается. И совершенно без разницы куда выводится это меню: на экран устройства или в UART и соответственно откуда управляется: с клавы устройства или опять же из UART. +1 Кроме того, я бы не вставлял в рабочую прогу отладочные режимы. Отладка предполагает свободный доступ к железу. Для рабочего режима это, на мой взгляд, недопустимо. Фактически - это даст возможность пользователю убить работоспособность изделия. Делали один проект, и программист, который писал головную прогу (на IBM) требовал, чтобы я предоставил прямой доступ к памяти устройства (под MODBUS). Я наотрез отказался. Их мотивация - что будет всё отлажено и PC прога не будет вредить устр-ву. За то это даст более широкие возможности, в том числе и по отладке. Моя мотивация - кто будет нести ответственность за работоспособность моего железа?
|
|
|
|
|
Aug 14 2009, 17:02
|
Местный
  
Группа: Участник
Сообщений: 421
Регистрация: 2-01-08
Пользователь №: 33 778

|
Обычно использую бинарный протокол для отладки, но если надо текстовую консоль, скопировал бы схему работы с юниксовых шелл+терминал, что то лучше придумать сложно. Код u8 uart_read(); void uart_write(u8 val);
//...
do { c = uart_read(); buff[i++]; if (c == CR) { uart_write('\n'); parse_line(buff); i = 0; continue; } if (c == BACKSPACE) { uart_write('\b'); --i; continue; } uart_write(c); } while(1); Конечно тут мало проверок, и можно удалять только последний символ, это упрощенный пример.
|
|
|
|
|
Aug 15 2009, 15:52
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата Принцип построения консоли управления устройством 1. Байт парсер, выделяющий строки команд и управляющие символы из потока. Вызывается или непосредственно из RX INT или из обработчика "OnRead" TCP сокета. 2. Задача поиска обработчика для выделенной из потока строки. (по табличке, в точности так как привел AHTOXA). 3. Обработчик каждой команды. 4. Общий парсер параметров, который пытается интерпретировать строку параметров всеми известными ему форматами: как целое число, как float-point число, как IP addres, mac-address, дата, время, строка и т.д и т.п.. 5. Ну и контекстный Help. (вызываемый в обработчике каждой команды, если команда вызвана с параметром "?" или "--help").
|
|
|
|
|
Aug 20 2009, 18:52
|
Местный
  
Группа: Свой
Сообщений: 262
Регистрация: 18-02-05
Из: SPb
Пользователь №: 2 743

|
Цитата(zltigo @ Aug 12 2009, 15:24)  С размахом Код int command( struct Cmd *cmd ) { //--------------------------------------------------------------------------- case 'sst ': ... break; Команды - по первым четырем (для 32битника) символам. Стандартная разборка на аргументы делается заранее. А не трудно показать начало ветвления (switch). Что за тип Вы ему даете? У меня как-то не срабатывает подобное, хотя пытался такое изобразить не раз. Компилятор варнингует, что нельзя сравнивать мультичарестерный чар (multi-character character constant). И везде встречал побайтный анализ, что приводит к огромным ветвлениям switch/case.
|
|
|
|
|
Aug 20 2009, 19:23
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(AlexMad @ Aug 20 2009, 20:52)  А не трудно показать начало ветвления (switch). Что за тип Вы ему даете? Код struct Cmd{ // Command unsigned long cmdcode; ....... };
switch( cmd->cmdcode ) {
..... Цитата У меня как-то не срабатывает подобное, хотя пытался такое изобразить не раз. Компилятор варнингует, что нельзя сравнивать мультичарестерный чар (multi-character character constant). Естественно, что это исходник, как уже писал, для 32bit. Для 16bit, соответственно только пара символов, ну а с 8bit  Если какой-то компилятор warning, выдает, что бывает - надо отключить для этого куска через #pragma Предупреждать он, конечно, может, но работать, как приказано, обязан.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Aug 25 2009, 11:56
|

Участник

Группа: Участник
Сообщений: 52
Регистрация: 6-05-09
Из: Москва
Пользователь №: 48 733

|
Цитата(mempfis_ @ Aug 12 2009, 12:43)  Сейчас реализована входная FIFO-UART которая заполняется в прерываниях и функция считывания символа из FIFO которая возвращает -1 если нет данных или принятый символ. Одиночные символы отлавливать легко (считал - обработал), два - уже сложнее но пока реализую устанавливая флаги. Как отловить три и более символа - вот тут нужны идеи  А расскажите пожалуйста теорию про FIFO (я на асме пишу под Мегу8). Не понимаю самого принципа. Форма команд моему девайсу: <префикс начала><команда> [<параметры>]<CRLF> Выделил какой-то буфер, думаю тупо заполнять его поступающими данными из UART, инкрементируя указатель... и не могу сообразить, с какого момента начать его обрабатывать? Вижу варианты: 1. Буфер переполнен - выдаём ошибку 2. Нашли CRLF - парсим буфер, обрабатываем команду 3. Какой-то тайм-аут передачи - буфер отбасывается, ошибка 4. Неверная команда - выдаём ошибку. Обрабатывать думаю - искать старт команды в буфере (три байта), и написать что-то типа strcmp. Мыслю верно? Смущает, как определить то, что передача данных закончилась... Если кому интересно, нашёл "для тупых" тут статейку. Идеи разжёваны идаже примеры есть http://www.atmel.ru/Articles/Atmel12.htm
Причина редактирования: Излишнее цитирование.
|
|
|
|
|
Aug 25 2009, 12:25
|

Участник

Группа: Участник
Сообщений: 52
Регистрация: 6-05-09
Из: Москва
Пользователь №: 48 733

|
2_Pasha Кхм, я путаюсь уровнем ниже. Как принимаемое пихать в буфер и что делать, если будут слать следующую команду,пока обрабатывается текущая. Думаю отключать UART на приём(?). То-есть есть отдельно принималка строки и есть отдельно парсер. Вот с принималкой строки затыки следующие: 0. Есть область памяти и счётчик адреса = буфер. Так? 1.1. По прерыванию пихаем байт, инкрементируем счётчик, проверяем переполнение счётчика, выдаём ошибки, если надо (переполнен буфер). 1.2. После принятия очередного байта проверяем два последних на CRLF. Если равны = отключаем приём, передаём буфер парсеру. 2. Парсер уже сам разбирается - команда/ошибка, выдаёт ответ или выполняет её, в конце разрешая приём.
Есть ли тут какие-то подводные камни? Первый вижу сам - пока обрабатываем что-то, теряем посылаемое в этот момент. Это я закладываю в протокол: если не пришёл ответ от команды, повторить посылку.
И ещё непонятно с таймаутом - как его посчитать? Выходит что-то типа ватчдога? Или вообще не делать, а просто ждать CRLF?
Видел модуль, там типа терминала через RS-232 написано, так, вроде там таймаута нет никакого. Просто строка кончается CRLF.
|
|
|
|
|
Aug 25 2009, 12:58
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(C.S. @ Aug 25 2009, 15:25)  Первый вижу сам - пока обрабатываем что-то, теряем посылаемое в этот момент. Это я закладываю в протокол: если не пришёл ответ от команды, повторить посылку. Тогда FIFO (пардон за Си): Код volatile char buffer[BUFSIZE]; volatile unsigned char pos_rd, pos_wr;
// прерывание UART { char tmp=UDR; buffer[pos_wr++] = tmp; if(pos_wr >= BUFSIZE ) pos_wr = 0; }
// опр числа принятых символов // условие кгда нет символов одно - это pos_wr == pos_rd unsigned char sym_pending(void) { return (pos_wr >= pos_rd) ? (pos_wr - pos_rd) : ( pos_wr + BUFSIZE - pos_rd); } // чтение из буфера char sym_read(void) { char tmp = buffer[pos_rd++]; if(pos_rd >= BUFSIZE) pos_rd = 0; return tmp; } Цитата И ещё непонятно с таймаутом - как его посчитать? Выходит что-то типа ватчдога? Для начала определитесь, для чего именно Вам таймаут. Он может быть как на время между принятыми командами, так и на время между символами. ЗЫ для определения переполнения буфера можно параллельно ввести счетчик принятых байт. При чтении - декрементировать его.
|
|
|
|
|
Aug 25 2009, 13:03
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(C.S. @ Aug 25 2009, 18:25)  Как принимаемое пихать в буфер и что делать, если будут слать следующую команду,пока обрабатывается текущая. Думаю отключать UART на приём(?). Во-первых, кто это будет так плохо себя вести?  Во-вторых, если такое всё же возможно, можно сделать два буфера на приём (и соответственно два счётчика), один принимается (в прерывании), другой обрабатывается (парсером). И флажок, номер_готового_буфера (0/1). Цитата И ещё непонятно с таймаутом - как его посчитать? Выходит что-то типа ватчдога? На да. При каждом принятом символе некий счётчик устанавливается в заданное значение, а в прерывании таймера - декрементируется. Как стал нулём, так тогось, тайм-аут. Только вот что делать по тайм-ауту? Цитата Или вообще не делать, а просто ждать CRLF? Да, так гораздо проще. Единственно, когда тайм-аут нужен, это в том случае, если при входе в консоль устройство перестаёт работать в штатном режиме. Тогда его минут через пять после ухода забывчивого наладчика таки желательно вернуть в рабочее состояние  Цитата Видел модуль, там типа терминала через RS-232 написано, так, вроде там таймаута нет никакого. Просто строка кончается CRLF. И это правильно. Вдруг человек просто задумался?
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Aug 25 2009, 13:17
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(C.S. @ Aug 25 2009, 16:02)  А sym_pending у Вас как вызывается? Где-то в цикле или по таймеру? Конечно, где-то в основном процессе. Вначале узнаем, сколько символов принято, а потом можем еще и покапризничать  - надо обрабатывать или нет. Может, есть другие более важные задачи. Затем - читаем посимвольно. Разворачиваем это все в другой буфер (к сожалению). и парсим от замеченного начала и до замеченного ВКПС. ЗЫ FIFO_flush делается как присвоение pos_wr = pos_rd. позаботившись об атомарности . Если надо, конечно.
|
|
|
|
|
Aug 25 2009, 13:26
|

Участник

Группа: Участник
Сообщений: 52
Регистрация: 6-05-09
Из: Москва
Пользователь №: 48 733

|
Цитата Разворачиваем это все в другой буфер (к сожалению). и парсим от замеченного начала и до замеченного ВКПС Аааа! А я-то хотел обрабатывать в том же, куда принял. Тогда можно рыбу накатать и проверить. По таймауту - чистить буфер. Не успели передать строку целиком - значит пришёл мусор. Оставлю как опцию. Насчёт плохо себя ведущих - вообще, потом думаю о каком-то протоколе, где несколько мастеров и несколько подчинённых. Хотел, чтобы они слали друг другу инфу в формате АдресПолучателя АдресОтправителя Инфа. Выходит, что сама магистраль может быть забита чем угодно, и в этом случае просто будет несколько попыток достучаться до девайса (передаёт и принимает всегда одна пара). Но это пока задумки и вопросы для другой темы. Мне б пока с компютера научиться управлять и команды парсить...
|
|
|
|
|
Aug 25 2009, 13:36
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(C.S. @ Aug 25 2009, 16:26)  Аааа! А я-то хотел обрабатывать в том же, куда принял. FIFO ведь не самоцель, а средство разгрузки основного процесса от тяжелых прерываний. Оно может быть каких-нить компромиссных размеров, скажем, 8 байт. Учитывая двойную буферизацию UDR, может хватить. Да и приемный буфер может быть динамическим. А если "рыбу накатать" - у Вас будет эдакий бегемот в ОЗУ сидеть статически, чтоб не прозевать команду, да еще и там же ее парсить... не думаю, что сие полезно. ЗЫ: это ж ответ от девайса пойдет только после приема команды? Тогда у Вас большой буфер для работы на RX/TX и ФИФО на прием.
|
|
|
|
|
Aug 25 2009, 13:54
|

Участник

Группа: Участник
Сообщений: 52
Регистрация: 6-05-09
Из: Москва
Пользователь №: 48 733

|
Цитата это ж ответ от девайса пойдет только после приема команды? Тогда у Вас большой буфер для работы на RX/TX и ФИФО на прием Эммм... А как иначе (про ответ)? Если я девайсу шлю например команду SETBR 1,100 - вот он её должен распарсить, выполнить и ответить OK? Так ведь и выходит - причём, обработка, ответ? Я по 32 байта выделил на буферы...
|
|
|
|
|
Aug 25 2009, 14:36
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(C.S. @ Aug 25 2009, 17:17)  Так а если надо будет вернуть чего-то более разумное в ответ, нежели ОК? Тогдабудет ОК <данные> 1. Принимаем команду в буфер 2. Парсим ее в буфере 3. Все аргументы - преобразуются и хранятся в локальных переменных. 4. Выполняются действия с полученным набором аргументов. 5. Ответ отправляется в тот же буфер. Ставится счетчик TxCNT = длине отправляемой строки 6. Разрешаем UDRE. (в нем отправляем и как только TxCNT ==0 запрещаем прерывание) 7. Ждем пока UDRE не станет ==0 За это время FIFO - если может заполниться - то оставьте его 32 байта, если низзя принимать команду - оставляйте меньше. Если новая команда не может поступить ранее, чем отдан ответ, этот факт фиксируется с помощью переполнения ФИФО, и далее - ответ, типа "?"
|
|
|
|
|
Aug 27 2009, 09:33
|

Участник

Группа: Участник
Сообщений: 52
Регистрация: 6-05-09
Из: Москва
Пользователь №: 48 733

|
Парсинг команд сделал. Использовал побайтовое сравненпие буфера в цикле, одновременно считая побайтово команду из памяти программ. Команды закодировал так: Код UARTCmdListTable: .DB 8, /*ОБЩЕЕ ЧИСЛО КОМАНД в ШТУКАХ!*/ \ 2, "UP", /*01: Кнопка "Вверх"*/ \ 3, "DWN", /*02: Кнопка "Вниз"*/ \ 4, "LAMP", /*03: Кнопка "Вкл-Выкл" (ON|OFF)*/ \ Соответственно - считаем числа, грузим в счётчики - и циклом крутимся. Нашли - из таблицы Код UARTCmdProcTable: .DW UARTCommand_UP;01 .DW UARTCommand_DWN;02 .DW UARTCommand_LAMP;03 выбираем нужный адрес и ICALL. Работает. Получилось, видимо,также как на СИ с массивом. Команда получает позицию её аргументов в буфере и делает с ними что хочет.
Сообщение отредактировал C.S. - Aug 27 2009, 09:34
|
|
|
|
|
Aug 27 2009, 14:19
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(C.S. @ Aug 27 2009, 12:33)  Команды закодировал так: По идее, ОБЩЕЕ ЧИСЛО КОМАНД в ШТУКАХ! можно определить директивой equ. Во-вторых, в своем первом посте (на который zltigo сказал "с размахом") я не договорил, что если имеется ситуация, когда для нескольких команд есть одинаковый набор аргументов (одинаковое кол-во и тип и даже диапазон иногда) - то зачем плодить сущности, можно сам парсинг утрясти/утоптать. Т.е аргументы уже будут считаны, преобразованы и уложены куда надо, а потом по индексу - вызываем нужную функцию. Разумеется, это не принципиально, так, не более, чем свое имхо.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|