unit FOS_COM;
(*
**
** Serial and TCP/IP communication routines for DOS, OS/2 and Win9x/NT.
** Tested with: TurboPascal   v7.0,    (DOS)
**              VirtualPascal v2.1,    (OS/2, Win32)
**              FreePascal    v0.99.12 (DOS, Win32)
**              Delphi        v4.0.    (Win32)
**
** Version : 1.01
** Created : 21-May-1998
** Last update : 07-Apr-1999
**
** Note: (c) 1998-1999 by Maarten Bekers
**
*)

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)
 INTERFACE
(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

uses Dos, Combase;

type TFossilObj = Object(TCommObj)
        Regs   : Registers;
        FosPort: Byte;

        constructor Init;
        destructor Done;

        function  Com_Open(Comport: Byte; BaudRate: Longint; DataBits: Byte;
                           Parity: Char; StopBits: Byte): Boolean; virtual;
        function  Com_OpenKeep(Comport: Byte): Boolean; virtual;
        function  Com_GetChar: Char; virtual;
        function  Com_CharAvail: Boolean; virtual;
        function  Com_Carrier: Boolean; virtual;
        function  Com_SendChar(C: Char): Boolean; virtual;
        function  Com_ReadyToSend(BlockLen: Longint): Boolean; virtual;
        function  Com_GetBPSrate: Longint; virtual;
        function  Com_GetDriverInfo: String; virtual;
        function  Com_GetHandle: longint; virtual;

        procedure Com_OpenQuick(Handle: Longint); virtual;
        procedure Com_Close; virtual;
        procedure Com_SendBlock(var Block; BlockLen: Longint; var Written: Longint); virtual;
        procedure Com_SendWait(var Block; BlockLen: Longint; var Written: Longint; Slice: SliceProc); virtual;
        procedure Com_ReadBlock(var Block; BlockLen: Longint; var Reads: Longint); virtual;
        procedure Com_GetBufferStatus(var InFree, OutFree, InUsed, OutUsed: Longint); virtual;
        procedure Com_SetDtr(State: Boolean); virtual;
        procedure Com_GetModemStatus(var LineStatus, ModemStatus: Byte); virtual;
        procedure Com_SetLine(BpsRate: longint; Parity: Char; DataBits, Stopbits: Byte); virtual;
        procedure Com_PurgeInBuffer; virtual;
        procedure Com_PurgeOutBuffer; virtual;
        procedure Com_SetFlow(SoftTX, SoftRX, Hard: Boolean); virtual;
     end; { object TFossilObj }

Type PFossilObj = ^TFossilObj;

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)
 IMPLEMENTATION
(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

uses Strings
       {$IFDEF GO32V2}
         ,Go32
       {$ENDIF} ;


(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure DosAlloc(var Selector: Word; var SegMent: Word; Size: Longint);
var Res: Longint;
begin
  {$IFDEF GO32V2}
    Res := Global_DOS_Alloc(Size);
    Selector := Word(Res);

    Segment := Word(RES SHR 16);
  {$ENDIF}
end; { proc. DosAlloc }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure DosFree(Selector: Word);
begin
  {$IFDEF GO32V2}
    Global_DOS_Free(Selector);
  {$ENDIF}
end; { proc. DosFree }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

constructor TFossilObj.Init;
begin
  inherited Init;
end; { constructor Init }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

destructor TFossilObj.Done;
begin
  inherited Done;
end; { destructor Done }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure FossilIntr(var Regs: Registers);
begin
  Intr($14, Regs);
end; { proc. FossilIntr }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function TFossilObj.Com_Open(Comport: Byte; BaudRate: Longint; DataBits: Byte;
                             Parity: Char; StopBits: Byte): Boolean;
begin
  {-------------------------- Open the comport -----------------------------}
  FosPort := (ComPort - 01);

  Regs.AH := $04;
  Regs.DX := FosPort;
  Regs.BX := $4F50;

  FossilIntr(Regs);

  Com_Open := (Regs.AX = $1954);
  InitFailed := (Regs.AX <> $1954);
  Com_SetLine(BaudRate, Parity, DataBits, StopBits);
end; { func. TFossilObj.Com_OpenCom }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function TFossilObj.Com_OpenKeep(Comport: Byte): Boolean;
begin
  FosPort := (ComPort - 01);

  Regs.AH := $04;
  Regs.DX := FosPort;
  Regs.BX := $4F50;

  FossilIntr(Regs);

  Com_OpenKeep := (Regs.AX = $1954);
  InitFailed := (Regs.AX <> $1954);
end; { func. Com_OpenKeep }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TFossilObj.Com_OpenQuick(Handle: Longint);
begin
  {-------------------------- Open the comport -----------------------------}
  FosPort := (Handle - 01);

  Regs.AH := $04;
  Regs.DX := FosPort;
  Regs.BX := $4F50;

  FossilIntr(Regs);
  InitFailed := (Regs.AX <> $1954);
end; { proc. Com_OpenQuick }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TFossilObj.Com_SetLine(BpsRate: longint; Parity: Char; DataBits, Stopbits: Byte);
var BPS: Byte;
begin
  if BpsRate > 65534 then
    BpsRate := 65534;

  Case Word(BpsRate) of { have to typecast to word, else will rte201 in dos }
    1200  : BPS := 128;
    2400  : BPS := 160;
    4800  : BPS := 192;
    9600  : BPS := 224;
    19200 : BPS := 0
     else BPS := 32;
   end; { case }

  if DataBits in [6..8] then
    BPS := BPS + (DataBits - 5);

  if Parity = 'O' then BPS := BPS + 8 else
   If Parity = 'E' then BPS := BPS + 24;

  if StopBits = 2 then BPS := BPS + 04;

  Regs.AH := $00;
  Regs.AL := BPS;
  Regs.DX := FosPort;
  FossilIntr(Regs);
end; { proc. TFossilObj.Com_SetLine }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function TFossilObj.Com_GetBPSrate: Longint;
begin
  Com_GetBpsRate := 115200;
end; { func. TFossilObj.Com_GetBpsRate }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TFossilObj.Com_Close;
begin
  if Dontclose then EXIT;

  Regs.AH := $05;
  Regs.DX := FosPort;
  FossilIntr(Regs);
end; { proc. TFossilObj.Com_Close }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function TFossilObj.Com_SendChar(C: Char): Boolean;
var Written: Longint;
begin
  Com_SendWait(C, SizeOf(c), Written, nil);

  Com_SendChar := (Written >= SizeOf(c));
end; { proc. TFossilObj.Com_SendChar }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function TFossilObj.Com_GetChar: Char;
begin
  Regs.AH := $02;
  Regs.DX := FosPort;
  FossilIntr(Regs);

  Com_GetChar := Chr(Regs.AL);
end; { proc. TFossilObj.Com_ReadChar }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TFossilObj.Com_ReadBlock(var Block; BlockLen: Longint; var Reads: Longint);
{$IFDEF GO32V2}
var Selector,
    Segment   : Word;
{$ENDIF}
begin
  {$IFDEF MSDOS}
    Regs.AH := $18;
    Regs.DX := FosPort;
    Regs.CX := Blocklen;
    Regs.ES := Seg(Block);
    Regs.DI := Ofs(Block);
    FossilIntr(Regs);

    Reads := Regs.AX;
  {$ENDIF}

  {$IFDEF GO32V2}
    DosAlloc(Selector, Segment, BlockLen);

    if Int31Error <> 0 then EXIT;
    DosmemPut(Segment, 0, Block, BlockLen);

    Regs.AH := $18;
    Regs.DX := FosPort;
    Regs.CX := Blocklen;
    Regs.ES := Segment;
    Regs.DI := 0;
    FossilIntr(Regs);

    Reads := Regs.AX;

    DosMemGet(Segment, 0, Block, BlockLen);
    DosFree(Selector);
  {$ENDIF}
end; { proc. TFossilObj.Com_ReadBlock }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TFossilObj.Com_SendBlock(var Block; BlockLen: Longint; var Written: Longint);
{$IFDEF GO32V2}
var Selector,
    Segment   : Word;
{$ENDIF}
begin
  {$IFDEF MSDOS}
    Regs.AH := $19;
    Regs.DX := FosPort;
    Regs.CX := Blocklen;
    Regs.ES := Seg(Block);
    Regs.DI := Ofs(Block);
    FossilIntr(Regs);

    Written := Regs.AX;
  {$ENDIF}

  {$IFDEF GO32V2}
    DosAlloc(Selector, Segment, BlockLen);

    if Int31Error <> 0 then EXIT;
    DosmemPut(Segment, 0, Block, BlockLen);

    Regs.AH := $19;
    Regs.DX := FosPort;
    Regs.CX := Blocklen;
    Regs.ES := Segment;
    Regs.DI := 0;
    FossilIntr(Regs);

    Written := Regs.AX;

    DosMemGet(Segment, 0, Block, BlockLen);
    DosFree(Selector);
  {$ENDIF}
end; { proc. TFossilObj.Com_SendBlock }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function TFossilObj.Com_CharAvail: Boolean;
begin
  Regs.AH := $03;
  Regs.DX := FosPort;
  FossilIntr(Regs);

  Com_CharAvail := (Regs.AH AND 01) <> 00;
end;  { func. TFossilObj.Com_CharAvail }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function  TFossilObj.Com_ReadyToSend(BlockLen: Longint): Boolean;
begin
  Regs.AH := $03;
  Regs.DX := FosPort;
  FossilIntr(Regs);

  Com_ReadyToSend := (Regs.AH AND $20) = $20;
end; { func. TFossilObj.Com_ReadyToSend }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function TFossilObj.Com_Carrier: Boolean;
begin
  Regs.AH := $03;
  Regs.DX := FosPort;
  FossilIntr(Regs);

  Com_Carrier := (Regs.AL AND 128) <> 00;
end; { func. TFossilObj.Com_Carrier }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TFossilObj.Com_SetDtr(State: Boolean);
begin
  Regs.AH := $06;
  Regs.AL := Byte(State);
  Regs.DX := Fosport;
  FossilIntr(Regs);
end; { proc. TFossilObj.Com_SetDtr }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TFossilObj.Com_GetModemStatus(var LineStatus, ModemStatus: Byte);
begin
  Regs.AH := $03;
  Regs.DX := FosPort;
  FossilIntr(Regs);

  ModemStatus := Regs.AL;
  LineStatus := Regs.AH;
end; { proc. TFossilObj.Com_GetModemStatus }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TFossilObj.Com_GetBufferStatus(var InFree, OutFree, InUsed, OutUsed: Longint);
type
  FosRec = record
    Size      : Word;
    Spec      : Byte;
    Rev       : Byte;
    ID        : Pointer;
    InSize    : Word;
    InFree    : Word;
    OutSize   : Word;
    OutFree   : Word;
    SWidth    : Byte;
    SHeight   : Byte;
    BaudMask  : Byte;
    Junk      : Word;
  end;

var Com_Info: FosRec;

    Selector,
    Segment : Word;
begin
  {$IFDEF MSDOS}
    Regs.AH := $1B;
    Regs.DX := FosPort;
    Regs.ES := Seg(Com_Info);
    Regs.DI := Ofs(Com_Info);
    Regs.CX := SizeOf(Com_Info);
  {$ENDIF}

  {$IFDEF GO32V2}
    DosAlloc(Selector, Segment, SizeOf(Com_Info));
    if Int31Error <> 0 then EXIT;

    DosmemPut(Segment, 0, Com_Info, SizeOf(Com_Info));

    Regs.AH := $1B;
    Regs.DX := FosPort;
    Regs.ES := Segment;
    Regs.DI := 0;
    Regs.CX := SizeOf(Com_Info);
    FossilIntr(Regs);

    DosMemGet(Segment, 0, Com_Info, SizeOf(Com_Info));
    DosFree(Selector);
  {$ENDIF}

  FossilIntr(Regs);

  InFree := Com_Info.InFree;
  InUsed := Com_Info.InSize - Com_Info.InFree;

  OutFree := Com_Info.OutFree;
  OutUsed := Com_Info.OutSize - Com_Info.OutFree;
end; { proc. TFossilObj.Com_GetBufferStatus }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function TFossilObj.Com_GetDriverInfo: String;
type
  FosRec = record
    Size      : Word;
    Spec      : Byte;
    Rev       : Byte;
    ID        : PChar;
    InSize    : Word;
    InFree    : Word;
    OutSize   : Word;
    OutFree   : Word;
    SWidth    : Byte;
    SHeight   : Byte;
    BaudMask  : Byte;
    Junk      : Word;
  end;

var Com_Info: FosRec;
    Segment,
    Selector: Word;
begin
  FillChar(Com_Info, SizeOf(FosRec), #00);

  {$IFDEF MSDOS}
    Regs.AH := $1B;
    Regs.DX := FosPort;
    Regs.ES := Seg(Com_Info);
    Regs.DI := Ofs(Com_Info);
    Regs.CX := SizeOf(Com_Info);
  {$ENDIF}

  {$IFDEF GO32V2}
    DosAlloc(Selector, Segment, SizeOf(Com_Info));
    if Int31Error <> 0 then EXIT;

    DosmemPut(Segment, 0, Com_Info, SizeOf(Com_Info));

    Regs.AH := $1B;
    Regs.DX := FosPort;
    Regs.ES := Segment;
    Regs.DI := 0;
    Regs.CX := SizeOf(Com_Info);
    FossilIntr(Regs);

    DosMemGet(Segment, 0, Com_Info, SizeOf(Com_Info));
    DosFree(Selector);
  {$ENDIF}

  FossilIntr(Regs);
  Com_GetDriverInfo := StrPas(Com_Info.ID);
end; { proc. TFossilObj.Com_GetDriverInfo }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TFossilObj.Com_PurgeInBuffer;
begin
  Regs.AH := $0A;
  Regs.DX := FosPort;

  FossilIntr(Regs);
end; { proc. TFossilObj.Com_PurgeInBuffer }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TFossilObj.Com_PurgeOutBuffer;
begin
  Regs.AH := $09;
  Regs.DX := FosPort;

  FossilIntr(Regs);
end; { proc. TFossilObj.Com_PurgeOutBuffer }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function TFossilObj.Com_GetHandle: longint;
begin
  Com_GetHandle := FosPort;
end; { func. Com_GetHandle }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TFossilObj.Com_SendWait(var Block; BlockLen: Longint; var Written: Longint; Slice: SliceProc);
var RestLen : Longint;
    Temp    : Array[0..(1024 * 50)] of Char ABSOLUTE Block;
    MaxTries: Longint;
begin
  RestLen := BlockLen;
  MaxTries := (Com_GetBpsRate div 8);

  repeat
    Com_SendBlock(Temp[BlockLen - RestLen], RestLen, Written);

    Dec(RestLen, Written);
    Dec(MaxTries);

    if RestLen <> 0 then
     if @Slice <> nil then
       Slice;
  until (RestLen <= 0) OR (NOT COM_Carrier) OR (MaxTries < 0);

  Written := (BlockLen - RestLen);
end; { proc. Com_SendWait }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TFossilObj.Com_SetFlow(SoftTX, SoftRX, Hard: Boolean);
begin
  Regs.AH := $0F;

  if SoftTX then
    Regs.AL := $01
     else Regs.AL := $00;

  if SoftRX then
    Regs.AL := Regs.AL OR $08;

  if Hard then
    Regs.AL := Regs.AL OR $02;

  Regs.DX := FosPort;
  FossilIntr(Regs);
end; { proc. Com_SetFlow }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

end.
