                                 Unit RS232Dos;

                                 INTERFACE

{$N+}

{Тип для преобразования последовательности байт}
{в число типа Single и обратно                 }
Type UFloat = packed record
  b : Array [0..3] of Byte;
 End;

{Инициализация порта с номером ComIndex                     }
{ ComIndex - номер порта                                    }
{ Speed     - скорость в бод                                }
{ Params   - конфигурация порта, согласно формату битов LCR }
{Возвращает False, если порт не обнаружен                   }
Function InitCOM(ComIndex : Byte; Speed : Longint; Params : Byte) : Boolean;

{Чтение байта с порта с тайм-аутом                          }
{ B    - прочитанный байт                                   }
{ Wait - время ожидания байта                               }
{Возвращает True, если байт реально прочитан                }
Function  ReadData(var B : Byte; Wait : LongInt): Boolean;
{Запись байта в порта с тайм-аутом                      }
{ B    - передаваемый байт                              }
{ Wait - время ожидания готовности передатчика          }
{Возвращает True, если байт передан                       }
Function  WriteData(B : Byte; Wait : LongInt): Boolean;


Function  CheckReadData(ChB : Byte; Wait : LongInt) : Boolean;
Function  ReadSingle(var S : Single; WD : LongInt) : Boolean;
Procedure CloseCOM;

                               IMPLEMENTATION


Var { Будет хранить базовый адрес порта }
 BaseAdr : Word;

 { Возвращает базовый адрес порта с номером PortIndex }
 Function GetBaseAdr(PortIndex : Byte) : Word;
 Var LowAdr : Word;
 Begin
  { вычисляем младшую часть адреса в таблице }
  LowAdr := (PortIndex-1)*2;
  { получаем базовый адрес порта из таблицы }
  GetBaseAdr:= MemW[$0040:LowAdr];
 End;

 {Инициализация порта}
 Function InitCOM(ComIndex : Byte; Speed : Longint; Params : Byte) : Boolean;
 Var Freq : Word; FreqH, FreqL : Byte;
 begin
  Freq := 115200 div Speed;
  FreqH:= Freq shr 8;
  FreqL:= Freq and $00FF;

  InitCOM:= True;
  { Вычисляем базовый адрес порта }
  BaseAdr:= GetBaseAdr(ComIndex);
  If BaseAdr = 0 then begin
   WriteLn('Порт ', ComIndex,' не обнаружен!');
   InitCOM:= False; {вернем ошибку}
   Exit;
  End;
  {Адресуем делитель порта с помощью установки DLAB=1}
  Port[BaseAdr+3]:= $80;
  {Устанавливаем младшую часть делителя}
  Port[BaseAdr+0]:= FreqL;
  {Устанавливаем старшую часть делителя}
  Port[BaseAdr+1]:= FreqH;
  {Сбрасываем DLAB и прописываем конфигурацию}
  Port[BaseAdr+3]:= Params;
 end;

 {Определение готовности}
 Function GetSR : Boolean; assembler;
 Asm
  Mov Dx, BaseAdr
  Add Dx, 5
  In  Al, Dx
  And Al, 20H
 End;


 {Чтение байта с порта}
 Function ReadCOM : Byte; assembler;
 Asm
  Mov Dx, BaseAdr
  In  Al, Dx
 End;

 {Передача байта в порт}
 Procedure WriteCOM(B : Byte); assembler;
 Asm
  Mov Dx, BaseAdr
  Mov Al, B
  Out Dx, Al
 End;

 { Возвращает бит DR порта LSR }
 Function GetDR : Boolean; assembler;
 Asm
  Mov Dx, BaseAdr
  Add Dx, 5
  In  Al, Dx
  And Al, 1
 End;

 {Возвращает биты ошибок порта LSR          }
 { Бит 4 - обрыв линии                      }
 { Бит 3 - ошибка кадра (неверный стоп-бит) }
 { Бит 2 - ошибка четности                  }
 { Бит 1 - переполнение (потеря символа)    }
 Function GetErr : Byte; assembler;
 Asm
  Mov Dx, BaseAdr
  Add Dx, 5
  In  Al, Dx
  And Al, 1EH {0001 1110b}
 End;

 {Чтение байта с порта с ожиданием готовности порта}
 Function ReadData(var B : Byte; Wait : LongInt): Boolean;
 Var Result : Boolean; w : LongInt;
 Begin
  w:= 0; Result:= False;
  For w:= 1 to Wait do begin {ожидание...}
   If GetDR then begin {проверяем доступность данных }
    B:= ReadCOM; {читаем байт с порта}
    Result:= (GetErr = 0); {проверяем код ошибки}
    Break;
   End;
  End;
  ReadData:= Result;
 End;

 {Возвращает true, если байт прочитан и равен ChB }
 Function CheckReadData(ChB : Byte; Wait : LongInt) : Boolean;
 Var B : Byte;
 Begin
  CheckReadData:= False;
  If ReadData(B, Wait) then begin
   CheckReadData:= (B = ChB);
  End;
 End;

 {Передает байт в порт с ожиданием готовности}
 Function WriteData(B : Byte; Wait : LongInt): Boolean;
 Var Result : Boolean; w : LongInt;
 Begin
  w:= 0; Result:= False;
  For w:= 1 to Wait do begin {ожидание...}
   If GetSR then begin {передатчик готов?}
    WriteCOM(B); {передаем байт}
    Result:= True;
    Break;
   End;
  End;
  WriteData:= Result;
 End;

 {Чтение числа с плавающей точкой (тип single) }
 Function  ReadSingle(var S : Single; WD : LongInt) : Boolean;
 Var F : UFloat; R : Single;
 Begin
  S:= 0.00; ReadSingle:= False;
  If ReadData(F.b[3], WD) then
   If ReadData(F.b[2], WD) then
    If ReadData(F.b[1], WD) then
     If ReadData(F.b[0], WD) then begin
      Move(F, S, 4);
      ReadSingle:= True;
     End;
 End;

 {"Закрытие" порта }
 Procedure CloseCOM;
 Begin
  WriteCOM($0FF);
 End;

END.
