Hardware Access/pt

From Free Pascal wiki
Jump to navigationJump to search

Deutsch (de) English (en) español (es) français (fr) magyar (hu) 日本語 (ja) 한국어 (ko) polski (pl) português (pt) русский (ru) slovenčina (sk) 中文(中国大陆)‎ (zh_CN)

Visão Geral

Está página é o inicio de um tutorial sobre acesso a dispositivos de hardware no Lazarus. Estes dispositivos incluem, mas não se limitam a: Placas ISA e PCI, as portas paralela e serial e USB.

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

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

Não se sabe ainda, até esse momento, se Mac OS x/x86 permitirá acesso HW. Ele pode não permitir isso, embora eu assuma neste caso , em tempo, que drivers como io.dll aparecerão.

Comparação entre Paralelo e Serial

Placas ISA, Placas PCI e a Porta Paralela comunicam-se com o computador utilizando um protocolo de comunição paralela. A Porta Serial e dispositivos USB trabalham com um protocolo serial. Como o processando e, consequentemente, as linguagens de programação trabalham com uma abordagem paralela aos dados, esse tipo de acesso é mais fácil de ser implementado no lado do software. Ao acessar uma variável do tipo inteiro, por exemplo, você pode acessar seu conteúdo inteiro com um único comando. Com o protocolo serial apenas um bit é enviado de cada vez e é preciso juntá-los para depois poder compreender os dados.

A Comunicação serial é difícil de ser implementada diretamente, mas pode ser muito fácil se utilizarmos um componente pronto. Ela também é mais difícil no lado do hardware, logo muitos dispositivos utilizam Circuitos Integrados especialmente desenvolvidos ou até microcontroladores para implementar o protocolo serial.

Agora uma breve comparação dos protocolos de comunicação:

Velocidade Dificuldade de implementação do hardware
Porta Serial Muito lenta (< E5 bit/s) Média
Porta Paralela Lenta (~ E6 bit/s) Fácil
Placa ISA Média (~ E7 bit/s) Média
USB Média (~ E7 bit/s) Difícil
Placa PCI Muito Rápida (> E9 bit/s) Muito difícil

Comunicação Paralela

Utilizando a inpout32.dll para Windows

O Windows tem diferentes formas para acessar dispositivos de hardware na série 9x e na série NT. A série 9x (95, 98, Me) os programas podem acessar as portas diretamente, da mesma maneira que era feito no DOS. A série NT, porém, não permite isto e todos acesso as portas devem ser feitos através de Dispositivos Drivers. Isto é um 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}

Este código foi testado com uma placa ISA própria na porta$0220, utilizando o Lazarus 0.9.10 no Windows XP. Obviamente é necessário possuir a unidade Windows na cláusula "uses" para que este código possa funcionar. Para distribuir um aplicativo que utilize a biblioteca você precisa apenas incluir a "inpout32.dll" no mesmo diretório do executável.

Está é a página principal da biblioteca: www.logix4u.net/inpout32.htm

Usando assembler no Windows 9x

No Windows 9x você pode também utilizar código assembler. Supondo que você deseja escrever em $CC para a portal $320. O seguinte código fará isso:

 {$ASMMODE ATT}
 ...
    asm
        movl $0x320, %edx
        movb $0xCC, %al
        outb %al, %dx
    end ['EAX','EDX'];

Troubleshooting no Windows

Uma possível fonte de confusão usando hardware paralelo que não suporta Plug and Play no Windows é que o Windows pode associar a porta utilizada pelo seu hardware para outro dispositivo. Você pode procurar instruções na URL a seguir sobre como falar para o Windows não associar o endereço de seu dispositivo para dispositivos Plug And Play:

http://support.microsoft.com/kb/135168

Utilizando ioperm para acessar portas no Linux

A melhor maneira de acessar dispositivos de hardware no Linux é através de drivers, mas, devido a complexidade envolvida na criação de um, às vezes um método mais simples é muito útil.

Para utilizar a unidade "ports" no Linux, seu programa deve ser executado como super-usuário (ex: root) e a função IOPerm deve ser chamada para definir as permissões de acesso as portas. Você pode encontrar documentação sobre a unidade "ports" aqui.

A primeira coisa a ser feita é estabelecer um vínculo com o (g)libc e chamar a função IOPerm. Uma unidade que estabelece vínculos para todo o (g)libc existe no Free Pascal, mas ela causa problemas quando é utilizada diretamente pela aplicação e vinculação estática, além do que não é uma boa idéia porque ela mudança frequentemente entre versões em uma incompatível maneira. Funções como ioperm, entretanto, são improváveis de serem modificadas.

 {$IFDEF Linux}
 function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external 'libc';
 {$ENDIF}
  • "from" representa a primeira porta a ser acessada.
  • "num" é o número de portas após a primeira a serem acessadas, assim ioperm($220, 8, 1) dará ao programa acesso a todos portas entre e incluindo $220 e $227.

Após vincular OIPerm você pode utilizar port[<Endereço>] para acessar as portas.

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

Este código for testado com uma placa ISA própria na porta $0220, utilizando o Lazarus 0.9.10 no Mandriva Linux 2005 e no Damn Small Linux 1.5.

Acesso geral ao Hardware UNIX

{$IFDEF Unix}
Uses Clib;   // recupera o nome da biblioteca libc.
{$ENDIF}

{$IFDEF Unix}
function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external clib;
{$ENDIF}


Nota Note que o FPC fornece uma abstração para ioperm chamada "fpioperm" na unit x86, e também define funções out e inport. Essas funções atualmente são implementadas por Linux/x86 e FreeBSD/x86.

Não é recomendado vincular libc a menos que seja absolutamente necessário para possibilitar o desenvolvimento e portabilidades das funções. Também a vinculação manual da libc (declarando importações pontuais libc para funções que estão disponíveis noutros países) como feito anteriormente não é recomendado (ex: a importação libc na linha acima irá falhar se, desnecessariamente, o padrão lib C não é chamado libc, como por exemplo libroot no BeOS, ou em plataformas com simbolos não-padrão C estragados).

Nota 2 Usar _unit_ libc não é recomendado sob quaisquer outras cirscunstâncias do que a compatibilidade com Kylix. Isso porque a unit é relativamente não-portável (garanta a exposição das estruturas e outros símbolos privados) e deve ser modificada tão pouco quanto possível fora das questões de compatibilidades com Kylix.

Comunicação Serial

A seção de Links Externos tem tutoriais de portas seriais UNIX e Windows.

USB

libusb

Uma possibilidade multi-plataforma para Linux, BSDs e Mac OS X é a libusb.

Os cabeçalhos estão listado em http://www.freepascal.org/contrib/db.php3?category=Miscellaneous:

nome autor versão data link comentários
libusb.pp Uwe Zimmermann 0.1.12 2006-06-29 http://www.sciencetronics.com/download/fpc_libusb.tgz
libusb.pas Johann Glaser 2005-01-14 http://www.johann-glaser.at/projects/libusb.pas
fpcusb Joe Jared 0.11-14 2006-02-02 http://relays.osirusoft.com/fpcusb.tgz link download quebrado

FTDI

Se você usa um dos chips da FTDI, você pode os cabeçalhos pascal da sua interface de dll para o chip.

Links Externos

Comparação de velocidade de Protocolos de Comunicação

  1. http://en.wikipedia.org/wiki/Serial_port#Speed
  2. http://www.lvr.com/jansfaq.htm - Jan Axelson's Parallel Port FAQ
  3. http://en.wikipedia.org/wiki/USB#Transfer_Speed
  4. http://en.wikipedia.org/wiki/PCI#Conventional_PCI_bus_specifications

Links de Comunicação Serial:

  1. Em UNIX: [1]
  2. Em Windows: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/msdn_serial.asp
  3. Componente Synaser: http://synapse.ararat.cz/
  4. Pacote Delphi Comport: http://sourceforge.net/projects/comport/

ISA Digital Oscilloscope - Um exemplo de acesso ao hardware com fonte completo incluso:

[2]