home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / modem / wxmodem.arc / WXMOPORT.INC < prev    next >
Text File  |  1986-10-30  |  12KB  |  322 lines

  1. {$U-,C-,I-,K-}
  2. type
  3.     tCport = (com1, com2);
  4.     tSaveInt = record                  {Save interrupt vector address}
  5.        IP :  integer;
  6.        CS :  integer;
  7.     end;
  8.     tRegs    = record                  {Dos registers}
  9.        AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags : integer;
  10.     end;
  11. Const
  12.      RECV_BUF_SIZE = 2048;             {this may be changed to
  13.                                         whatever size you need}
  14. { *** Port addresses *** }
  15.      cRBR: array[com1..com2] of integer = ($3F8,$2F8);
  16.                                        {Receive Buffer Register}
  17.      cTHR: array[com1..com2] of integer = ($3F8,$2F8);
  18.                                        {Transmitter Holding Register: the
  19.                                         serial port address we use to send
  20.                                         data}
  21.      cIER: array[com1..com2] of integer = ($3F9,$2F9);
  22.                                        {Interrupt Enable Register for the
  23.                                         serial port}
  24.      cLCR: array[com1..com2] of integer = ($3FB,$2FB);
  25.                                        {Line Control Register for the serial
  26.                                         port. Determines data bits, stop bits
  27.                                         and parity, contributes to setting
  28.                                         baud-rate}
  29.      cMCR: array[com1..com2] of integer = ($3FC,$2FC);
  30.                                        {Modem Control Register}
  31.      cLSR: array[com1..com2] of integer = ($3FD,$2FD);
  32.                                        {Line Status Register}
  33.      cMSR: array[com1..com2] of integer = ($3FE,$2FE);
  34.                                        {Modem Status Register}
  35.      IMR = $021;                       {Interrupt Mask Register port address
  36.                                         of Intel 8259A Programmable Interrupt
  37.                                         controller}
  38. { *** Masks *** }
  39.      ENABLE_OUT2 = 8;                  {Setting bit 3 of MCR enables OUT2}
  40.      ENABLE_DAV = 1;                   {Setting bit 0 of IER enables Data
  41.                                         AVailable interrupt from serial port}
  42.      ENABLE_IRQ: array[com1..com2] of integer = ($00EF,$00F7);
  43.                                        {Clearing bit of IMR enables serial
  44.                                         interrupts to reach the CPU}
  45.      DISABLE_OUT2 = 1;                 {Clearing MCR disables OUT2}
  46.      DISABLE_DAV = 0;                  {Clearing IER disables Data
  47.                                        AVailable interrupt from serial port}
  48.      DISABLE_IRQ: array[com1..com2] of integer = ($0010,$0008);
  49.                                        {Setting bit of IMR stops serial
  50.                                         interrupts from reaching the CPU}
  51.      cINVLIST: array[com1..com2] of integer = ($000C,$000B);
  52.                                        {Interrupt vector number}
  53.      SET_BAUD = $80;                   {Setting bit 7 of LCR allows us to set
  54.                                         the baud rate of the serial port}
  55.      SET_PARMS = $7F;                  {Clearing bit 7 of LCR allows us to set
  56.                                         non-baud-rate parameters on the
  57.                                         serial port}
  58. Type
  59.     parity_set        = (none,even);    {readability and expansion}
  60. Var
  61.    SaveInt                           : tSaveInt;
  62.    Regs                              : tRegs;
  63.    RBR, THR, IER, LCR, MCR, LSR, MSR : integer;
  64.    INVLIST                           : integer;
  65.    SavIER, SavLCR, SavMCR, SavIMR    : integer;
  66.    buf_start, buf_end    : integer;    {NOTE: these will change by them-
  67.                                         selves in the background}
  68.    recv_buffer           : array [1..RECV_BUF_SIZE] of byte;
  69.                                        {also self-changing}
  70.    speed                 : integer;    {I don't know the top speed these
  71.                                         routines will handle}
  72.    dbits                 : 7..8;       {only ones most people use}
  73.    stop_bits             : 1..2;       {does anyone use 2?}
  74.    parity                : parity_set;  {even and none are the common ones}
  75.    Cport                 : tCport;     {set at initialization}
  76.  
  77. function cgetc(TimeLimit : integer) : integer;
  78. {if a byte is recieved at COM1/COM2: in less than TimeLimit seconds,
  79.  returns byte as an integer, else returns -1}
  80. const
  81.      TIMED_OUT = -1;
  82. begin
  83.      TimeLimit := TimeLimit shl 10;     {convert TimeLimit to millisecs}
  84.      while (buf_start = buf_end) and (TimeLimit > 0) do
  85.      begin
  86.           delay(1);
  87.           TimeLimit := pred(TimeLimit)
  88.      end;
  89.      if (TimeLimit >= 0) and (buf_start <> buf_end) then
  90.      begin
  91.           inline ($FA);            {suspend interrupts}
  92.           cgetc := recv_buffer[buf_start];
  93.           buf_start := succ(buf_start);
  94.           if buf_start > RECV_BUF_SIZE then
  95.           buf_start := 1;
  96.           inline ($FB);            {resume interrupts}
  97.      end
  98.      else
  99.          cgetc := TIMED_OUT;
  100. end;
  101.  
  102. procedure send(c : byte);
  103. var
  104.    a : byte;
  105. begin
  106. {
  107.   repeat
  108.        a := port[LSR]
  109.   until odd(a shr 5);
  110.   port[THR] := c;
  111.  }
  112.   inline(
  113.      $8B/$16/LSR/   {in: mov dx,[LSR]}
  114.      $EC/               {in  al,dx}
  115.      $24/$20/           {and al,20}
  116.      $74/$F7/           {jz  in}
  117.      $8B/$16/THR/       {mov dx,[THR]}
  118.      $36/               {ss:}
  119.      $8B/$86/c/         {mov ax,[bp+c]}
  120.      $EE                {out dx,al}
  121.         );
  122. end;
  123.  
  124.  
  125. {Communications routines for TURBO Pascal written by Alan Bishop,
  126.  modified slightly by Scott Murphy.  Modified by Peter Boswell to
  127.  add COM2, saving the original interrupt vector, more inline code.
  128.  Handles standart COM1/COM2: ports with interrupt handling.  Includes
  129.  support for only one port, and with no overflow, parity, or other
  130.  such checking.  However, even some of the best communication programs
  131.  don't do this anyway, and I never use it.  If you make modifications,
  132.  please send me a copy if you have a simple way of doing it (CIS EMAIL,
  133.  Usenet, MCI Mail, etc)  Hope these are useful.
  134.  
  135. Alan Bishop - CIS      - 72405,647
  136.               Usenet   - bishop@ecsvax
  137.               MCI Mail - ABISHOP
  138. }
  139. procedure update_uart;
  140. {uses dbits, stop_bits, and parity}
  141. var
  142.    newparm, oldLCR : byte;
  143. begin
  144.  newparm := dbits-5;
  145.  if stop_bits = 2 then newparm := newparm + 4;
  146.  if parity = even then newparm := newparm + 24;
  147.  oldLCR := port[LCR];
  148.  port[LCR] := oldLCR and SET_PARMS;
  149.  port[LCR] := newparm;
  150. end;
  151.  
  152. procedure term_ready(state : boolean);
  153. {if state = TRUE then set RTS true else set false}
  154. var
  155.    OldMCR : byte;
  156. begin
  157.      OldMCR := port[MCR];
  158.      if state then
  159.         port[MCR] := OldMCR or 1
  160.      else
  161.          port[MCR] := OldMCR and $FE
  162. end;
  163.  
  164. function carrier : boolean;
  165. {true if carrier, false if not}
  166. begin
  167.  carrier := odd(port[MSR] shr 7);
  168. end;
  169.  
  170. procedure set_up_recv_buffer;
  171. begin
  172.  buf_start := 1;
  173.  buf_end   := 1;
  174. end;
  175.  
  176. procedure new_baud(rate : integer);
  177. {has no problems with non-standard bauds}
  178. var
  179.    OldLCR : byte;
  180. begin
  181.  if rate <= 9600 then
  182.  begin
  183.   speed := rate;
  184.   rate := trunc(115200.0/rate);
  185.   OldLCR := port[LCR] or SET_BAUD;
  186.   port[LCR] := OldLCR;
  187.   port[THR] := lo(rate);
  188.   port[IER] := hi(rate);
  189.   port[LCR] := OldLCR and SET_PARMS;
  190.  end;
  191. end;
  192.  
  193. procedure init_port;
  194. {installs interrupt sevice routine for serial port}
  195. var a,b : integer;
  196.     buf_len : integer;
  197. begin
  198.  RBR := cRBR[Cport];
  199.  THR := cTHR[Cport];
  200.  IER := cIER[Cport];
  201.  LCR := cLCR[Cport];
  202.  MCR := cMCR[Cport];
  203.  LSR := cLSR[Cport];
  204.  MSR := cMSR[Cport];
  205.  INVLIST := cINVLIST[Cport];
  206.  update_uart;
  207.  new_baud(speed);
  208.  buf_len := RECV_BUF_SIZE;
  209.  
  210.  {save the original vector}
  211.  
  212.  with Regs do begin
  213.    AX := $3500 + INVLIST;
  214.    MsDos(Regs);
  215.    SaveInt.CS := ES;
  216.    SaveInt.IP := BX;
  217.  end;
  218.  
  219.  {this is the background routine}
  220.  
  221.  inline (
  222.               $FA/                     {cli}
  223.               $1E/                     {push ds}
  224.               $0E/                     {push cs}
  225.               $A1/INVLIST/             {mov  ax,[INVLIST]   interrupt vector}
  226.               $1F/                     {pop  ds                  ;ds := cs}
  227.               $BA/*+22/                {mov  dx, offset ISR}
  228.               $B4/$25/                 {mov  ah,25H}
  229.               $CD/$21/                 {int  21H}
  230.               $8B/$BE/BUF_LEN/         {mov  di, buf_len}
  231.               $89/$3E/*+88/            {mov  lcl_buf_len,di}
  232.               $1F/                     {pop  ds}
  233.               $2E/$8C/$1E/*+84/        {mov  lcl_ds, ds}
  234.               $EB/$52/                 {jmp  exit}
  235. {ISR:}        $1E/                     {push ds}
  236.               $50/                     {push ax}
  237.               $53/                     {push bx}
  238.               $52/                     {push dx}
  239.               $56/                     {push si}
  240.               $FB/                     {sti}
  241.               $2E/$8E/$1E/*+71/        {mov  ds,[lcl_ds]}
  242.               $8B/$16/RBR/             {mov  dx,[RBR] 3F8H/2F8H ;address RBR}
  243.               $EC/                     {in   al, dx             ;read rbr}
  244.               $BE/RECV_BUFFER/         {mov  si, recv_buffer    ;address start of recv_buffer}
  245.               $8B/$1E/BUF_END/         {mov  bx, [buf_end]      ;index of current char in recv_buffer}
  246.               $88/$40/$FF/             {mov  [bx+si-1],al       ;copy char to recv_buffer}
  247.               $43/                     {inc  bx                 ;update buf_end}
  248.               $E8/$22/$00/             {call adj_idx}
  249.               $89/$1E/BUF_END/         {mov  [buf_end],bx}
  250.               $3B/$1E/BUF_START/       {cmp  bx, [buf_start]}
  251.               $75/$0C/                 {jnz  ISR_DONE}
  252.               $8B/$1E/BUF_START/       {mov  bx,buf_start}
  253.               $43/                     {inc  bx}
  254.               $E8/$10/$00/             {call adj_idx}
  255.               $89/$1E/BUF_START/       {mov  [buf_start],bx}
  256.               $BA/$20/$00/             {mov  dx,20H            ;EOI command for 8259A PIC}
  257.               $B0/$20/                 {mov  al,20H            ;EOI port for 8259A PIC}
  258.               $EE/                     {out  dx,al             ;End Of Interrupt}
  259.               $5E/                     {pop  si}
  260.               $5A/                     {pop  dx}
  261.               $5B/                     {pop  bx}
  262.               $58/                     {pop  ax}
  263.               $1F/                     {pop  ds}
  264.               $CF/                     {iret}
  265. {adj_idx:}    $2E/$8B/$16/*+11/        {mov  dx,[lcl_buf_len]}
  266.               $42/                     {inc  dx}
  267.               $39/$DA/                 {cmp  dx,bx}
  268.               $75/$03/                 {jnz  no_change}
  269.               $BB/$01/$00/             {mov  bx,1}
  270. {no_change:}  $C3/                     {ret}
  271. {lcl_buf_len;}$00/$00/                 {dw  0}
  272.               $00/$01/                 {dw  1}
  273. {exit:}       $90/                     {nop}
  274.               $FB                      {cli}
  275.  );
  276.  SavLCR    := port[LCR];
  277.  SavIER    := port[IER];
  278.  port[IER] := ENABLE_DAV;              {interrupt enable}
  279.  a         := port[MCR];
  280.  SavMCR    := a;
  281.  port[MCR] := a or ENABLE_OUT2;        {preserve RTS and enable OUT2}
  282.  a         := port[IMR];
  283.  SavIMR    := a;
  284.  a         := a and ENABLE_IRQ[Cport];
  285.  port[IMR] := a;
  286. end;
  287.  
  288.  
  289. procedure remove_port;
  290. {Restores status to reflect the status upon entry}
  291. var
  292.    a : byte;
  293. begin
  294.      inline($FA);                     {disable interrupts}
  295.      port[IMR] := SavIMR;
  296.      port[IER] := SavIER;
  297.      port[MCR] := SavMCR;
  298.      port[LCR] := SavLCR;
  299.  
  300.      {Restore the interrupt vector}
  301.      with Regs do begin
  302.         AX := $2500 + INVLIST;        {function 25H & INVLIST port}
  303.         DS := SaveInt.CS;
  304.         DX := SaveInt.IP;
  305.         MsDos(Regs);
  306.      end;
  307.      inline($FB);
  308. end;
  309.  
  310.  
  311. procedure break;
  312. {send a break}
  313. var a,b : byte;
  314. begin
  315.  a := port[LCR];
  316.  b := (a and $7F) or $40;
  317.  port[LCR] := b;
  318.  delay(750);
  319.  port[LCR] := a;
  320. end;
  321.  
  322.