Hardware Access/pt

From Lazarus wiki
Revision as of 22:23, 20 October 2005 by Sekelsenmat (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

Visão Geral

Está página é o começo de um tutorial sobre acesso a dispositivos de hardware por programas desenvolvidos no Lazarus. Estes dispositivos incluem, porem não estão limitados a: Placas ISA e PCI, as portas paralela e serial e USB.

O acesso ao hardware de uma maneira completamente multi-plataforma não é implementada pela biblioteca RunTime do Free Pascal ou pela LCL, assim este tutorial cobre metodos diferentes para diferentes plataformas. O código pode ser compilado em ambientes diferentes utilizando a compilação condicional. Abaixo segue um exemplo disto:

uses
 Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls,
{$IFDEF WIN32}
  Windows;
{$ENDIF}
{$IFDEF Linux}
  ports;
{$ENDIF}

Quem desejar pode contribuir para este documento.

Utilizando a inpout32.dll para Windows

No Windows há diferentes metodos para acessar dispositivos de hardware na série 9x e na série NT, o que pode gerar muitos problemas. A série 9x (95, 98, Me) permite que os programas acessem as portas diretamente, da mesma maneira que éra feita no DOS. A série NT, porém, não permite isto e todos acesso as portas deve ser feito através de Device Drivers. Isto é mecanismo de segurança, mas pode complicar o desenvolvimento de aplicativos pequenos que apenas precisam acessar uma determinada porta.

Felizmente existe uma biblioteca que carrega dentro de si um driver. Quando ela é chamada para acessar uma determinada porta ela detecta se o Windows em operação é da série NT e, em caso afirmativo, descomprime o driver Hwinterface.sys e o instala no kernel. Se a série 9x for detectada ele simplesmente utiliza instruções de assembler para acessar o hardware.

Mas como utilizar a biblioteca? Simples! Ela possuí apenas duas funções, Inp32 e Out32, e seu uso é bastante intuitivo.

Nós estaremos carregando a biblioteca dinamicamente, então é bom definir as funções antes:

type
  TInp32 = function(Address: ShortInt): ShortInt; stdcall;
  TOut32 = procedure(Address: ShortInt; Data: ShortInt); stdcall;

  • Address representa o endereço da porta a ser acessada. Out32 envida Dados para a porta. Inp32 returna um byte da porta no Address.

Agora podemos carregar a biblioteca. Isto pode ser implementado num lugar como o evento OnCreate do seu formulário principal:

type
  TMyForm = class(TForm)
  .........
  private
    { private declarations }
    Inpout32: THandle;
    Inp32: TInp32;
    Out32: TOut32;
  .........
implementation
  .........
procedure TMyForm.FormCreate(Sender: TObject);
begin
{$IFDEF WIN32}
  Inpout32 := LoadLibrary('inpout32.dll');
  if (Inpout32 <> 0) then
  begin
    @Inp32 := GetProcAddress(Inpout32, 'Inp32');
    if (@Inp32 = nil) then Caption := 'Error';
    @Out32 := GetProcAddress(Inpout32, 'Out32');
    if (@Out32 = nil) then Caption := 'Error';
  end
  else Caption := 'Error';
{$ENDIF}
end;

Se você carregar a biblioteca no evento OnCreate não esqueça de descarrega-la no evento OnDestroy:

procedure TMyForm.FormDestroy(Sender: TObject);
begin
{$IFDEF WIN32}
  FreeLibrary(Inpout32);
{$ENDIF}
end;

Aqui está um exemplo de uso da função Inp32:

{$IFDEF WIN32}
  myLabel.Caption := IntToStr(Inp32($0220));
{$ENDIF}

This code was tested with a custom ISA card on port $0220, using Lazarus 0.9.10 on Windows XP. Of course you will need to have Windows on your uses clause in order for this code to run. For deployment you only need to include "inpout32.dll" in the same directory of our application.

This is the homepage for the library: www.logix4u.net/inpout32.htm

Using ioperm to access ports on Linux

The best way to access the hardware on Linux is throught device drivers, but, due to the complexity of the task of creating a driver, sometimes a quick method is very useful.

In order to use the "ports" unit under linux your program must be run as root, and IOPerm must be called to set appropriate permissions on the port access. You can find documentation about the "ports" unit here.

The first thing to do is link to glibc and call IOPerm. A unit that links to the entire glibc exists on free pascal, but this unit gives problems when used directly by application and linking statically to the entire glibc library is not a very good idea for a multi-platform application. The use of platform-specific functions should be kept to a minimum.

{$IFDEF Linux}
function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external 'libc';
{$ENDIF}

  • "from" represents the first port to be accessed.
  • "num" is the number of ports after the first to be accessed, so ioperm($220, 8, 1) will give access for the program for all ports between and including $220 and $227.

After linking to OIPerm you can port[<Address>] to access the ports.

{$IFDEF Linux}
  i := ioperm($220, 8, 1);
  port[$220] := $00;
  myLabel.Caption := 'ioperm: ' + IntToStr(i);
  i := Integer(port[$220]);
  myOtherLabel.Caption := 'response: ' + IntToStr(i);
{$ENDIF}

This code was tested with a custom ISA card on port $0220, using Lazarus 0.9.10 on Mandriva Linux 2005 and Damn Small Linux 1.5