Программирование LPT порта в Delphi, под Win9x, WinXP на основе драйвера LPTWDMIO
Нужно конечно согласится с тем, что программирование под ДОС, на языке Паскаль, достаточно не сложно и удобно, но время движется в перед и нужно осваивать новые подходы и методы в программировании. Интерфейсы написанные на языке высокого уровня, коим является Delphi, намного дружелюбнее и наглядней. В этой части статьи, я постараюсь подробней описать основные методы программирования LPT порта под WinXP. Сложного здесь ничего нет, тем более, если вы знакомы со средой программирования Delphi
Начиная с Delphi 2.0, в языке Object Pascal отсутствуют массивы Port и PortW, которые мы применяли ранее, программируя на Паскале. Предпринималось множество попыток обойти эту проблему, но большинство из них сводилось к тривиальным ассемблерным вставкам и использованию команд in и out. Это являлось достаточно эффективным решением при программировании для платформы Windows 9x, но не работало под управлением WinNT, так как там требовалось писать драйвер уровня ядра для получения возможности доступа к портам. Большинство нуждавшихся в доступе к портам ввода/вывода, испытывали необходимость обращаться к стандартным портам RS232 (Com) или IEEE 1284 (LPT). Найдя стандартные функции Win API, эти люди успокаивались и забывали о массиве Port, но те, кому требовалось работать с нестандартными устройствами, продолжали ломать свою голову об защиту WinNT, ибо писать драйвер не хотелось, да и мало кто умел. Но нашёлся добрый человек, который написал библиотеку функций для работы с портами процессора, и имя ему Фред Булбак (Fred Bulback). Библиотека называется io.dll. Я конечно не буду приводить исходный код данной библиотеки и вдаваться в тонкости проблемы программирования под NT системы (коей является и WinXP), кто захочет глубже разобраться, по ссылке все есть. Для нас важно то, что данная библиотека существует и благодаря ей, мы имеем возможность работать с LPT портом под WinXP. Эта библиотека содержит все необходимые для работы функции.
Все выше сказанное о данной библиотеке, я привел как пример того, что существует вариант работать в Delphi c LPT портом. Покопавшись в дебрях интернета, я увидел, что существует не только этот вариант, есть и другие варианты, которые использовал я в своих разработках и которые для новичка, на мой взгляд, будут намного проще для понимания и использования. Эти варианты мы сейчас и рассмотрим.
Существует проект LptWdmIo - некоммерческий проект программного обеспечения (ПО), ставящий целью, создание простого и надёжного компонента, для работы с параллельными портами IBM-совместимых персональных компьютеров, работающих под управлением ОС Windows. ПО, созданное в рамках проекта распространяется свободно (и бесплатно). Вы можете копировать, распространять и модифицировать ПО по своему усмотрению. Разрешается использование исходников для своих разработок, в т.ч. коммерческих. Этот проект, включает в себя специальный драйвер LPTWDMIO.sys, который предоставляет пользовательским приложениям, возможность управлять параллельными портами ПК. Обращение к драйверу из пользовательских приложений осуществляется через функцию DeviceIoControl( ). Он поддерживает два вида операций - чтение из порта и записи в порт. За одно обращение к драйверу возможны несколько (от одной и более) акций вывода (ввода) данных в (из) регистров порта. Это позволяет легко реализовывать сложные протоколы управления внешними устройствами.
Платформы Windows, на которых работает драйвер:
Windows 98 |
Проверено |
Windows Me |
Проверено |
Windows NT4 |
НЕ проверено, но противопоказаний нет |
Windows 2000 Prof. |
Проверено |
Windows XP Home Edition |
Проверено |
На ОС Windows 2000 Server и Windows XP Prof. драйвер не проверялся. Но противопоказаний к использованию нет. Как видите, драйвер поддерживается практически всеми пользовательскими операционными системами, что нам и нужно.
Итак, для того чтобы наши программы работали нужно скачать и установить данный драйвер в системе, а так же обзавестись средой визуального программирования, Borland Delphi 5.0 - 7.0. Как устанавливается драйвер, читайте далее.
Существует два варианта установки:
- Установка драйвера вручную.
- Автоматическая установка.
Установка драйвера вручную.
Установка вручную практикуется при использовании LPTWDMIO на ОС Windows 98/Me.
В этом случае надо запустить Мастер установки оборудования и указать ему путь к .inf файлу в подкаталоге Driver, который находится в скаченном архиве. Там же должен находиться файл lptwdmio.sys. После установки потребуется перезагрузка компьютера.
При желании удалить драйвер, можно через Диспетчер устройств (значок Система в панели управления). После удаления также может потребоваться перезагрузка.
При работе на ОС Windows 2000/XP также возможна установка вручную аналогичным способом.
Но в отличие от Windows 98/Me при установке перезагрузка точно не потребуется, драйвер стартует сразу.
Кроме того у ручной инсталляции есть одно преимущество: если клиентская программа была запущена от имени пользователя, не обладающего правами администратора, она всё равно сможет работать с портами через драйвер.
Автоматическая установка.
Автоматическая установка выполняется при создании объекта для работы с драйвером (см. след. пункт) в программе пользователя в том случае, если программа работает на платформе семейства NT - т.е. Windows NT4/2000/XP и драйвер не был ранее установлен вручную. При этом со стороны пользователя не требуется каких-либо дополнительных действий. Но если программа стартует от имени пользователя, не обладающего административными полномочиями, автоматическая установка не произойдёт, и программа пользователя не сможет управлять портами.
Мы подошли к самому интересному, непосредственно к программированию, через драйвер, при написании программ на Delphi.
Скачайте архив LPTWDMIO.rar, в котором находятся исходные тексты тестовой программы на Delphi и продолжим. Сразу сделаю оговорку: - дальнейшее описание модулей и исходников, для непосвященных новичков, будет конечно трудно осмыслить, посему не заостряйте на этом внимание, нам важно понять, как пишется непосредственно, сама программа с использованием готового модуля LPTIO.pas.Вот на практическом моменте написания программы и стоит сконцентрировать максимум внимания. Первым делом изучим содержимое архива:
В архиве LPTWDMIO.rar, находится три папки, Bonus, Delphi, Driver. О папке Bonus, будет сказано в конце статьи, в папке Delphi, находится базовый исходник - пример от разработчика и модуль LPTIO.pas, в папке Driver, находится сам драйвер который необходимо установить.
Чтобы облегчить программистам использование драйвера, был написан модуль LPTIO.pas.
В этом модуле определён класс TLptPortConnection. Для того, чтобы работать с портами, пользовательская программа должна создать объект данного класса. Объект сам связывается с драйвером и пользователю остаётся только проверить результат - готов объект или нет:
// <...>
type
TForm1 = class(TForm) // Класс для пользовательской формы
// <...>
procedure FormCreate(Sender: TObject); // Обработчик создания формы
procedure FormDestroy(Sender: TObject); // Обработчик разрушения
Lpt : TLptPortConnection; // Указатель на объект для работы с портами
end; // class
// <...>
// Обработчик создания формы
procedure TForm1.FormCreate(Sender: TObject);
var msg : AnsiString;
begin
Lpt := TLptPortConnection.Create;
if not Lpt.Ready then
begin {объект не готов -- покажем код ошибки}
msg := 'Ошибка при создании объекта Lpt, код = ' + IntToStr(GetLastError());
Application.MessageBox(PChar(msg),'ERROR',MB_OK);
Application.Terminate;
end;
end;
// Обработчик разрушения формы
procedure TForm1.FormDestroy(Sender: TObject);
begin
Lpt.Destroy;
end;
// <...>
Объект класса TLptPortConnection предоставляет в распоряжение пользователя ряд функций, большая часть которых описана в следующих пунктах.
function Ready : boolean; |
Возвращает признак готовности (true) или неготовности (false) |
function IsNtPlatform : boolean; |
Функцияя возвращает true, если работаем на платформе NT. Иначе -- false. |
function IsPortPresent(LptNumber : byte) : boolean; |
Ф-я тестирования наличия порта. Возвратит true, если порт присутствует |
function IsPortBidirectional(LptNumber : byte) : boolean; |
Ф-я тестирования порта на двунаправленность. Если порт двунаправленный, возвратит true. |
Если ф-я Ready( ) сразу после создания объекта возвращает false, это значит, что объект не смог связаться с драйвером. При работе под ОС Windows 98/Me такой ситуации не возникает, т.к. если драйвер не установлен, объект класса TLptConnection будет использовать прямые обращения к регистрам портов. При работе под ОС семейства NT, это как правило означает неудачу при попытке старта сервиса - не найден драйвер (должен быть размещён в каталоге программы) или нет административных полномочий. И ещё одно замечание - не создавайте несколько экземпляров объекта типа TLptPortConnection в одном приложении. Это совершенно не нужно.
Нумерация портов и регистров
Обращения к регистрам портов производятся по их логическим номерам. Номер составляется из маски порта и маски регистра. Логический номер имеет размер 1 байт. В модуле LPTIO.pas определены следующие константы:
{ Номера портов LPT }
LPT1 : byte = $10; // база $3BC
LPT2 : byte = $20; // $378
LPT3 : byte = $30; // $278
{Смещения регистров порта}
LPT_DATA_REG : byte = 0; // Регистр данных
LPT_STATE_REG : byte = 1; // Регистр состояния
LPT_CONTROL_REG : byte = 2; // Регистр управления
LPT_EPP_ADDRESS : byte = 3; // Регистр адреса EPP
LPT_EPP_DATA : byte = 4; // Регистр данных EPP
Например, логический номер регистра управления порта LPT2:
(LPT2 or LPT_CONTOL_REG)
при этом обращение будет выполняться по адресу $378+2 = $37A.
Нумерация отдельных бит регистров
Побитная раскладка регистров порта LPT определена в виде двух наборов констант - для регистров управления и для регистров состояния:
{ Битовые расклады регистров / разъём 25 pin / разъём Centronic }
{ Битовый расклад регистра УПРАВЛЕНИЯ }
STROBE : byte = $01; { Строб, 1 /1 }
AUTOFEED : byte = $02; { Автопротяжка, 14/14 }
INIT : byte = $04; { Инициализация, 16/31 }
SELECTIN : byte = $08; { Выбор принтера, 17/36 }
IRQE : byte = $10; { Прерывание, ------ }
DIRECTION : byte = $20; { Направление ШД, ------ }
{ Битовый расклад регистра СОСТОЯНИЯ }
IRQS : byte = $04; { Флаг прерывания,------ }
ERROR : byte = $08; { Признак ошибки, 15/32 }
SELECT : byte = $10; { Признак выбора, 13/13 }
PAPEREND : byte = $20; { Конец бумаги, 12/12 }
ACK : byte = $40; { Готовность к приёму данных, 10/10}
BUSY : byte = $80; { Занятость, 11/11 }
Эти значения могут быть использованы, например для управления состоянием отдельных линий. Например, вот так можно установить бит INIT в регистре управления порта LPT1:
Lpt.WritePort(LPT1,LPT_CONTROL_REG, (INIT or Lpt.ReadPort(LPT1,LPT_CONTROL_REG)) )
Функции для вывода данных
Этих ф-ций две: WritePorts( ) и WritePort( ).
WritePorts( ), предназначена для вывода пакета данных (множество значений). Определена следующим образом:
function WritePorts(PairArray : PADRDATASTRUCT; PairCount : cardinal) : boolean;
PairArray должен указывать на массив структур типа ADRDATASTRUCT:
{Структура Адрес-Данные}
ADRDATASTRUCT = record
Adr : byte; {адрес == <Номер порта> or <Смещение регистра>}
Data : byte; {данные для вывода или место для прочитанного байта}
end;
Массив передаётся в драйвер полностью, цикл по структурам происходит внутри самого драйвера. Для каждой структуры выполняется вывод данных в регистр порта. Это позволяет выдавать данные в порты с максимальной скоростью, причём акт выдачи такого блока данных не может быть прерван до его завершения другими пользовательскими приложениями, что весьма удобно для реализации протоколов передачи, критичных ко времени. Параметр PairCount -- должен содержать количество структур в массиве PairArray. WritePort( ) предназначена для вывода одиночного байта в указанный порт:
procedure WritePort (LptNumber : byte; RegOffset : byte; Value : byte);
Здесь LptNumber - одна из констант LPT1..LPT3, определяет номер порта,
RegOffset -- одна из констант LPT_DATA_REG, LPT_STATE_REG, LPT_CONROL_REG, определяет номер регистра порта. Value -- значение, которое будет выведено в указанный регистр.
Функции для ввода данных
Для ввода данных предназначены функции ReadPorts( ) и ReadPort( ).
function ReadPorts (PairArray : PADRDATASTRUCT; PairCount : cardinal) : boolean;
Параметры задаются аналогично WritePorts( ), отличие в том, что при выполнении этой процедуры в поля Data каждой структуры ADRDATASTRUCT будут записаны значения, прочитанные из регистров портов, номера которых (<порт> or <регистр>) были указаны в полях Adr.
Функция возвращает false, если объект TLptConnection не готов к работе или если произошла ошибка в драйвере.
function ReadPort (LptNumber : byte; RegOffset : byte) : byte;
Параметры задаются аналогично WritePort( ). Возвращаемое значение - результат чтения регистра порта.
Автозагрузка драйвера
Автозагрузка драйвера выполняется объектом типа TLptConnection при работе на NT-платформах Windows в том случае, если драйвер не был установлен вручную. Однако, для успешного старта драйвера необходимо, чтобы программа запускалась от имени пользователя, обладающего административными полномочиями.
А теперь давайте отвлечемся, от сложных теоретических повествований и попробуем написать пару простейших программ, к примеру, помигаем диодом и заставим нашу программу как то реагировать на внешнее событие (замыкание одного из тумблеров, нашей схемки см. рис. ниже).
Подключив данную схемку к LPT порту, из распакованного архива, в папке Bonus (о которой я говорил выше), запустите на выполнение файл Project1.exe. Эта программка написанна мной, специально для демонстрации практически всех возможностей программирования LPT порта с помощью LPTWDMIO метода. Попробуйте, поиграйтесь элементами управления, измените некоторые участки программного кода относящиеся непосредственно к выводу и чтению информации с порта. Таким образом, вы досконально разберетесь, как работает данная система.
Как видите, кто знаком с азами программирования на Delphi, все достаточно просто. Благодаря замечательному проекту LPTWDMIO, программисты получили возможность работать с LPT портом, не вдаваясь в API функции Windows и прочие извороты. В папке Delphi, архива LPTWDMIO.rar, как выше было сказано, лежит исходник программы test.exe, от разработчика проекта, его так же необходимо внимательно изучить. В представленных исходниках программ Test и Project1, много полезного, тем более исходный текст снабжен подробными комментариями, как говорят в стиле лучших традиций программирования. Программа Project1 в папке Bonus, написана для новичков, с подробными комментариями и в принципе представляет собой готовый исходник, для реализации программ любой сложности.
Вверх | Главная | Далее..