Федя
Гость
|
|
« : 13-10-2004 07:54 » |
|
Постановка задачи --------------------------------- Нужно написать программу под ОС Windows 2000, которая реализует взаимодействие с устройством через последовательный порт (RS-232) на скорости 4800 бод. Компьютер должен принимать поток байт, если в потоке приходят 2 определенных байта, то нужно за 65 миллисекунд от момента их приема послать заранее подготовленных 20 байт. Управление потоком и т.п. не используется, устройство никак не контролирует приём байт компьютером, компьютер никак не контролирует устройство. Проблема заключается в том, чтобы уложиться в эти 65 миллисекунд (это предельное значение), а желательно меньше 20-40 миллисекунд. По моей оценке* на основе тестового приложения это невозможно сделать в рамках пользовательского Win32 приложения.
Вопросы --------------------------------- Возможно ли решить эту задачу путём написания драйвера последовательного порта (или внесением модификации в существующий драйвер serial.sys, если я правильно понял пример из DDK под Windows 2000 и есть этот драйвер)? По моей оценке на основе исходников serial.sys проанализировать получение 2 байт можно непосредственно в обработчике прерывания (функция SerialISR()), остается инициировать из обработчика прерываний запись 20 байт в порт. Возможно ли сделать это в указанных временных рамках и если да, то по какой схеме это сделать? Можно реализовать задачу не через собственный драйвер, а обращаясь к существующему драйверу** из режима ядра используя Irp запросы? Может быть такое, что задачу можно реализовать из пользовательского приложения? Какую информацию и где можно посмотреть по данным вопросам?
Примечания --------------------------------- * Оценка времени получена следующим образом. Время измерялось функцией GetTickCount(). Написано 2 тестовые программы (используются вызовы WinAPI), которые взаимодействуют с друг другом через последовательный порт (2 компьютера соединены через нуль-модемный кабель). Первая (программа А) посылает 2 байта и принимает 20 байт, вторая (программа B) ждет приёма 2 байт и посылает 20 байт. Если в программе А сделать задержку (Sleep()) меньше 120 мс, то будет приходить меньше 20 байт в рамках одной операции чтения FileRead(). В программе B временной интервал от наступления выполнения потока после задержки функцией WaitCommEvent() до завершения операции WriteFile() время скачет, т.е. может быть 0 мс, а может быть 30-40 мс. Из всего этого я сделал вывод, что гарантированно реализовать указанную задачу в рамках пользовательского приложения (с учетом того, что нужен запас времени) невозможно. ** Как я понял, одна из проблем это буферизация порта. Если я правильно понял из пользовательского приложения можно только рекомендовать функцией SetupComm() размеры буферов (кажется драйвера, а не порта), но отключить её нельзя. Если я правильно понял драйвер анализирует микросхему и включает буферизацию вроде как особо никого не справшивая.
|
|
|
Записан
|
|
|
|
MOPO3
Ай да дэдушка! Вах...
Команда клуба
Offline
Пол:
Холадна аднака!
|
|
« Ответ #1 : 13-10-2004 08:06 » |
|
Ну я не спец в дровах, но думаю что можно реализовать это посредством драйвера-фильтра над ком портом. Данные пойдут сначала через фильтр, а потом фильтр отправит их вниз драйверу ком порта, но это моё ИМХО. Есть на сайте нашем в разделе "файлы" книга по дровам Вальтера Оней.
|
|
|
Записан
|
MCP, MCAD, MCTS:Win, MCTS:Web
|
|
|
Серж
Гость
|
|
« Ответ #2 : 13-10-2004 10:03 » |
|
Федя, по-моему, никакой драйвер не нужен. Читать данные из порта нужно асинхронно, сколько придет, столько и считывать и анализировать получение необходимых двух, а на отсылку 20 байт при скорости 4800 бод у тебя есть запас ~25 мс (40 мс отнимает железо), это же очень много. Если машина быстродействующая, то его за глаза хватит для переключения потоков и прочих системных дел. Если же его не хватит, в конце концов задай максимальный приоритет своему процессу перед вызовом WriteFile, а потом после записи верни нормальный.
|
|
|
Записан
|
|
|
|
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии
Offline
Пол:
Бодрый птах
|
|
« Ответ #3 : 13-10-2004 11:18 » |
|
Вообще то есть функция SetCommTimeouts где можно очень четко выставить все задержки которые будут идти в драйвере. Сам по себе драйвер тебе писать ИМХО совершенно не нужно...
Кроме того, из задания не ясно какие 20 байт тебе надо отправить...
Ведь они могут быть подготовлены заранее. Если я правильно понял можно сделать такую структуру.
Например:
1. Создается окно аппликации.
2. Инициализируются ВСЕ возможные наборы данных в виде 20-байтных буферов. (В качестве вопроса, как они зависят от 2 принятых байт и зависят ли вообще. Или они всегда одни и теже???)
3. ЗАпускается отдельный поток (_beginthreadex() ) который получает повышенный приоритет и ставится в суспенд. (спящий режим).
4. ЗАпускается еще оджин поток (читающий данные асинхронно и ждущий приходящие байты на функции WaitCommEvent). (Примеры кода как его организовать тут на форуме есть).
5. Как только читающий поток принял 2 нужных байта он выставляет сообщение на отсылку для первого потока, который сидит в спящем режиме. При нужном приоритете (или/и вообще при отмене переключения контекста с одного процесса на другой в момент передачи 20 байт буфера) отправляются нужные данные и все восстанавливается в исходную позицию на ожидание очередных 2 байт инфы...
Маленькое пояснение. В коде на С++ для винды можно выставить блок кода в процессе(потоке), когда пока он выполняется не будет винда обращать внимание на остальные процессы и потоки которые могли бы помешать текущему, запросив время у процессора на обслуживание. Т.е. пока нужный код не выполнется и не отключит блокировку, будет выполнятся только этот поток и сисемные процессы, без которых невозможно обойтись...
Как это сделать я счас навскидку не помню, но этот метод описан у Рихтера в книге, которая лежит у нас на сайте на русском в двух видах...
Удачи...
|
|
|
Записан
|
А птичку нашу прошу не обижать!!!
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #5 : 14-10-2004 16:28 » |
|
В коде на С++ для винды можно выставить блок кода в процессе(потоке), когда пока он выполняется не будет винда обращать внимание на остальные процессы и потоки которые могли бы помешать текущему, запросив время у процессора на обслуживание.
так это критическая секция - делаем #include "Afxmt.h" CCriticalSection m_crisec; f() { ... ... m_crisec.Lock(); //сюда больше никто не пролезет m_crisec.Unlock(); ... ... }
|
|
|
Записан
|
|
|
|
Серж
Гость
|
|
« Ответ #6 : 15-10-2004 06:34 » |
|
Федя, не со всем могу согласиться в исчерпывающем ответе Leo, совсем не обязательно принимать по одному байту, достаточно ожидать в WaitCommEvent событие EV_RXCHAR и принимать, сколько придет, при этом необязательно пользоваться функциями WriteFileEx и ReadFileEx, достаточно и обычных WriteFile и ReadFile. Конечно, если WriteFile будет находиться в одном потоке с приемом, то он должен быть асинхронным. И что совершенно отсутствует в ответе, так это то, что обязательно нужно отключить аппаратное FIFO, т.к. по умолчанию этот флаг включен. Это сброс определенного флага в DCB.
|
|
|
Записан
|
|
|
|
Rulik
Помогающий
Offline
|
|
« Ответ #7 : 02-11-2004 06:38 » |
|
Цитата:
В коде на С++ для винды можно выставить блок кода в процессе(потоке), когда пока он выполняется не будет винда обращать внимание на остальные процессы и потоки которые могли бы помешать текущему, запросив время у процессора на обслуживание.
так это критическая секция -
делаем
#include "Afxmt.h"
CCriticalSection m_crisec;
f() { ... ... m_crisec.Lock(); //сюда больше никто не пролезет m_crisec.Unlock(); ... ... }
Не соглашусь с этим. Критическая секция защищает ресурс, а не выделяет тебе процессор эксклюзивно. Тебя в любой момент могут прервать другие процессы.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #8 : 02-11-2004 10:15 » |
|
Rulik, да ты прав. Я не имел в виду захват всего процессора, невнимательно прочитал выше
|
|
|
Записан
|
|
|
|
|