Воскресенье, 19.05.2024, 04:19
Personal dimanche13 site
Главная | Регистрация | Вход Приветствую Вас Гость | RSS
Категории каталога
Мои статьи [22]
BlitzMax [17]
раздел содержит статьи относящиеся к языку программирования BlitzMax
SDL [9]
раздел содержит статьи на тему SDL
Code::Blocks [3]
в этом разделе рассказывается как прикрутить движок к интегрированной среде разработки(IDE) Code::Blocks
Форма входа
Поиск
Друзья сайта
Главная » Статьи » BlitzMax

BlitzMax + LPT-port

ВВЕДЕНИЕ.

Где-то год назад, передо мной встала задача использовать LPT порт компьютера для подключения к одному устройству через интерфейс JTAG, с целью считывания дампа flash-памяти. Эту задачу я решил взвалить на хрупкие плечи BlitzMax-а. И только я начал разработку, как у меня сменился рабочий комп. На новом уже и небыло параллельного порта, так что я даже не смог проверить свое творение))). Но все-таки хочу рассказать обо всем этом. Времени правда прошло предостаточно, где-то я что-то и подзабыл, ну да ладно буду вспоминать по ходу дела.

ПАРАЛЛЕЛЬНЫЙ ПОРТ (LPT).

Странно, но в новых материнских платах, стали избавляться от такого большого довеска как паралельный порт. Хотя это и не сложно понять, ведь этот интерфейс уже довольно таки старый и теперь уже нигде почти не используется, помимо этого еще и занимает предостаточно места. На смену ему пришел USB - универсальная шина, на которую можно цеплять всё: от мышки до подогревалки кофе или точилки для карандашей или другого ЮСБ-барахла. Тем не менее для программистов работающих с перефирийными устройствами, этот паралельный порт подходил как нельзя кстати. Он содержит 25 пинов. В этом его недостаток(занимает много места), но в этом его и приемущество. В отличие от последовательных шин, этот порт может передавать данные паралельно, что и так понятно из названия))) Первоначально он использовался для подключения принтеров к компьютеру, если помните они так орали при печати, как кошки в мае не кричат. И в связи с тем что он часто использовался для подключения принтеров у него были некоторые специфичные сигналы и названия.

Состоит порт из 3 логических портов(еще я буду называть их регистрами)

1)порт данных (DATA)

2)порт состояния (STATUS)

3)порт контроля (CONTROL)

Изначально порт данных был только для вывода, но теперь он может быть использован и для входа данных. Насколько я знаю, устанавливается режим в БИОС-е. (поправьте если не так) Как они распределены на контактере, можно увидеть из рисунка:

Как видите дата-порт имеет 8 пинов (контакты 2-9). Чаще всего работают с ним, так как к нему легко обращаться с байтом данных(8 бит) и он двунаправленный, остальные порты в этом плане не полноценны. Регистр STATUS(контакты 10-13 и 15) служит только для чтения данных из-вне. Следующий регист CONTROL(контакты 1, 14, 16-17) он еще меньше - всего 4 контта(пина) умеет работать только на вывод данных. Итого мы видим 1 полный двунаправленный порт и 2 однонаправленных, да еще и не полных. Некоторые пины имеют свои технические названия, например 16 - INITIALIZE - и служит для инициализации принтера. Конечно, для инициализации достаточно и одной направленности, потому эти сигналы и остались с давних времен однонаправленными, так сказать для совместимости. Остальные контакты земляные GND. Тем не менее, программисту есть где развернуться ))).

Программирование.

На каждом компьютере может быть установлено до 4 LPT-портов. И чтобы как-то с ними разбираться у них есть адрессация. Так, например, первый LPT-порт имеет адрес 0x378 в 16-тиричной системе счисления, второй 0x278. Эти адреса называются базовыми для порта(BASE_ADDRESS) и указывают на регистр DATA. Чтоб узнать адрес регистра STATUS порта надо просто прибавить 1 к базовому адресу, а чтоб получить адрес регистра CONTROL надо прибавить 2 к базовому адресу. Вот пример:

BASE_ADDRESS = 0х378 // LPT1

DATA_REG_ADDRESS = BASE_ADDRESS // 0x378

STATUS_REG_ADDRESS = BASE_ADDRES + 1 // 0x379

CONTROL_REG_ADDRESS = BASE_ADDRESS + 2 // 0x37A

Да, раньше в ДОС-е и Win`95(8) можно было обращаться к порту простыми функциями записи в порт. Но с NT системами такое уже не проходит (надо работать через WinApi) а через WinApi мне работать как-то не хотелось))) . И о счастье, бродя по интернету в поисках решения этой проблемы малой кровью, я зашел на сайт http://www.pcports.ru на котором рассматривалась библиотека inpout32.dll и чем она хороша, что позволяет работать с портом независимо в какой системе ты работаешь в 95(8) или в NT/2000. Вот схема того как она функционирует, с сайта разработчика этой библиотеки. 

как вы сами видите, она сначала проверяет какая система установлена у пользователя, а потом применяет необходимые функции записи/чтения из порта. Хорошо, что такая библиотека нашлась. Правда есть и еще много таких же либ, для работы с параллельным портом, но эта имеет малый размер, работает на нескольких системах и имеет в себе все 2 необходимых нам функции. Для чтения(Inp32()) и записи(Out32()) в порт. Вот их прототипы:

Out32(port, data);  // Out32(адрес_порта, данные)  

data = Inp32(port); // данные = Inp32(адрес_порта)  

Конечно помимо этих функций она содержит еще ряд, таких как открытие и закрытие драйвера, проверка системы и др. Но они более низкоуровневые и нами использоваться не будут. Если вы хотите их изучить подробнее или посмотреть исодный код, то посетите эту страничку http://logix4u.net/Legacy_Ports/Parallel_Port/How_Inpout32.dll_works_.html Кстати, на их сайте так же сть форум, в котором комьюнити поможет решить вашу проблему с программированием портов. Нам же надо двигаться дальше.

BlitzMax + dll.

Просто великолепно, нужная библиотека у нас есть. Осталось научить БМ понимать и использовать ее функции в наших целях. Для того чтобы воспользоваться библиотекой, все равно придется использовать WInApi функцию. Называется она LoadLibraryA , которая принимает имя библиотеки в кодировке ANSI, для unicode есть функция LoadLibraryW. И возвращает она хэндл библиотеки. Его надо проверить на нуль, чтоб убедиться что либа успешно загружена.

SuperStrict

Global DllHandle:Int = LoadLibraryA("inpout32.dll")

If (Not DllHandle)
 RuntimeError(" Where is the file ~qinpout32.dll~q ? ")
End If

Кстати, мы можем не только узнать что наша dll-ка не загружена, но так же узнать более подробное сообщение об ошибке. ВинАпи предоставляет такую возможность функцией GetLastError(), которая возвращает значение последнего неудачного Windows API вызова, а уже по номеру можно найти ее текстовое описание в msdn. Или сформировать это описание другими способами. Но это уже в другую степь.

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

Global Inp32:Int( port:Int )"Win32" = GetProcAddress(DllHandle,"Inp32")
Global Out32( port:Int, value:Int )"Win32" = GetProcAddress(DllHandle,"Out32")

GetProcAddress - так же ВинАпи функция. В случае успешного завеpшения возвращает точку входа в функцию, в пpотивном случае возвращает 0. Принимает хэнд библиотеки и название функции из этой библиотеки. Вот после этого можно использвать эти функции, как нам угодно в нашей программе на БМ, все остальное сделает dll-ка. ))) 

Программа.

SuperStrict

Global DllHandle:Int = LoadLibraryA("inpout32.dll")

If (Not DllHandle)
 RuntimeError(" Where is the file ~qinpout32.dll~q ? ")
End If

Global Inp32:Int(port:Int) "Win32" = GetProcAddress(DllHandle, "Inp32")
Global Out32(port:Int, value:Int) "Win32" = GetProcAddress(DllHandle, "Out32")

Const LPT1:Short = $378

Const LPT_DATA:Int = 0
Const LPT_STATUS:Int = 1
Const LPT_CONTROL:Int = 2 

Type _Flag
 Field value:Byte
 
 Method Set(bit:Int)
  value :| (1 Shl bit)
 End Method

 Method Get:Int(bit:Int)
  Return (value & (1 Shl bit)) Shr bit
 End Method

 Method Clear(bit:Int)
  value :& ~(1 Shl bit)
 End Method
 
 Method Toggle(bit:Int)
  value :~ (1 Shl bit)
 End Method

 Method Reset()
  value = 0
 End Method
End Type

Type _Port

 Field Address:Short
 Field idreg:Int
 Field in:_Flag = New _Flag
 Field out:_Flag = New _Flag
 
 Method New()
  Address = LPT1
  idreg = LPT_DATA
  in.Reset()
  out.Reset()
 End Method

 Method Delete()
  in = Null
  out = Null
 End Method
 
 Function Create:_Port(_address:Short, _idreg:Int)
  Local Port:_Port = New _Port
  Port.Address = _address + _idreg
  Port.idreg = _idreg
  Return Port
 End Function
  
 Method Write(value:Byte)
  out.value = value
  Out32(Address, out.value)
 End Method
 
 Method Read:Byte()
  Return Inp32(Address)
 End Method

 Method Set(pin:Int)
  
  out.value = Read()
  
  Select(idreg)
  Case LPT_STATUS WriteStdout("Impossible! ") 
   
  Case LPT_CONTROL 
  Select pin
  Case 4, 5, 6, 7 WriteStdout("CONTROL registrer used 0-3 bits. "); Return
  End Select 
  End Select 
   
  out.Set(pin)
  Write(out.value)  

 End Method

 Method Clr(pin:Int)
  
  out.value = Read()
  
  Select(idreg)
  Case LPT_STATUS WriteStdout("Impossible! ") 
   
  Case LPT_CONTROL 
  Select pin
  Case 4, 5, 6, 7 WriteStdout("CONTROL registrer used 0-3 bits. "); Return
  End Select 
  End Select 
   
  out.Clear(pin)
  Write(out.value)  

 End Method

 Method Get:Int(pin:Int) 
  
  in.value = Read()
  
  Select( idreg )

  Case LPT_STATUS  

  Select pin
  Case 0, 1, 2 WriteStdout("STATUS registrer used 3-7 bits. ")
  End Select

  Case LPT_CONTROL 
   
  Select pin
  Case 4, 5, 6, 7 WriteStdout("CONTROL registrer used 0-3 bits. ")
  End Select
   
  End Select 

  Return in.Get(pin)
 
 End Method 
 
 Method Clear()
  in.Reset()
  out.Reset()  
 End Method

End Type

Local i:Int
Local CtrlPort:_Port = _Port.Create(LPT1, LPT_CONTROL)
Local DataPort:_Port = _Port.Create(LPT1, LPT_DATA)
Local StatPort:_Port = _Port.Create(LPT1, LPT_STATUS)

'CtrlPort.Set(0)
'CtrlPort.Set(1)
'CtrlPort.Set(2) 
'CtrlPort.Set(3) 

Print

For i = 0 Until 8
 Print "DATA[" + i + "] = " + DataPort.Get( i )
Next

Print

For i = 0 Until 8
 Print "STATUS[" + i + "] = " + StatPort.Get( i )
Next

Print

For i = 0 Until 8
 Print "CONTROL[" + i + "] = " + CtrlPort.Get( i )
Next

While Not KeyHit(KEY_ESCAPE) Wend

End 

Как я и говорил, программу протестировать мне не удалось. Даже посмотреть на каком-нибудь снифере LPT-порта. Если вдруг, что-то не работает, то сообщите мне об этом. А если работает- то я тоже хочу об этом знать ))) К слову, когда писалась эта статья, я посетил сайт разработчика inpout32.dll там уже анонсирована следующая библиотека (hwinterface32), которая имеет более обширный функционал. Теперь помимо записи в порт данных разного размера, там есть функции для записи/считывания памяти. Если кому интересно, то сейчас идет ее бета-тестирование, можете помочь отловить пару блох.

http://logix4u.net/Legacy_Ports/Parallel_Port/How_to_read_Parallel_Serial_Port_address_from_BIOS.html

Спасибо, за внимание. Удачи Вам в разработке ;)
Категория: BlitzMax | Добавил: dimanche (24.05.2008) | Автор: Dmitriy
Просмотров: 2093 | Комментарии: 2 | Рейтинг: 5.0/2 |
Всего комментариев: 0
Имя *:
Email *:
Код *:
Copyright MyCorp © 2024