unit Ppar;

{ ------------------------ } interface { ------------------------------ }

{$ifdef Linux}
uses
  Ports, x86;
{$endif}

const
  PPAR_SELECT = 3;		{ output, control port }
  PPAR_ERROR = 3;		{ input, status port }
  PPAR_BUSY = 7;		{ input, status port }

  PPAR_STATUS = 1;
  PPAR_CONTROL = 2;

  PPAR_INV_STATUS = $80;
  PPAR_INV_CONTROL = $0B;

type
  par_port = object
    addr: word;
    ctl_state,
    data_state: byte;

    procedure Initialize(paddr: word);
    procedure Release;
    procedure SetData(data: byte);
    procedure SetDataBit(bitnr: integer; new_state: boolean);
    procedure SetControlBit(bitnr: integer; new_state: boolean);
    function GetDataBit(bitnr: integer): boolean;
    function GetControlBit(bitnr: integer): boolean;
    function GetStatusBit(bitnr: integer): boolean;
  end;

{ ---------------------- } implementation { --------------------------- }

procedure par_port.Initialize(paddr: word);
var
  err: integer;
begin
  addr := paddr;
  data_state := $ff;
{$ifdef fpc}
  err := fpioperm(paddr, 3, 1);
  if err <> 0 then begin
    writeln('Cannot IOPerm the parallel port');
    halt;
  end;
{$endif}
  port[addr] := data_state;
end;

procedure par_port.Release;
begin
{$ifdef fpc}
  fpioperm(addr, 3, 0);
{$endif}
end;
  

procedure par_port.SetData(data: byte);
begin
  data_state := data;
  port[addr] := data_state;
end;

procedure par_port.SetDataBit(bitnr: integer; new_state: boolean);
begin
  if new_state then
    data_state := data_state or (1 shl bitnr)
  else
    data_state := data_state and not(1 shl bitnr);
  port[addr] := data_state;		// No inversion for data port
end;

procedure par_port.SetControlBit(bitnr: integer; new_state: boolean);
begin
  if new_state then
    ctl_state := ctl_state or (1 shl bitnr)
  else
    ctl_state := ctl_state and not(1 shl bitnr);
  port[addr+PPAR_CONTROL] := ctl_state xor PPAR_INV_CONTROL;
end;

function par_port.GetDataBit(bitnr: integer): boolean;
begin
  GetDataBit := (data_state and (1 shl bitnr))  <> 0;
end;

function par_port.GetControlBit(bitnr: integer): boolean;
begin
  GetControlBit := (port[addr+PPAR_CONTROL] and (1 shl bitnr)) <> 0;
end;

function par_port.GetStatusBit(bitnr: integer): boolean;
begin
  GetStatusBit := ((port[addr+PPAR_STATUS] xor PPAR_INV_STATUS)
                    and (1 shl bitnr)) <> 0;
end;


begin
end.
