home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / ECO30603.ZIP / ECO30603.LZH / ECOLIBBS / ECO_ASYN.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-09-20  |  100.2 KB  |  1,737 lines

  1. (*
  2.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  3.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  4.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  5.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  6.     ▓▓▓▓▓▓▓▓·──                                              ──·▓▓▓▓▓▓▓▓▓▓▓
  7.     ▓▓▓▓▓▓▓▓│                                                  │░░▓▓▓▓▓▓▓▓▓
  8.     ▓▓▓▓▓▓▓▓   Unit was Reconceived, Redesigned and Rewritten   ░░▓▓▓▓▓▓▓▓▓
  9.     ▓▓▓▓▓▓▓▓   by Floor A.C. Naaijkens for                      ░░▓▓▓▓▓▓▓▓▓
  10.     ▓▓▓▓▓▓▓▓   UltiHouse Software / The ECO Group.              ░░▓▓▓▓▓▓▓▓▓
  11.     ▓▓▓▓▓▓▓▓                                                    ░░▓▓▓▓▓▓▓▓▓
  12.     ▓▓▓▓▓▓▓▓   MCMXCII by EUROCON PANATIONAL CORPORATION.       ░░▓▓▓▓▓▓▓▓▓
  13.     ▓▓▓▓▓▓▓▓   All Rights Reserved for The ECO Group.           ░░▓▓▓▓▓▓▓▓▓
  14.     ▓▓▓▓▓▓▓▓│                                                  │░░▓▓▓▓▓▓▓▓▓
  15.     ▓▓▓▓▓▓▓▓·──                                              ──·░░▓▓▓▓▓▓▓▓▓
  16.     ▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓▓▓▓▓
  17.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  18.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  19.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  20.  
  21.  
  22.   ┌───────────────────────────────────────────────────────────────────────┐
  23.   │          ECO_ASYN   ───   Asynchronous I/O for TurboPascal            │
  24.   ├───────────────────────────────────────────────────────────────────────┤
  25.   │                                                                       │
  26.   │  routines:                                                            │
  27.   │                                                                       │
  28.   │     bios_rs232_init        ───    use bios to initialize port         │
  29.   │     async_isr              ───    com port interrupt service routine  │
  30.   │     async_init             ───    performs initialization.            │
  31.   │     async_clear_errors     ───    clear pending serial port errors    │
  32.   │     async_reset_port       ───    resets uart parameters for port     │
  33.   │     async_open             ───    sets up com port                    │
  34.   │     async_close            ───    closes down com port                │
  35.   │     async_carrier_detect   ───    checks for modem carrier detect     │
  36.   │     async_carrier_drop     ───    checks for modem carrier drop       │
  37.   │     async_buffer_check     ───    checks if character in com buffer   │
  38.   │     async_term_ready       ───    toggles terminal ready status       │
  39.   │     async_find_delay       ───    find busy wait count for 1ms delay  │
  40.   │     async_receive          ───    reads character from com buffer     │
  41.   │     async_receive_with_timeout                                        │
  42.   │                            ───    receives char. with timeout check   │
  43.   │     async_ring_detect      ───    if ringing detected                 │
  44.   │     async_send             ───    transmits char over com port        │
  45.   │     async_send_string      ───    sends string over com port          │
  46.   │     async_send_string_with_delays                                     │
  47.   │                            ───    sends string with timed delays      │
  48.   │     async_send_break       ───    sends break (attention) signal      │
  49.   │     async_percentage_used  ───    returns percentage com buffer used  │
  50.   │     async_purge_buffer     ───    purges receive buffer               │
  51.   │     async_release_buffers  ───    free memory for serial port queues  │
  52.   │     async_setup_port       ───    define port base, irq, rs232 addr   │
  53.   │     async_stuff            ───    insert char into receive buffer     │
  54.   │     async_flush_output_buffer                                         │
  55.   │                            ───    flush serial port output buffer     │
  56.   │     async_drain_output_buffer                                         │
  57.   │                            ───    wait for serial output to drain     │
  58.   │     async_port_address_given                                          │
  59.   │                            ───    check if port address installed     │
  60.   │     async_send_now         ───    send character without buffering    │
  61.   │     async_wait_for_quiet   ───    wait for port to quiesce            │
  62.   │                                                                       │
  63.   ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤
  64.   │                                                                       │
  65.   │ 1]  set_params             ───    set the parameters, requested by    │
  66.   │                                   your program                        │
  67.   │ 2]  initialize_modem       ───    initialize the modem, using params  │
  68.   │ 3]  send_modem_command     ───    send a commandstring to the modem   │
  69.   │                                                                       │
  70.   └───────────────────────────────────────────────────────────────────────┘
  71.  
  72.  
  73.   Floor Naaijkens, 28-2-1990, MCMXCII
  74. *)
  75.  
  76. unit eco_asyn;
  77. interface
  78. uses
  79.   dos, crt
  80.  
  81.   ;
  82.  
  83.  
  84. const { 8086/8088 hardware flags }
  85.   ff   =  12; { form feed       }   cr   =  13; { carriage return }
  86.   dle  =  16; { data link esc.  }   xon  =  17; { xon             }
  87.   xoff =  19; { xoff            }   sub  =  26; { end of file     }
  88.   esc  =  27; { escape          }   del  = 127; { delete          }
  89.   fk_cr          :       char =  '|'; { function key definition cr        }
  90.   fk_delay       :       char =  '~'; { function key def. 1 second wait   }
  91.   fk_wait_for    :       char =  '`'; { function key wait for next char   }
  92.   fk_ctrl_mark   :       char =  '^'; { marks next char as ctrl character }
  93.   fk_script_ch   :       char =  '@'; { script to execute follows         }
  94.   fk_delay_time  :    integer =   10; { delay to insert between each char }
  95.   bs_string      :     string =   ^h; { string to send when back space hit}
  96.   ctrl_bs_string :     string = #127; { string to send when ctrl bs hit   }
  97.  
  98.   half_second_delay       =  500;    one_second_delay        = 1000;
  99.   two_second_delay        = 2000;    three_second_delay      = 3000;
  100.   tenth_of_a_second_delay =  100;    on   = true; off  = false;
  101.  
  102.   data_bits     : 5..8 = 8;          parity        : char = 'N';
  103.   stop_bits     : 0..2 = 1;          comm_port     : 1..4 = 1;
  104.   baud_rate     : 110..38400 = 2400; cmd_line_port : 0..4 = 0;
  105.  
  106.   n_baud_rates = 11;
  107.   baud_rates: array[ 1 .. n_baud_rates ] of word = (
  108.     110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600
  109.   );
  110.  
  111.   modem_init          : string   = 'ATZ|~ATX1|';
  112.   modem_dial          : string[30] = 'ATDT';
  113.   modem_dial_end      : string[30] = '|';
  114.   modem_busy          : string[30] = 'BUSY';
  115.   modem_connect       : string[30] = 'CONNECT';
  116.   modem_no_carrier    : string[30] = 'NO CARRIER';
  117.   modem_escape        : string[30] = '+++';
  118.   modem_escape_time   : integer  = 1500;
  119.   modem_hang_up       : string[30] = 'ATH0|';
  120.   modem_time_out      : longint  = 60;
  121.   modem_redial_delay  : longint  = 45;
  122.   modem_answer        : string[30] = 'ATA|';
  123.   modem_host_set      : string   = 'ATZ|~ATX1|~ATS0=1|';
  124.   modem_host_unset    : string   = 'ATZ|~ATX1|~ATS0=0|';
  125.   modem_command_delay : integer  = 10;
  126.   modem_carrier_high  : boolean  = false;
  127.   modem_ring          : string[30] = 'RING';
  128.   host_auto_baud      : boolean  = true;
  129.   modem_hold_line     : boolean  = false;
  130.  
  131.   {               communications hardware addresses                   }
  132.   {     these are specific to IBM PCs and Close compatibles.          }
  133.   uart_thr = $00;       { offset from base of uart registers for ibm pc }
  134.   uart_rbr = $00; uart_ier = $01; uart_iir = $02; uart_lcr = $03;
  135.   uart_mcr = $04; uart_lsr = $05; uart_msr = $06;
  136.  
  137.   i8088_imr = $21;      { port address of the interrupt mask register }
  138.  
  139.   com1_base = $03f8;    { port addresses for the uart }
  140.   com2_base = $02f8; com3_base = $03e8; com4_base = $02e8;
  141.   com1_irq = 4;         { interrupt line for the uart }
  142.   com2_irq = 3; com3_irq = 4; com4_irq = 3;
  143.   com1_int = $0c;       { interrupt number for the uart }
  144.   com2_int = $0b; com3_int = $0c; com4_int = $0b;
  145.  
  146.   rs232_base = $0400    { address of rs 232 com port pointer };
  147.   maxcomports = 4       { four ports allowed by this code    };
  148.                                   { port addresses of each com port }
  149.   default_com_base : array[1..maxcomports] of word =
  150.     ( com1_base, com2_base, com3_base, com4_base );
  151.                                   { irq line for each port }
  152.   default_com_irq  : array[1..maxcomports] of integer =
  153.     ( com1_irq, com2_irq, com3_irq, com4_irq );
  154.                                   { interrupt for each port }
  155.   default_com_int  : array[1..maxcomports] of integer =
  156.     ( com1_int, com2_int, com3_int, com4_int );
  157.  
  158.   {───────────────────────────────────────────────────────────────────────────}
  159.   {                                                                           }
  160.   {                    communications buffer variables                        }
  161.   {                                                                           }
  162.   {      the communications buffers are implemented as circular (ring)        }
  163.   {      buffers, or double-ended queues.  the asynchronous i/o routines      }
  164.   {      enter characters in the receive buffer as they arrive at the         }
  165.   {      serial port.  higher-level routines may extract characters from      }
  166.   {      the receive buffer at leisure.  higher-level routines insert         }
  167.   {      characters into the send buffer.  the asynchronous i/o routines      }
  168.   {      then send characters out the serial port when possible.              }
  169.   {                                                                           }
  170.   {───────────────────────────────────────────────────────────────────────────}
  171.  
  172.   timeout             = 256;          { timeout value                         }
  173.   async_xon           =  ^Q;          { xon character                         }
  174.   async_xoff          =  ^S;          { xoff character                        }
  175.   async_overrun_error =   2;          {   overrun                             }
  176.   async_parity_error  =   4;          {   parity error                        }
  177.   async_framing_error =   8;          {   framing error                       }
  178.   async_break_found   =  16;          {   break interrupt                     }
  179.   async_cts           = $10;          {   clear to send                       }
  180.   async_rts           = $20;          {   request to send                     }
  181.   async_dsr           = $20;          {   data set ready                      }
  182.   async_dtr           = $10;          {   data terminal ready                 }
  183.   async_rtsdtr        = $30;          {   rts + dtr                           }
  184.  
  185.  
  186. type                                  { i/o buffer type for serial port       }
  187.   async_buffer_type = array[0..1] of char;
  188.   async_ptr         = ^async_buffer_type;
  189.  
  190. var                                   { port addresses for serial ports       }
  191.   com_base               : array[1..maxcomports] of word;
  192.                                       { irq line for each serial port         }
  193.   com_irq                : array[1..maxcomports] of integer;
  194.                                       { interrupt for each serial port        }
  195.   com_int                : array[1..maxcomports] of integer;
  196.   async_buffer_ptr       : async_ptr; { input buffer address                  }
  197.   async_obuffer_ptr      : async_ptr; { output buffer address                 }
  198.   async_open_flag        :   boolean; { true if port opened                   }
  199.   async_port             :   integer; { current open port number (1 ── 4)     }
  200.   async_base             :   integer; { base for current open port            }
  201.   async_irq              :   integer; { irq for current open port             }
  202.   async_int              :   integer; { interrupt # for current port          }
  203.   async_rs232            :   integer; { rs232 address for current port        }
  204.   async_buffer_overflow  :   boolean; { true if buffer overflow's happened    }
  205.   async_buffer_used      :   integer; { amount of input buffer used so far    }
  206.   async_maxbufferused    :   integer; { maximum amount of input buffer used   }
  207.                                       { async_buffer empty if head = tail     }
  208.   async_buffer_head      :   integer; { loc in async_buf to put next char     }
  209.   async_buffer_tail      :   integer; { loc in async_buf to get next char     }
  210.   async_buffer_newtail   :   integer; { for updating tail value               }
  211.   async_obuffer_overflow :   boolean; { true if buffer overflow's happened    }
  212.   async_obuffer_used     :   integer; { amount of output buffer used          }
  213.   async_maxobufferused   :   integer; { max amount of output buffer used      }
  214.                                       { async_buffer empty if head = tail     }
  215.   async_obuffer_head     :   integer; { loc in async_buf to put next char     }
  216.   async_obuffer_tail     :   integer; { loc in async_buf to get next char     }
  217.   async_obuffer_newtail  :   integer; { for updating tail value               }
  218.   async_buffer_low       :   integer; { low point in receive buffer for xon   }
  219.   async_buffer_high      :   integer; { high point in rec'buffer for xoff     }
  220.   async_buffer_high_2    :   integer; { emergency point for xoff              }
  221.   async_xoff_sent        :   boolean; { if xoff sent                          }
  222.   async_sender_on        :   boolean; { if sender is enabled                  }
  223.   async_send_xoff        :   boolean; { true to send xoff asap                }
  224.   async_xoff_received    :   boolean; { if xoff received                      }
  225.   async_xoff_rec_display :   boolean; { if xoff received and displayed        }
  226.   async_xon_rec_display  :   boolean; { if xon received                       }
  227.   async_baud_rate        :      word; { current baud rate                     }
  228.                                       { save prev serial interrupt status     }
  229.   async_save_iaddr       :   pointer;
  230.   async_do_cts           :   boolean; { true to do clear-to-send checking     }
  231.   async_do_dsr           :   boolean; { true to do data-set-ready checking    }
  232.   async_do_xonxoff       :   boolean; { true to do xon/xoff flow checking     }
  233.   async_ov_xonxoff       :   boolean; { true to do xon/xoff if buf overflow   }
  234.   async_hard_wired_on    :   boolean; { true if hard-wired connection         }
  235.   async_break_length     :   integer; { length of break in 1/10 seconds       }
  236.   async_line_status      :      byte; { line status reg at interrupt          }
  237.   async_modem_status     :      byte; { modem status reg at interrupt         }
  238.   async_line_error_flags :      byte; { line status bits accumulated          }
  239.   async_buffer_size      :   integer; { stores input buffer size              }
  240.   async_obuffer_size     :   integer; { stores output buffer size             }
  241.   async_uart_ier         :   integer; { interrupt enable register address     }
  242.   async_uart_mcr         :   integer; { interrupt enable register address     }
  243.   async_uart_iir         :   integer; { interrupt id register address         }
  244.   async_uart_msr         :   integer; { modem status register address         }
  245.   async_uart_lsr         :   integer; { line status register address          }
  246.   async_output_delay     :   integer; { delay in ms when output buffer full   }
  247.   async_onemsdelay       :   integer; { loop count value to effect 1 ms delay }
  248.   async_buffer_length    :   integer; { receive buffer length                 }
  249.   async_obuffer_length   :   integer; { send buffer length                    }
  250.                                       { pointer to async_send routine         }
  251.   async_send_addr        : async_ptr;
  252.   break_length           :   integer;
  253.   current_carrier_status,
  254.   new_carrier_status,
  255.   attended_mode,
  256.   hard_wired,
  257.   reset_comm_port,
  258.   comm_port_changed,
  259.   check_cts,check_dsr,
  260.   do_xon_xoff_checks     :   boolean;
  261.  
  262.  
  263.  
  264.   {──────────────────────────────────────────────────────────────────────}
  265.   {                       multitasker definitions                        }
  266.   {──────────────────────────────────────────────────────────────────────}
  267.  
  268. type
  269.   multitaskertype = (
  270.     multitasker_none, doubledos, desqview, topview,
  271.     mswindows, apxcore, ezdosit, concurrent_dos,
  272.     taskview, multilink, other
  273.   );
  274.  
  275.  
  276. var
  277.   timesharingactive: boolean;    { true if multitasker active        }
  278.                                  { which multitasker active          }
  279.   multitasker: multitaskertype;
  280.  
  281.  
  282.   {──────────────────────────────────────────────────────────────────────}
  283.   {              dos jump stuff                                          }
  284.   {──────────────────────────────────────────────────────────────────────}
  285. {var}const
  286.   heaptop           : pointer = nil   { top of heap at program start       };
  287.   stacksafetymargin : word    = 1000  { safety margin for stack            };
  288.   minspacefordos    : word    = 20000 { minimum bytes for dos shell to run };
  289.  
  290.  
  291.   procedure bios_rs232_init(comport: integer; comparm: word);
  292.   procedure async_close(drop_dtr: boolean);
  293.   procedure async_clear_errors;
  294.   procedure async_reset_port(
  295.     comport  : integer;
  296.     baudrate : word;
  297.     parity   : char;
  298.     wordsize : integer;
  299.     stopbits : integer
  300.   );
  301.   function  async_open(
  302.     comport  : integer;
  303.     baudrate : word;
  304.     parity   : char;
  305.     wordsize : integer;
  306.     stopbits : integer
  307.   ): boolean;
  308.   procedure async_send(c: char);
  309.   function async_receive(var c: char): boolean;
  310.   procedure async_receive_with_timeout(secs: integer; var c: integer);
  311.   procedure async_stuff(ch: char);
  312.   procedure async_find_delay(var one_ms_delay: integer);
  313.   procedure async_init(
  314.     async_buffer_max : integer;
  315.     async_obuffer_max: integer;
  316.     async_high_lev1  : integer;
  317.     async_high_lev2  : integer;
  318.     async_low_lev    : integer
  319.   );
  320.   function  async_carrier_detect: boolean;
  321.   function  async_carrier_drop: boolean;
  322.   procedure async_term_ready(ready_status: boolean);
  323.   function  async_buffer_check: boolean;
  324.   function  async_line_error(var error_flags: byte): boolean;
  325.   function  async_ring_detect: boolean;
  326.   procedure async_send_break;
  327.   procedure async_send_string(s: string);
  328.   procedure async_send_string_with_delays(
  329.     s          : string;
  330.     char_delay : integer;
  331.     eos_delay  : integer
  332.   );
  333.   function  async_percentage_used: real;
  334.   procedure async_purge_buffer;
  335.   function  async_peek(nchars: integer): char;
  336.   procedure async_setup_port(
  337.     comport      : integer;
  338.     base_address : integer;
  339.     irq_line     : integer;
  340.     int_numb     : integer
  341.   );
  342.   procedure async_release_buffers;
  343.   procedure async_flush_output_buffer;
  344.   procedure async_drain_output_buffer(max_wait_time: integer);
  345.   function  async_port_address_given(com_port: integer): boolean;
  346.   procedure async_send_now(c: char);
  347.   function  async_wait_for_quiet(
  348.     max_wait: longint; wait_time: longint
  349.   ): boolean;
  350.   { --- }
  351.   procedure send_modem_command(modem_text: string);
  352.   function  set_params(first_time: boolean): boolean;
  353.   procedure initialize_modem;
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361. implementation
  362.  
  363.  
  364.  
  365.  
  366. { ensure multitasking defined }
  367. {$DEFINE MTASK}
  368. { multitasker interface routines }
  369.  
  370.  
  371.  
  372.  
  373.   function isnovellactive: boolean;
  374.   var regs: registers;
  375.   begin { isnovellactive }
  376.     regs.cx := 0; regs.al := 0;
  377.     { request workstation id. this should be ignored if novell }
  378.     { network software isn't active.   }
  379.     regs.ah := $dc;  msdos(regs);
  380.     { if we got back a non-zero station id, then novell must be loaded.  }
  381.     isnovellactive := (regs.al <> 0);
  382.   end;
  383.  
  384.  
  385.  
  386.   procedure turnontimesharing;
  387.   var regs: registers;
  388.   begin { turnontimesharing }
  389.     case multitasker of
  390.       { if ddos is active, $eb turns on timesharing }
  391.       doubledos: begin
  392.         regs.ax := $eb00;
  393.         msdos(regs)
  394.       end; { int 15h for topview family products }
  395.       desqview,topview,mswindows,
  396.       taskview: begin regs.ax := $101c; intr($15, regs) end; else;
  397.     end { case };
  398.   end;
  399.  
  400.  
  401.  
  402.   procedure turnofftimesharing;
  403.   var regs: registers;
  404.   begin
  405.     case multitasker of
  406.       { if ddos is active, $ea suspends timesharing }
  407.       doubledos: begin
  408.         regs.ax := $ea00;
  409.         msdos(regs)
  410.       end; { int 15h for topview family products }
  411.       desqview, topview, mswindows,
  412.       taskview: begin regs.ax := $101b; intr($15 , regs) end; else;
  413.     end { case };
  414.   end;
  415.  
  416.  
  417.  
  418.   procedure giveuptime(nslices: integer);
  419.   {    purpose:    gives away time slices to other tasks                 }
  420.   {    calling sequence:                                                 }
  421.   {          nslices ─── # of slices (55 ms) to give away, if doubledos. }
  422.   var regs: registers;
  423.   begin { giveuptime }
  424.     if (timesharingactive and (nslices > 0)) then case multitasker of
  425.       doubledos: begin
  426.         regs.ah := $ee;
  427.         regs.al := nslices;
  428.         msdos(regs);
  429.       end; { function ee gives time to other part. }
  430.       desqview, topview, mswindows,
  431.       taskview: begin
  432.         inline(
  433.           $b8/$00/$10 { mov ax,$1000; give up time}
  434.           /$cd/$15    { int $15}
  435.         );
  436.       end; else;
  437.     end;
  438.   end;
  439.  
  440.  
  441.  
  442.  
  443.   function timeofday: longint;
  444.   var
  445.    hours,
  446.    minutes,
  447.    seconds,
  448.    sechun   :   word;
  449.    timeval  : longint;
  450.  
  451.   begin
  452.     gettime(hours, minutes, seconds, sechun);
  453.     timeval := hours; timeofday := timeval * 3600 + minutes * 60 + seconds;
  454.   end;
  455.  
  456.  
  457.  
  458.  
  459.   function timediff(timer1, timer2: longint): longint;
  460.   const secs_per_day = 86400    { seconds in one day };
  461.   var tdiff: longint;
  462.   begin { timediff }
  463.     tdiff := timer2 - timer1;
  464.     if (tdiff < 0) then tdiff := tdiff + secs_per_day;
  465.     timediff := tdiff;
  466.   end;
  467.  
  468.  
  469.  
  470.  
  471.   function timeofdayh: longint;
  472.   var
  473.     hours, minutes,
  474.     seconds, sechun :    word;
  475.     timerval        : longint;
  476.  
  477.   begin
  478.     gettime(hours, minutes, seconds, sechun); timerval := hours;
  479.     timeofdayh := timerval * 360000 + minutes * 6000 + seconds * 100 + sechun;
  480.   end;
  481.  
  482.  
  483.  
  484.  
  485.   function timediffh(timer1, timer2: longint): longint;
  486.   const hundredths_secs_per_day = 8640000    { 1/100 seconds in one day };
  487.   var tdiff: longint;
  488.   begin { timediffh }
  489.     tdiff := timer2 - timer1;
  490.     if tdiff < 0 then tdiff := tdiff + hundredths_secs_per_day;
  491.     timediffh := tdiff;
  492.   end;
  493.  
  494.  
  495. {$DEFINE MTASK}
  496.   procedure bios_rs232_init(comport: integer; comparm: word);
  497.   var regs: registers;
  498.   begin   { bios_rs232_init }
  499.     with regs do begin { initialize port }
  500.       ax := comparm and $00ff;  { ah=0; al=comparm   }
  501.       dx := comport;            { port number to use } intr($14, regs);
  502.     end;
  503.   end;
  504.  
  505.  
  506.  
  507.   procedure async_isr(
  508.     flags, cs, ip, ax, bx, cx, dx, si, di, ds, es, bp: word
  509.   ); interrupt;
  510.   begin
  511.     inline(
  512.       $fb/                             {  sti                                       ;allow interrupts                  }
  513.                                        {  begin major polling loop over pending interrupts.                            }
  514.                                        {  the polling loop is needed because the 8259 cannot handle another 8250       }
  515.                                        {  interrupt while we service this interrupt.  we keep polling here as long     }
  516.                                        {  as an interrupt is received.                                                 }
  517.       $8b/$16/>async_uart_iir/         {poll:    mov     dx,[>async_uart_iir]       ;get interrupt ident register      }
  518.       $ec/                             {         in      al,dx                      ;pick up interrupt type            }
  519.       $a8/$01/                         {         test    al,1                       ;see if any interrupt signalled.   }
  520.       $74/$03/                         {         jz      polla                      ;yes ─── continue                  }
  521.       $e9/$b9/$01/                     {         jmp     near back                  ;no  ───  return to invoker        }
  522.                                        {  determine type of interrupt.                                                 }
  523.                                        {  possibilities:                                                               }
  524.                                        {     0 = modem status changed                                                  }
  525.                                        {     2 = transmit hold register empty (write char)                             }
  526.                                        {     4 = character received from port                                          }
  527.                                        {     6 = line status changed                                                   }
  528.       $24/$06/                         {polla:   and     al,6                       ;strip unwanted bits fr intr typ   }
  529.       $3c/$04/                         {         cmp     al,4                       ;check if interrupt >= 4           }
  530.       $74/$03/                         {         je      pollb                      ;                                  }
  531.       $e9/$db/$00/                     {         jmp     near int2                                                     }
  532.                                        {  write interrupts must be turned on if a higher-priority interrupt            }
  533.                                        {  has been received, else the characters may not be sent (and a lockup         }
  534.                                        {  may occur).                                                                  }
  535.       $50/                             {pollb:   push    ax                         ;save interrupt type               }
  536.       $e8/$9f/$01/                     {         call    enabwi                     ;enable write interrupts           }
  537.       $58/                             {         pop     ax                         ;restore interrupt type            }
  538.                                        {  ─── received a character ────                                                }
  539.       $3c/$04/                         {int4:    cmp     al,4                       ;check for received char intr      }
  540.       $74/$03/                         {         je      int4a                      ;yes ── process it.                }
  541.       $e9/$cf/$00/                     {         jmp     near int2                  ;no ── skip.                       }
  542.                                        {  read the character from the serial port.                                     }
  543.       $8b/$16/>async_base/             {int4a:   mov     dx,[>async_base]           ;read character from port          }
  544.       $ec/                             {         in      al,dx                                                         }
  545.                                        {  check if xon/xoff honored.  if so, check if incoming character is            }
  546.                                        {  an xon or an xoff.                                                           }
  547.       $f6/$06/>async_do_xonxoff/$01/   {         test    byte [<async_do_xonxoff],1 ;see if we honor xon/xoff          }
  548.       $74/$25/                         {         jz      int4d                      ;no ── skip xon/xoff checks        }
  549.       $3c/<xon/                        {         cmp     al,<xon                    ;see if xon found                  }
  550.       $74/$11/                         {         je      int4b                      ;skip if xon found                 }
  551.       $3c/<xoff/                       {         cmp     al,<xoff                   ;see if xoff found                 }
  552.       $75/$1d/                         {         jne     int4d                      ;skip if xoff not found            }
  553.                                        {  xoff received ── set flag indicating sending of chars isn't possible         }
  554.       $c6/$06/>async_xoff_received/$01/{         mov     byte [<async_xoff_received],1    ;turn on rec' xoff flag      }
  555.       $c6/$06/>async_xoff_rec_display/ {         mov     byte [<async_xoff_rec_display],1 ;turn on display flag        }
  556.       $01/ $e9/$be/$ff/                {         jmp     near poll                                                     }
  557.                                        {  xon received ── allow more characters to be sent.                            }
  558.       $c6/$06/>async_xoff_received/$00/{int4b:   mov     byte [<async_xoff_received],0   ;turn off rec'd xoff flag     }
  559.       $c6/$06/>async_xon_rec_display/  {         mov     byte [<async_xon_rec_display],1 ;turn on display flag         }
  560.       $01/$e8/$69/$01/                 {         call    enabwi                     ;enable write interrupts           }
  561.       $e9/$9b/$00/                     {         jmp     near int4z                                                    }
  562.                                        {  not xon/xoff ── handle other character.                                      }
  563.       $f6/$06/>async_line_status/$02/  {int4d:   test    byte [>async_line_status],2 ;check for buffer overrun         }
  564.       $74/$03/                         {         jz      int4e                       ;yes ── don't store anything      }
  565.       $e9/$91/$00/                     {         jmp     int4z                                                         }
  566.       $8b/$1e/>async_buffer_head/      {int4e:   mov     bx,[>async_buffer_head]    ;cur position in input buffer      }
  567.       $c4/$3e/>async_buffer_ptr/       {         les     di,[>async_buffer_ptr]     ;pick up buffer address            }
  568.       $01/$df/                         {         add     di,bx                      ;update position                   }
  569.       $26/$88/$05/                     {     es: mov     [di],al                    ;store rec'd character in buffer   }
  570.       $ff/$06/>async_buffer_used/      {         inc     word [>async_buffer_used]  ;increment count of chars in buf   }
  571.       $a1/>async_buffer_used/          {         mov     ax,[>async_buffer_used]    ;pick up buffer usage count        }
  572.       $3b/$06/>async_maxbufferused/    {         cmp     ax,[>async_maxbufferused]  ;see if greater usage              }
  573.       $7e/$03/                         {         jle     int4f                      ;skip if not                       }
  574.       $a3/>async_maxbufferused/        {         mov     [>async_maxbufferused],ax  ;this is greatest use thus far     }
  575.       $43/                             {int4f:   inc     bx                         ;increment buffer pointer          }
  576.       $3b/$1e/>async_buffer_size/      {         cmp     bx,[>async_buffer_size]    ;check if past end of buffer       }
  577.       $7e/$02/                         {         jle     int4h                                                         }
  578.       $31/$db/                         {         xor     bx,bx                      ;if so, wrap around to front       }
  579.       $39/$1e/>async_buffer_tail/      {int4h:   cmp     word [>async_buffer_tail],bx ;check for overflow              }
  580.       $74/$60/                         {         je      int4s                        ;jump if head ran into tail      }
  581.       $89/$1e/>async_buffer_head/      {         mov     [>async_buffer_head],bx    ;update head pointer               }
  582.                                        {  check for receive buffer nearly full here.                                   }
  583.                                        {  if xon/xoff available, and buffer getting full, set up to send               }
  584.                                        {  xoff to remote system.                                                       }
  585.                                        {  this happens in two possible stages:                                         }
  586.                                        {     (1)  an xoff is sent right when the buffer becomes 'Async_Buffer_High'    }
  587.                                        {          characters full.                                                     }
  588.                                        {     (2)  a second xoff is sent right when the buffer becomes                  }
  589.                                        {          'Async_Buffer_High_2' characters full;  this case is likely the      }
  590.                                        {          result of the remote not having seen our xoff because it was         }
  591.                                        {          lost in transmission.                                                }
  592.                                        {  if cts/rts handshaking, then drop rts here if buffer nearly full.            }
  593.                                        {  note that this has to be done even if the xoff is being sent as well.        }
  594.                                        {  check receive buffer size against first high-water mark.                     }
  595.       $3b/$06/>async_buffer_high/      {         cmp     ax,[>async_buffer_high]    ;ax still has async_buffer_used    }
  596.       $7c/$5b/                         {         jl      int4z                      ;not very full, so keep going.     }
  597.                                        {  remember if we've already (supposedly) disabled sender.                      }
  598.       $8a/$16/>async_sender_on/        {         mov     dl,[<async_sender_on]      ;get sender enabled flag.          }
  599.                                        {  drop through means receive buffer getting full.                              }
  600.                                        {  check for xon/xoff.                                                          }
  601.       $f6/$06/>async_ov_xonxoff/$01/   {         test    byte [<async_ov_xonxoff],1 ;see if we honor xon/xoff          }
  602.                                        {                                           ; for buffer overflow               }
  603.       $74/$1a/                         {         jz      int4k                      ;no ── skip xon/xoff checks        }
  604.                                        {  check if we've already sent XOFF.                                            }
  605.       $f6/$06/>async_xoff_sent/$01/    {         test    byte [<async_xoff_sent],1  ;rememb if we sent xoff or not     }
  606.       $74/$06/                         {         jz      int4j                      ;no ── go send it now.             }
  607.                                        {  check against second high-water mark.                                        }
  608.                                        {  if we are right at it, send an xoff regardless of whether we've              }
  609.                                        {  already sent one or not.  (perhaps the first got lost.)                      }
  610.       $3b/$06/>async_buffer_high_2/    {         cmp     ax,[>async_buffer_high_2]                                     }
  611.       $75/$0d/                         {         jne     int4k                      ;not at 2nd mark ── skip           }
  612.       $c6/$06/>async_send_xoff/$01/    {int4j:   mov     byte [<async_send_xoff],1  ;indicate we need to send xoff     }
  613.       $e8/$06/$01/                     {         call    enabwi                     ;ensure write intr enabled         }
  614.       $c6/$06/>async_sender_on/$00/    {         mov     byte [<async_sender_on],0  ;disable sender                    }
  615.                                        {  check here if we're doing hardware handshakes.                               }
  616.                                        {  drop rts if cts/rts handshaking.                                             }
  617.                                        {  drop dtr if dsr/dtr handshaking.                                             }
  618.       $f6/$c2/$01/                     {int4k:   test    dl,1                       ;see if sender already disabled    }
  619.       $74/$31/                         {         jz      int4z                      ;yes ── skip h/w handshakes.       }
  620.       $30/$e4/                         {         xor     ah,ah                      ;no hardware handshakes            }
  621.       $f6/$06/>async_do_cts/$01/       {         test    byte [<async_do_cts],1     ;see if rts/cts checking           }
  622.       $74/$02/                         {         jz      int4l                      ;no ── skip it                     }
  623.       $b4/<async_rts/                  {         mov     ah,<async_rts              ;turn on rts bit                   }
  624.       $f6/$06/>async_do_dsr/$01/       {int4l:   test    byte [<async_do_dsr],1     ;see if dsr/dtr checking           }
  625.       $74/$03/                         {         jz      int4m                      ;no ── skip it                     }
  626.       $80/$cc/<async_dtr/              {         or      ah,<async_dtr              ;turn on dtr bit                   }
  627.       $80/$fc/$00/                     {int4m:   cmp     ah,0                       ;any hardware signal?              }
  628.       $74/$17/                         {         jz      int4z                      ;no ── skip                        }
  629.       $8b/$16/>async_uart_mcr/         {         mov     dx,[>async_uart_mcr]       ;get modem control register        }
  630.       $ec/                             {         in      al,dx                                                         }
  631.       $f6/$d4/                         {         not     ah                         ;complement hardware flags         }
  632.       $20/$e0/                         {         and     al,ah                      ;nuke rts/dtr                      }
  633.       $ee/                             {         out     dx,al                                                         }
  634.       $c6/$06/>async_sender_on/$00/    {         mov     byte [<async_sender_on],0  ;indicate sender disabled          }
  635.       $e9/$05/$00/                     {         jmp     int4z                                                         }
  636.                                        {  if we come here, then the input buffer has overflowed.                       }
  637.                                        {  characters will be thrown away until the buffer empties at least one slot.   }
  638.       $80/$0e/>async_line_status/$02/  {int4s:   or      byte ptr [>async_line_status],2 ;flag overrun                 }
  639.       $e9/$10/$ff/                     {int4z:   jmp     near poll                                                     }
  640.                                        {  ─── write a character ───                                                    }
  641.       $3c/$02/                         {int2:    cmp     al,2                       ;check for thre interrupt          }
  642.       $74/$03/                         {         je      int2a                      ;yes ── process it.                }
  643.       $e9/$97/$00/                     {         jmp     near int6                  ;no ── skip.                       }
  644.                                        {  check first if we need to send an xoff to remote system.                     }
  645.       $f6/$06/>async_send_xoff/$01/    {int2a:   test    byte [<async_send_xoff],1  ;see if we are sending xoff        }
  646.       $74/$34/                         {         jz      int2d                      ;no ── skip it                     }
  647.                                        {  yes, we are to send xoff to remote.                                          }
  648.                                        {  first, check dsr and cts as requested.                                       }
  649.                                        {  if those status lines aren't ready, turn off write interrupts and            }
  650.                                        {  try later, after a line status change.                                       }
  651.       $f6/$06/>async_do_dsr/$01/       {         test    byte [<async_do_dsr],1     ;see if dsr checking required      }
  652.       $74/$09/                         {         jz      int2b                      ;no ── skip it                     }
  653.       $8b/$16/>async_uart_msr/         {         mov     dx,[>async_uart_msr]       ;get modem status register         }
  654.       $ec/                             {         in      al,dx                                                         }
  655.       $a8/<async_dsr/                  {         test    al,<async_dsr              ;check for data set ready          }
  656.       $74/$2e/                         {         jz      int2e                      ;if not dsr, turn off writ intr    }
  657.       $f6/$06/>async_do_cts/$01/       {int2b:   test    byte [<async_do_cts],1     ;see if cts checking required      }
  658.       $74/$09/                         {         jz      int2c                      ;no ── skip it                     }
  659.       $8b/$16/>async_uart_msr/         {         mov     dx,[>async_uart_msr]       ;get modem status register         }
  660.       $ec/                             {         in      al,dx                                                         }
  661.       $a8/<async_cts/                  {         test    al,<async_cts              ;check for clear to send           }
  662.       $74/$1e/                         {         jz      int2e                      ;if not cts, turn off writ ints    }
  663.                                        {  all status lines look ok.                                                    }
  664.                                        {  send the xoff.                                                               }
  665.       $b0/<xoff/                       {int2c:   mov     al,<xoff                   ;get xoff character                }
  666.       $8b/$16/>async_base/             {         mov     dx,[>async_base]           ;get transmit hold reg address     }
  667.       $ee/                             {         out     dx,al                      ;output the xoff                   }
  668.       $c6/$06/>async_send_xoff/$00/    {         mov     byte [<async_send_xoff],0  ;turn off send xoff flag           }
  669.       $c6/$06/>async_xoff_sent/$01/    {         mov     byte [<async_xoff_sent],1  ;turn on sent xoff flag            }
  670.       $e9/$ce/$fe/                     {         jmp     near poll                  ;return                            }
  671.                                        {  not sending xoff ── see if any character in buffer to be sent.               }
  672.       $8b/$1e/>async_obuffer_tail/     {int2d:   mov     bx,[>async_obuffer_tail]   ;pick up output buffer pointers    }
  673.       $3b/$1e/>async_obuffer_head/     {         cmp     bx,[>async_obuffer_head]                                      }
  674.       $75/$0b/                         {         jne     int2m                      ;skip if not equal ──> send        }
  675.                                        {  if nothing to send, turn off write interrupts to avoid unnecessary           }
  676.                                        {  time spent handling useless thre interrupts.                                 }
  677.       $8b/$16/>async_uart_ier/         {int2e:   mov     dx,[>async_uart_ier]       ;if nothing ─or can't─ send ...    }
  678.       $ec/                             {         in      al,dx                      ;                                  }
  679.       $24/$fd/                         {         and     al,$fd                     ;                                  }
  680.       $ee/                             {         out     dx,al                      ;... disable write interrupts      }
  681.       $e9/$b9/$fe/                     {         jmp     near poll                  ;                                  }
  682.                                        {  if something to send, ensure that remote system didn't send us XOFF.         }
  683.                                        {  if it did, we can't send anything, so turn off write interrupts and          }
  684.                                        {  wait for later (after an xon has been received).                             }
  685.       $f6/$06/>async_xoff_received/$01/{int2m:   test    byte [<async_xoff_received],1 ;see if we received xoff        }
  686.       $75/$ee/                         {         jnz     int2e                      ;yes ── can't send anything now    }
  687.                                        {  if we can send character, check dsr and cts as requested.                    }
  688.                                        {  if those status lines aren't ready, turn off write interrupts and            }
  689.                                        {  try later, after a line status change.                                       }
  690.       $8b/$16/>async_uart_msr/         {         mov     dx,[>async_uart_msr]       ;otherwise get modem status        }
  691.       $ec/                             {         in      al,dx                                                         }
  692.       $a2/>async_modem_status/         {         mov     [>async_modem_status],al   ;and save modem status for later   }
  693.       $f6/$06/>async_do_dsr/$01/       {         test    byte [<async_do_dsr],1     ;see if dsr checking required      }
  694.       $74/$04/                         {         jz      int2n                      ;no ── skip it                     }
  695.       $a8/<async_dsr/                  {         test    al,<async_dsr              ;check for data set ready          }
  696.       $74/$db/                         {         jz      int2e                      ;if not dsr, turn off write ints   }
  697.       $f6/$06/>async_do_cts/$01/       {int2n:   test    byte [<async_do_cts],1     ;see if cts checking required      }
  698.       $74/$04/                         {         jz      int2o                      ;no ── skip it                     }
  699.       $a8/<async_cts/                  {         test    al,<async_cts              ;check for clear to send           }
  700.       $74/$d0/                         {         jz      int2e                      ;if not cts, turn off write ints   }
  701.                                        {  everything looks ok for sending, so send the character.                      }
  702.       $c4/$3e/>async_obuffer_ptr/      {int2o:   les     di,[>async_obuffer_ptr]    ;get output buffer pointer         }
  703.       $01/$df/                         {         add     di,bx                      ;position to character to output   }
  704.       $26/$8a/$05/                     {     es: mov     al,[di]                    ;get character to output           }
  705.       $8b/$16/>async_base/             {         mov     dx,[>async_base]           ;get transmit hold reg address     }
  706.       $ee/                             {         out     dx,al                      ;output the character              }
  707.       $ff/$0e/>async_obuffer_used/     {         dec     word [>async_obuffer_used] ;decrement count of chars in buf   }
  708.       $43/                             {         inc     bx                         ;increment tail pointer            }
  709.       $3b/$1e/>async_obuffer_size/     {         cmp     bx,[>async_obuffer_size]   ;see if past end of buffer         }
  710.       $7e/$02/                         {         jle     int2z                                                         }
  711.       $31/$db/                         {         xor     bx,bx                      ;if so, wrap to front              }
  712.       $89/$1e/>async_obuffer_tail/     {int2z:   mov     [>async_obuffer_tail],bx   ;store updated buffer tail         }
  713.       $e9/$72/$fe/                     {         jmp     near poll                                                     }
  714.                                        {  ─── line status change ───                                                   }
  715.       $3c/$06/                         {int6:    cmp     al,6                       ;check for line status interrupt   }
  716.       $75/$11/                         {         jne     int0                       ;no ── skip.                       }
  717.       $8b/$16/>async_uart_lsr/         {         mov     dx,[>async_uart_lsr]       ;yes ── pick up line status reg    }
  718.       $ec/                             {         in      al,dx                      ;and its contents                  }
  719.       $24/$1e/                         {         and     al,$1e                     ;strip unwanted bits               }
  720.       $a2/>async_line_status/          {         mov     [>async_line_status],al    ;store for future reference        }
  721.       $08/$06/>async_line_error_flags/ {         or      [>async_line_error_flags],al ;add to any past transgressions  }
  722.       $e9/$5d/$fe/                     {         jmp     near poll                                                     }
  723.                                        {  ─── modem status change ───                                                  }
  724.       $3c/$00/                         {int0:    cmp     al,0                       ;check for modem status change     }
  725.       $74/$03/                         {         je      int0a                      ;yes ── handle it                  }
  726.       $e9/$56/$fe/                     {         jmp     near poll                  ;else get next interrupt           }
  727.       $8b/$16/>async_uart_msr/         {int0a:   mov     dx,[>async_uart_msr]       ;pick up modem status reg. address }
  728.       $ec/                             {         in      al,dx                      ;and its contents                  }
  729.       $a2/>async_modem_status/         {         mov     [>async_modem_status],al   ;store for future reference        }
  730.       $e8/$03/$00/                     {         call    enabwi                     ;turn on write interrupts, in case }
  731.                                        {                                            ;status change resulted fm cts/dsr }
  732.                                        {                                            ;changing state.                   }
  733.       $e9/$48/$fe/                     {         jmp     near poll                                                     }
  734.                                        {  internal subroutine to enable write interrupts.                              }
  735.                                        {enabwi: ;proc    near                                                          }
  736.       $8b/$16/>async_uart_ier/         {         mov     dx,[>async_uart_ier]       ;get interrupt enable register     }
  737.       $ec/                             {         in      al,dx                      ;check contents of ier             }
  738.       $a8/$02/                         {         test    al,2                       ;see if write interrupt enabled    }
  739.       $75/$03/                         {         jnz     enabret                    ;skip if so                        }
  740.       $0c/$02/                         {         or      al,2                       ;else enable write interrupts ...  }
  741.       $ee/                             {         out     dx,al                      ;... by rewriting ier contents     }
  742.       $c3/                             {enabret: ret                                ;return to caller                  }
  743.                                        {  send non-specific eoi to 8259 controller.                                    }
  744.       $b0/$20/                         {back:    mov     al,$20          ;eoi = $20                                    }
  745.       $e6/$20                          {         out     $20,al                                                        }
  746.     );
  747.   end;
  748.  
  749.  
  750.  
  751.  
  752.   procedure async_close(drop_dtr: boolean);
  753.   var i: integer; m: integer;
  754.   begin  { async_close }
  755.     if async_open_flag then begin  {     disable the irq on the 8259     }
  756.       inline($fa);                 {     disable interrupts              }
  757.       i := port[i8088_imr];        {     get the interrupt mask register }
  758.       m := 1 shl async_irq;        {     set mask to turn off interrupt  }
  759.       port[i8088_imr] := i or m;   {     disable the 8250 interrupts     }
  760.       port[uart_ier + async_base] := 0;
  761.       { disable out2, rts, out1 on 8250, but possibly leave dtr enabled.}
  762.       if drop_dtr then port[uart_mcr + async_base] := 0 else
  763.         port[uart_mcr + async_base] := 1;
  764.       inline($fb);                { enable interrupts                   }
  765.       { re-initialize our data areas so we know the port is closed      }
  766.       async_open_flag := false; async_xoff_sent := false;
  767.       async_sender_on := false;    { restore the previous interrupt pointers }
  768.       setintvec(async_int , async_save_iaddr);
  769.     end;
  770.   end;
  771.  
  772.  
  773.  
  774.   procedure async_clear_errors;
  775.   var i:  integer; m:  integer;
  776.   begin
  777.     { read the rbr and reset any pending error conditions. }
  778.     { first turn off the divisor access latch bit to allow }
  779.     { access to rbr, etc.                                  }
  780.     inline($fa);  { disable interrupts }
  781.     port[uart_lcr + async_base] := port[uart_lcr + async_base] and $7f;
  782.     { read the line status register to reset any errors it indicates    }
  783.     i := port[uart_lsr + async_base];
  784.     { read the receiver buffer register in case it contains a character }
  785.     i := port[uart_rbr + async_base];
  786.     { enable the irq on the 8259 controller }
  787.     i := port[i8088_imr];  { get the interrupt mask register }
  788.     m := (1 shl async_irq) xor $00ff;
  789.     port[i8088_imr] := i and m;         { enable out2 on 8250 }
  790.     i := port[uart_mcr + async_base];
  791.     port[uart_mcr + async_base] := i or $0b;
  792.     { enable the data ready interrupt on the 8250 }
  793.     port[uart_ier + async_base] := $0f; { re-enable 8259      }
  794.     port[$20] := $20;
  795.     inline($fb); { enable interrupts }
  796.   end;
  797.  
  798.  
  799.  
  800.   procedure async_reset_port(
  801.     comport  : integer;
  802.     baudrate : word;
  803.     parity   : char;
  804.     wordsize : integer;
  805.     stopbits : integer
  806.   );
  807.   const
  808.     async_num_bauds = 11;
  809.     async_baud_table : array [1..async_num_bauds] of record
  810.       baud, bits: word;
  811.     end = (
  812.       (baud:   110; bits: $00),
  813.       (baud:   150; bits: $20),
  814.       (baud:   300; bits: $40),
  815.       (baud:   600; bits: $60),
  816.       (baud:  1200; bits: $80),
  817.       (baud:  2400; bits: $A0),
  818.       (baud:  4800; bits: $C0),
  819.       (baud:  9600; bits: $E0),
  820.       (baud: 19200; bits: $E0),
  821.       (baud: 38400; bits: $E0),
  822.       (baud: 57600; bits: $E0)
  823.     );                   {────────────────────────────────────────────────}
  824.   var                    { build the comparm for rs232_init               }
  825.     i, m,                { see technical reference manual for description }
  826.     comparm : integer;   {────────────────────────────────────────────────}
  827.  
  828.   begin                  {       set up the bits for the baud rate        }
  829.     if (baudrate > async_baud_table[async_num_bauds].baud) then
  830.       baudrate := async_baud_table[async_num_bauds].baud else
  831.         if (baudrate < async_baud_table[1].baud) then
  832.           baudrate := async_baud_table[1].baud; { remember baudrate 4 purges }
  833.     async_baud_rate := baudrate;
  834.     i := 0;
  835.     repeat 
  836.       inc(i)
  837.     until ((i >= async_num_bauds) or (baudrate = async_baud_table[i].baud));
  838.     comparm := async_baud_table[i].bits;
  839.     { choose parity.  temporarily consider mark, space as none.   }
  840.     parity := upcase(parity);
  841.     case parity of
  842.       'E': comparm := comparm or $0018; 'O': comparm := comparm or $0008;
  843.       else ;
  844.     end { case };                  { choose number of data bits }
  845.     wordsize := wordsize - 5;
  846.     if (wordsize < 0) or (wordsize > 3) then wordsize := 3;
  847.     comparm := comparm or wordsize;
  848.     if stopbits = 2 then comparm := comparm or $0004; { choose stop bits }
  849.     { default is 1 stop bit use the bios com port init routine           }
  850.     bios_rs232_init(comport - 1 , comparm);
  851.     { if > 9600 baud, we have to screw around a bit                      }
  852.     if (baudrate >= 19200) then begin
  853.       i := port[ uart_lcr + async_base ];
  854.       port[uart_lcr + async_base] := i or $80;
  855.       port[uart_thr + async_base] := 115200 div baudrate;
  856.       port[uart_ier + async_base] := 0;
  857.       i := port[ uart_lcr + async_base ];
  858.       port[uart_lcr + async_base] := i and $7f;
  859.     end;                                 { now fix up mark, space parity }
  860.     if ((parity = 'M') or (parity = 'S')) then begin
  861.       i := port[ uart_lcr + async_base ];
  862.       port[ uart_lcr + async_base ] := $80;
  863.       comparm := wordsize or ((stopbits - 1) shl 2);
  864.       case parity of
  865.         'M': comparm := comparm or $0028;
  866.         'S': comparm := comparm or $0038;
  867.         else ;
  868.       end;
  869.       port[uart_lcr + async_base] := comparm;
  870.     end;
  871.     async_sender_on := true;
  872.     { sender is enabled | clear any pending errors on async line   }
  873.     async_clear_errors;
  874.   end;
  875.  
  876.  
  877.  
  878.  
  879.   function async_open(
  880.     comport  : integer;
  881.     baudrate :    word;
  882.     parity   :    char;
  883.     wordsize : integer;
  884.     stopbits : integer
  885.   ): boolean;
  886.  
  887.   begin { if port open, close it down first. }
  888.     if async_open_flag then async_close(false); { choose communications port }
  889.     if (comport < 1) then comport := 1 else
  890.       if (comport > maxcomports) then comport := maxcomports;
  891.     async_port := comport;
  892.     async_base := com_base[comport];
  893.     async_irq  := com_irq[comport];
  894.     async_int  := com_int[comport];       { set reg pointers for isr routine }
  895.     async_uart_ier := async_base + uart_ier;
  896.     async_uart_iir := async_base + uart_iir;
  897.     async_uart_msr := async_base + uart_msr;
  898.     async_uart_lsr := async_base + uart_lsr;
  899.     async_uart_mcr := async_base + uart_mcr; { check if given port installed }
  900.     if (
  901.       (port[uart_iir + async_base] and $00f8) <> 0
  902.     ) then async_open := false else begin        { serial port not installed }
  903.       getintvec(async_int , async_save_iaddr);
  904.       setintvec(async_int , @async_isr);
  905.       async_reset_port(comport, baudrate, parity, wordsize, stopbits);
  906.       async_open := true; async_open_flag := true;
  907.     end;
  908.   end;
  909.  
  910.  
  911.  
  912.  
  913.   procedure async_send(c: char);
  914.   begin 
  915.     inline(
  916.       $8b/$1e/>async_obuffer_head/    {         mov     bx,[>async_obuffer_head]   ;get output queue head pointer      }
  917.       $c4/$3e/>async_obuffer_ptr/     {         les     di,[>async_obuffer_ptr]    ;pick up output buffer address      }
  918.       $01/$df/                        {         add     di,bx                      ;position to current character      }
  919.       $89/$da/                        {         mov     dx,bx                      ;save previous head pointer         }
  920.       $43/                            {         inc     bx                         ;increment head pointer             }
  921.       $3b/$1e/>async_obuffer_size/    {         cmp     bx,[>async_obuffer_size]   ;see if past end of buffer          }
  922.       $7e/$02/                        {         jle     send1                      ;skip if not                        }
  923.       $31/$db/                        {         xor     bx,bx                      ;wrap to start of buffer            }
  924.       $3b/$1e/>async_obuffer_tail/    {send1:   cmp     bx,[>async_obuffer_tail]   ;see if head collided with tail     }
  925.       $75/$1c/                        {         jne     send4                      ;no ── buffer didn't fill up        }
  926.       $8b/$0e/>async_output_delay/    {         mov     cx,[>async_output_delay]   ;run delay loop & see if buf drains }
  927.       $51/                            {send2:   push    cx                         ;save milleseconds to go            }
  928.       $8b/$0e/>async_onemsdelay/      {         mov     cx,[>async_onemsdelay]     ;get delay loop value for 1 ms      }
  929.       $e2/$fe/                        {send3:   loop    send3                      ;tight loop for 1 ms delay          }
  930.       $59/                            {         pop     cx                         ;get back millesecond count         }
  931.       $3b/$1e/>async_obuffer_tail/    {         cmp     bx,[>async_obuffer_tail]   ;see if buffer drained yet          }
  932.       $75/$0a/                        {         jne     send4                      ;yes ── ok, stop delay loop.        }
  933.       $e2/$f0/                        {         loop    send2                      ;decrement millisec count and loop  }
  934.       $c6/$06/>async_obuffer_overflow/{         mov     byte [>async_obuffer_overflow],1 ;indicate output buf overflow }
  935.       $01/$e9/$1a/$00/                {         jmp     send5                      ;skip updating head pointers        }
  936.       $89/$1e/>async_obuffer_head/    {send4:   mov     [>async_obuffer_head],bx   ;save updated head pointer          }
  937.       $8a/$46/<c/                     {         mov     al,[bp+<c]                 ;pick up character to send          }
  938.       $26/$88/$05/                    {     es: mov     [di],al                    ;place character in output buffer   }
  939.       $a1/>async_obuffer_used/        {         mov     ax,[>async_obuffer_used]   ;get buffer use count               }
  940.       $40/                            {         inc     ax                         ;increment buffer use count         }
  941.       $a3/>async_obuffer_used/        {         mov     [>async_obuffer_used],ax   ;save new count                     }
  942.       $3b/$06/>async_maxobufferused/  {         cmp     ax,[>async_maxobufferused] ;see if larger than ever before     }
  943.       $7e/$03/                        {         jle     send5                      ;skip if not                        }
  944.       $a3/>async_maxobufferused/      {         mov     [>async_maxobufferused],ax ;save new maximum usage             }
  945.       $8b/$16/>async_uart_ier/        {send5:   mov     dx,[>async_uart_ier]       ;get interrupt enable register      }
  946.       $ec/                            {         in      al,dx                      ;check contents of ier              }
  947.       $a8/$02/                        {         test    al,2                       ;see if write interrupt enabled     }
  948.       $75/$03/                        {         jnz     send6                      ;skip if so                         }
  949.       $0c/$02/                        {         or      al,2                       ;else enable write interrupts ...   }
  950.       $ee                             {         out     dx,al                      ;... by rewriting ier contents      }
  951.     );                                {send6:                                                                          }
  952.   end;
  953.  
  954.  
  955.  
  956.  
  957.  
  958.   function async_receive(var c: char): boolean;
  959.   begin
  960.     inline(
  961.                                  {  check if any characters in input comm buffer                                       }
  962.       $a1/>async_buffer_tail/    {         mov   ax,[>async_buffer_tail]                                               }
  963.       $3b/$06/>async_buffer_head/{         cmp   ax,[>async_buffer_head]                                               }
  964.       $75/$0b/                   {         jne   rec1                                                                  }
  965.                                  {  buffer is empty ── return nul character                                            }
  966.       $c4/$7e/<c/                {         les   di,[bp+<c]                   ;get character address                   }
  967.       $31/$c0/                   {         xor   ax,ax                        ;clear out unused bits                   }
  968.       $26/$88/$05/               {     es: mov   [di],al                      ;nul character                           }
  969.       $e9/$69/$00/               {         jmp   return                                                                }
  970.                                  {  buffer not empty ── pick up next character.                                        }
  971.       $c4/$3e/>async_buffer_ptr/ {rec1:    les   di,[>async_buffer_ptr]       ;pick up buffer address                  }
  972.       $01/$c7/                   {         add   di,ax                        ;add character offset                    }
  973.       $26/$8a/$1d/               {     es: mov   bl,[di]                      ;get character from buffer               }
  974.       $c4/$7e/<c/                {         les   di,[bp+<c]                   ;get result address                      }
  975.       $26/$88/$1d/               {     es: mov   [di],bl                      ;store character from buffer             }
  976.       $40/                       {         inc   ax                           ;increment tail pointer                  }
  977.       $3b/$06/>async_buffer_size/{         cmp   ax,[>async_buffer_size]      ;past end of buffer?                     }
  978.       $7e/$02/                   {         jle   rec2                         ;no ── skip wrapping                     }
  979.       $31/$c0/                   {         xor   ax,ax                        ;yes ── point to start of buffer         }
  980.       $a3/>async_buffer_tail/    {rec2:    mov   [>async_buffer_tail],ax      ;update tail pointer                     }
  981.       $a1/>async_buffer_used/    {         mov   ax,[>async_buffer_used]      ;pick up amount of buffer used           }
  982.       $48/                       {         dec   ax                           ;update buffer use count                 }
  983.       $a3/>async_buffer_used/    {         mov   [>async_buffer_used],ax      ;                                        }
  984.                                  { check how empty the receive buffer is.                                              }
  985.                                  { we may have previously sent xoff, or dropped rts, to                                }
  986.                                  { stop sender from sending.  if so, and the buffer is                                 }
  987.                                  { now empty enough, we should re-enable the sender.                                   }
  988.       $f6/$06/>async_sender_on/  {         test  byte [<async_sender_on],1    ;see if sender enabled                   }
  989.       $01/$75/$3d/               {         jnz   rec6                         ;skip buffer tests if so                 }
  990.       $3b/$06/>async_buffer_low/ {         cmp   ax,[>async_buffer_low]       ;check if low enough                     }
  991.       $7f/$37/                   {         jg    rec6                         ;still too full, skip                    }
  992.                                  { buffer is reasonably empty, send xon to get things rolling again                    }
  993.                                  { if xoff previously sent.                                                            }
  994.       $f6/$06/>async_xoff_sent/  {         test  byte [<async_xoff_sent],1    ;check if xoff sent                      }
  995.       $01/$74/$0d/               {         jz    rec3                         ;no ── skip.                             }
  996.       $b8/>xon/                  {         mov   ax,>xon                      ;else push xon onto stack                }
  997.       $50/                       {         push  ax                                                                    }
  998.       $ff/$1e/>async_send_addr/  {         call  far [>async_send_addr]       ;call output routine                     }
  999.       $c6/$06/>async_xoff_sent/  {         mov   byte [>async_xoff_sent],0    ;clear xoff flag                         }
  1000.       $00/                       { if rts dropped because buffer was too full, enable rts.                             }
  1001.       $f6/$06/>async_do_cts/$01/ {rec3:    test    byte [<async_do_cts],1     ;check if cts/rts checking               }
  1002.       $74/$08/                   {         jz      rec4                       ;no ── skip                              }
  1003.       $8b/$16/>async_uart_mcr/   {         mov     dx,[>async_uart_mcr]       ;get modem control register              }
  1004.       $ec/                       {         in      al,dx                                                               }
  1005.       $0c/<async_rts/            {         or      al,<async_rts              ;enable rts                              }
  1006.       $ee/                       {         out     dx,al                                                               }
  1007.                                  { if dtr dropped because buffer was too full, enable dtr.                             }
  1008.       $f6/$06/>async_do_dsr/$01/ {rec4:    test    byte [<async_do_dsr],1     ;check if dsr/dtr checking               }
  1009.       $74/$08/                   {         jz      rec5                       ;no ── skip                              }
  1010.       $8b/$16/>async_uart_mcr/   {         mov     dx,[>async_uart_mcr]       ;get modem control register              }
  1011.       $ec/                       {         in      al,dx                                                               }
  1012.       $0c/<async_dtr/            {         or      al,<async_dtr              ;enable dtr                              }
  1013.       $ee/                       {         out     dx,al                                                               }
  1014.       $c6/$06/>async_sender_on/  {rec5:    mov     byte [>async_sender_on],1  ;indicate sender enabled                 }
  1015.       $01/                       {  indicate character found                                                           }
  1016.       $b8/$01/$00/               {rec6:    mov    ax,1                                                                 }
  1017.       $80/$26/>async_line_status/{return:  and    byte [>async_line_status],$fd ;remove overflow flag                  }
  1018.       $fd/$09/$c0/               {         or     ax,ax                       ;set zero flag to indicate return status }
  1019.       $89/$ec/                   {         mov    sp,bp                                                                }
  1020.       $5d/                       {         pop    bp                                                                   }
  1021.       $ca/$04/$00                {         retf   4                                                                    }
  1022.     );
  1023.   end;
  1024.  
  1025.  
  1026.  
  1027.  
  1028.   procedure async_receive_with_timeout(secs: integer; var c: integer);
  1029.   begin
  1030.     inline(                      {  check if a character in input comm buffer                                          }
  1031.       $a1/>async_buffer_tail/    {         mov   ax,[>async_buffer_tail]                                               }
  1032.       $3b/$06/>async_buffer_head/{         cmp   ax,[>async_buffer_head]                                               }
  1033.       $75/$29/                   {         jne   rec1                                                                  }
  1034.                                  {  buffer empty ── begin wait loop.                                                   }
  1035.       $8b/$46/<secs/             {         mov   ax,[bp+<secs]                 ;get seconds to wait                    }
  1036.       $b9/$0a/$00/               {         mov   cx,10                         ;shift count = 2 ** 10 = 1024           }
  1037.       $d3/$e0/                   {         shl   ax,cl                         ;seconds * 1024 = milleseconds          }
  1038.       $89/$c1/                   {         mov   cx,ax                         ;move to looping register               }
  1039.                                  {  delay for 1 ms.                                                                    }
  1040.       $51/                       {delay:   push  cx                            ;save milleseconds to go                }
  1041.       $8b/$0e/>async_onemsdelay/ {         mov   cx,[>async_onemsdelay]        ;get delay loop value for 1 ms          }
  1042.       $e2/$fe/                   {delay1:  loop  delay1                        ;tight loop for 1 ms delay              }
  1043.                                  {  check if any character yet.                                                        }
  1044.       $59/                       {         pop   cx                            ;get back millesecond count             }
  1045.       $a1/>async_buffer_tail/    {         mov   ax,[>async_buffer_tail]                                               }
  1046.       $3b/$06/>async_buffer_head/{         cmp   ax,[>async_buffer_head]                                               }
  1047.       $75/$0e/                   {         jne   rec1                                                                  }
  1048.                                  {  buffer still empty ── decrement elapsed time                                       }
  1049.       $e2/$ed/                   {         loop  delay                         ;decrement millesecond count and loop   }
  1050.                                  {  dropped through ── no character arrived in specified interval.                     }
  1051.                                  {  return timeout as result.                                                          }
  1052.       $bb/>timeout/              {         mov   bx,>timeout                   ;pick up timeout value                  }
  1053.       $c4/$7e/<c/                {         les   di,[bp+<c]                    ;get result character address           }
  1054.       $26/$89/$1d/               {    es:  mov   [di],bx                       ;store timeout value                    }
  1055.       $e9/$68/$00/               {         jmp   return                        ;return to caller                       }
  1056.                                  {  buffer not empty ── pick up next character.                                        }
  1057.       $c4/$3e/>async_buffer_ptr/ {rec1:    les   di,[>async_buffer_ptr]        ;pick up buffer address                 }
  1058.       $01/$c7/                   {         add   di,ax                         ;add character offset                   }
  1059.       $26/$8a/$1d/               {     es: mov   bl,[di]                       ;get character from buffer              }
  1060.       $30/$ff/                   {         xor   bh,bh                         ;clear high-order bits                  }
  1061.       $c4/$7e/<c/                {         les   di,[bp+<c]                    ;get result address                     }
  1062.       $26/$89/$1d/               {     es: mov   [di],bx                       ;store character from buffer            }
  1063.       $40/                       {         inc   ax                            ;increment tail pointer                 }
  1064.       $3b/$06/>async_buffer_size/{         cmp   ax,[>async_buffer_size]       ;past end of buffer?                    }
  1065.       $7e/$02/                   {         jle   rec2                          ;no ── skip wrapping                    }
  1066.       $31/$c0/                   {         xor   ax,ax                         ;yes ── point to start of buffer        }
  1067.       $a3/>async_buffer_tail/    {rec2:    mov   [>async_buffer_tail],ax       ;update tail pointer                    }
  1068.       $a1/>async_buffer_used/    {         mov   ax,[>async_buffer_used]       ;pick up amount of buffer used          }
  1069.       $48/                       {         dec   ax                            ;update buffer use count                }
  1070.       $a3/>async_buffer_used/    {         mov   [>async_buffer_used],ax       ;                                       }
  1071.                                  { check how empty the receive buffer is.                                              }
  1072.                                  { we may have previously sent xoff, or dropped rts, to                                }
  1073.                                  { stop sender from sending.  if so, and the buffer is                                 }
  1074.                                  { now empty enough, we should re-enable the sender.                                   }
  1075.       $f6/$06/>async_sender_on/  {         test  byte [<async_sender_on],1     ;see if sender enabled                  }
  1076.       $01/$75/$3d/               {         jnz   return                        ;skip buffer tests if so                }
  1077.       $3b/$06/>async_buffer_low/ {         cmp   ax,[>async_buffer_low]        ;check if low enough                    }
  1078.       $7f/$37/                   {         jg    return                        ;still too full, skip                   }
  1079.                                  { buffer is reasonably empty, send xon to get things rolling again                    }
  1080.                                  { if xoff previously sent.                                                            }
  1081.       $f6/$06/>async_xoff_sent/  {         test  byte [<async_xoff_sent],1     ;check if xoff sent                     }
  1082.       $01/$74/$0d/               {         jz    rec3                          ;no ── skip.                            }
  1083.       $b8/>xon/                  {         mov   ax,>xon                       ;else push xon onto stack               }
  1084.       $50/                       {         push  ax                                                                    }
  1085.       $ff/$1e/>async_send_addr/  {         call  far [>async_send_addr]        ;call output routine                    }
  1086.       $c6/$06/>async_xoff_sent/  {         mov   byte [>async_xoff_sent],0     ;clear xoff flag                        }
  1087.       $00/                       { if rts dropped because buffer was too full, enable rts.                             }
  1088.       $f6/$06/>async_do_cts/$01/ {rec3:    test    byte [<async_do_cts],1      ;check if cts/rts checking              }
  1089.       $74/$08/                   {         jz      rec4                        ;no ── skip                             }
  1090.       $8b/$16/>async_uart_mcr/   {         mov     dx,[>async_uart_mcr]        ;get modem control register             }
  1091.       $ec/                       {         in      al,dx                                                               }
  1092.       $0c/<async_rts/            {         or      al,<async_rts               ;enable rts                             }
  1093.       $ee/                       {         out     dx,al                                                               }
  1094.                                  { if dtr dropped because buffer was too full, enable dtr.                             }
  1095.       $f6/$06/>async_do_dsr/$01/ {rec4:    test    byte [<async_do_dsr],1      ;check if dsr/dtr checking              }
  1096.       $74/$08/                   {         jz      rec5                        ;no ── skip                             }
  1097.       $8b/$16/>async_uart_mcr/   {         mov     dx,[>async_uart_mcr]        ;get modem control register             }
  1098.       $ec/                       {         in      al,dx                                                               }
  1099.       $0c/<async_dtr/            {         or      al,<async_dtr               ;enable dtr                             }
  1100.       $ee/                       {         out     dx,al                                                               }
  1101.       $c6/$06/>async_sender_on/  {rec5:    mov     byte [>async_sender_on],1   ;indicate sender enabled                }
  1102.       $01/
  1103.       $80/$26/>async_line_status/{return:  and     byte [>async_line_status],$fd ;remove overflow flag                 }
  1104.       $fd
  1105.     );
  1106.   end;
  1107.  
  1108.  
  1109.  
  1110.   
  1111.   procedure async_stuff(ch: char);
  1112.   var new_head: integer;
  1113.   begin 
  1114.     async_buffer_ptr^[async_buffer_head] := ch;
  1115.     new_head := succ(async_buffer_head) mod succ(async_buffer_size);
  1116.     if (
  1117.       (new_head = async_buffer_tail)
  1118.     ) then async_buffer_overflow := true else begin
  1119.       async_buffer_head := new_head; inc(async_buffer_used);
  1120.       if (async_buffer_used > async_maxbufferused) then
  1121.         async_maxbufferused := async_buffer_used;
  1122.     end;
  1123.   end;
  1124.  
  1125.  
  1126.  
  1127.  
  1128.   function async_wait_for_quiet(
  1129.     max_wait  : longint;
  1130.     wait_time : longint
  1131.   ): boolean;
  1132.   var
  1133.     t1   : longint;
  1134.     w1   : longint;
  1135.     head : integer;
  1136.  
  1137.   begin { async_wait_for_quiet }
  1138.     t1 := timeofdayh;                          { get current time of day }
  1139.     { outer loop runs over maximum time to wait for quiet spell to appear }
  1140.     repeat
  1141.       { get time defining "quiet" for our purposes in 1/100th secs.  }
  1142.       w1 := wait_time;
  1143.       { delay 1/100th second and then see if receive buffer head     }
  1144.       { has changed or not.  if head changed, drop through to start  }
  1145.       { check over again.                                            }
  1146.       repeat
  1147.         delay(10); dec(w1);
  1148.       until  ((w1 = 0) or (head <> async_buffer_head));
  1149.       { check if maximum wait time is exhausted ── quit if so.  else }
  1150.       { if buffer head didn't change, then port is quiet, so quit.   }
  1151.       { else keep on going.                                          }
  1152.     until (
  1153.       (timediffh(t1 , timeofday) > max_wait) or
  1154.       (head = async_buffer_head)
  1155.     );
  1156.     { if we dropped through with the buffer head not changed,      }
  1157.     { this means that the port is quiet.                           }
  1158.     async_wait_for_quiet := (head = async_buffer_head);
  1159.   end;
  1160.  
  1161.  
  1162.  
  1163.  
  1164.   procedure async_send_now(c: char);
  1165.   var timeout: word;
  1166.   begin
  1167.     port[uart_mcr + async_base] := $0b; { turn on out2, dtr, and rts }
  1168.     if async_do_dsr then begin { wait for dsr using busy wait }
  1169.       timeout := 65535;
  1170.       while (
  1171.         ((port[uart_msr + async_base] and $20) = 0) and
  1172.         (timeout > 0)
  1173.       ) do dec(timeout);
  1174.     end; { wait for cts using busy wait }
  1175.     if async_do_cts then begin
  1176.       timeout := 65535;
  1177.       while (
  1178.         ((port[uart_msr + async_base] and $10) = 0) and
  1179.         (timeout > 0)
  1180.       ) do dec(timeout);
  1181.     end; { wait for transmit hold register empty (thre) }
  1182.     if (timeout > 0) then  timeout := 65535;
  1183.     while (
  1184.       ((port[uart_lsr + async_base] and $20) = 0) and
  1185.       (timeout > 0)
  1186.     ) do dec(timeout); { send the character when port clear }
  1187.     inline($fa);                    { cli ─── disable interrupts }
  1188.     port[uart_thr + async_base] := ord(c);
  1189.     inline($fb);                    { sti ─── enable interrupts }
  1190.   end;
  1191.  
  1192.  
  1193.  
  1194.  
  1195.   procedure async_find_delay(var one_ms_delay: integer);
  1196.   const
  1197.     hi_timer : integer = 0  { saves high portion of timer   };
  1198.     lo_timer : integer = 0  { saves low portion of timer    };
  1199.     outcount : integer = 0  { accumulates outer loop counts };
  1200.  
  1201.   begin
  1202.     inline(
  1203.       $31/$c0/                   {          xor    ax,ax                 ;clear ax to zero                     }
  1204.       $8e/$c0/                   {          mov    es,ax                 ;allow low-memory access              }
  1205.       $c7/$06/>outcount/$00/$00/ {          mov    word [>outcount],0    ;clear outer loop counter             }
  1206.       $fa/                       {          cli                          ;no interrupts while reading          }
  1207.       $26/$8b/$0e/>$46e/         {      es: mov    cx,[>$46e]            ;hi part of cpu timer value           }
  1208.       $26/$8b/$16/>$46c/         {      es: mov    dx,[>$46c]            ;lo part of cpu timer value           }
  1209.       $fb/                       {          sti                          ;interrupts back on                   }
  1210.       $89/$0e/>hi_timer/         {          mov    [>hi_timer],cx        ;save hi part of timer                }
  1211.       $89/$16/>lo_timer/         {          mov    [>lo_timer],dx        ;save low part of timer               }
  1212.       $fa/                       {loop1:    cli                          ;no interrupts while reading          }
  1213.       $26/$8b/$0e/>$46e/         {      es: mov    cx,[>$46e]            ;hi part of cpu timer value           }
  1214.       $26/$8b/$16/>$46c/         {      es: mov    dx,[>$46c]            ;lo part of cpu timer value           }
  1215.       $fb/                       {          sti                          ;interrupts back on                   }
  1216.       $89/$c8/                   {          mov    ax,cx                 ;save cx and dx for later             }
  1217.       $89/$d3/                   {          mov    bx,dx                                                       }
  1218.       $2b/$06/>hi_timer/         {          sub    ax,[>hi_timer]        ;subtract low order part              }
  1219.       $1b/$1e/>lo_timer/         {          sbb    bx,[>lo_timer]        ;subtract high order part             }
  1220.       $74/$e6/                   {          je     loop1                 ;continue until non-0 tick difference }
  1221.       $89/$0e/>hi_timer/         {          mov    [>hi_timer],cx        ;save hi part                         }
  1222.       $89/$16/>lo_timer/         {          mov    [>lo_timer],dx        ;save low part                        }
  1223.       $b9/$6e/$00/               {loop2:    mov    cx,110                ;run short delay loop.                }
  1224.       $e2/$fe/                   {delay:    loop   delay                                                       }
  1225.       $fa/                       {          cli                          ;no interrupts while reading          }
  1226.       $26/$8b/$0e/>$46e/         {      es: mov    cx,[>$46e]            ;hi part of cpu timer value           }
  1227.       $26/$8b/$16/>$46c/         {      es: mov    dx,[>$46c]            ;lo part of cpu timer value           }
  1228.       $fb/                       {          sti                          ;interrupts back on                   }
  1229.       $ff/$06/>outcount/         {          inc    word [>outcount]      ;increment outer loop count           }
  1230.       $2b/$0e/>hi_timer/         {          sub    cx,[>hi_timer]        ;subtract low order part              }
  1231.       $1b/$16/>lo_timer/         {          sbb    dx,[>lo_timer]        ;subtract high order part             }
  1232.       $74/$e1/                   {          je     loop2                 ;keep going if next tick not found    }
  1233.       $a1/>outcount/             {          mov    ax,[>outcount]        ;pick up outer loop counter           }
  1234.       $d1/$e0/                   {          shl    ax,1                  ;* 2 = ticks for 1 ms delay           }
  1235.       $c4/$be/>one_ms_delay/     {          les    di,[bp+>one_ms_delay] ;get address of result                }
  1236.       $26/$89/$05                {      es: mov    [di],ax               ;store result                         }
  1237.     );
  1238.   end;
  1239.  
  1240.  
  1241.  
  1242.  
  1243.  
  1244.   procedure async_init(
  1245.     async_buffer_max : integer;
  1246.     async_obuffer_max: integer;
  1247.     async_high_lev1  : integer;
  1248.     async_high_lev2  : integer;
  1249.     async_low_lev    : integer
  1250.   );
  1251.   var i: integer;
  1252.   begin
  1253.     async_open_flag := false; { no port open yet.                 }
  1254.     async_xoff_sent := false; { no xon/xoff handling yet.         }
  1255.     async_xoff_received := false;
  1256.     async_xoff_rec_display := false;
  1257.     async_xon_rec_display := false;
  1258.     async_send_xoff := false;
  1259.     async_sender_on := false;
  1260.     { sender not enabled. set up empty receive buffer             }
  1261.     async_buffer_overflow := false;
  1262.     async_buffer_used := 0; async_maxbufferused := 0;
  1263.     async_buffer_head := 0; async_buffer_tail := 0;
  1264.     async_obuffer_overflow := false; { set up empty send buffer.         }
  1265.     async_obuffer_used := 0; async_maxobufferused := 0;
  1266.     async_obuffer_head := 0; async_obuffer_tail := 0;
  1267.     { set default wait time for output; buffer to drain when it fills up.}
  1268.     async_output_delay := 500; { no modem or line errors yet.       }
  1269.     async_line_status := 0; async_modem_status := 0;
  1270.     async_line_error_flags := 0; { get buffer sizes }
  1271.     if (async_buffer_max > 0) then
  1272.       async_buffer_size := async_buffer_max - 1 else
  1273.       async_buffer_size := 4095;
  1274.     if (async_obuffer_max > 0) then
  1275.       async_obuffer_size := async_obuffer_max - 1 else
  1276.       async_obuffer_size := 1131;
  1277.     { get receive buffer overflow; check-points. }
  1278.     if (async_low_lev > 0) then
  1279.       async_buffer_low := async_low_lev else
  1280.       async_buffer_low := async_buffer_size div 4;
  1281.     if (async_high_lev1 > 0) then
  1282.       async_buffer_high := async_high_lev1 else
  1283.       async_buffer_high := (async_buffer_size div 4) * 3;
  1284.     if (async_high_lev2 > 0) then
  1285.       async_buffer_high_2 := async_high_lev2 else
  1286.       async_buffer_high_2 := (async_buffer_size div 10) * 9;
  1287.     { allocate buffers }
  1288.     getmem(async_buffer_ptr, async_buffer_size  + 1);
  1289.     getmem(async_obuffer_ptr, async_obuffer_size + 1);
  1290.     { no uart addresses defined yet }
  1291.     async_uart_ier := 0; async_uart_iir := 0; async_uart_msr := 0; 
  1292.     async_uart_lsr := 0; async_uart_mcr := 0;
  1293.     { set default port addresses; and default irq lines }
  1294.     for i := 1 to maxcomports do begin
  1295.       com_base[i] := default_com_base [i];
  1296.       com_irq [i] := default_com_irq  [i];
  1297.       com_int [i] := default_com_int  [i];
  1298.     end;
  1299.     { get the delay loop value for 1 ms delay loops. }
  1300.     { you should turn off time sharing if running under a multitasker }
  1301.     { to get an accurate delay loop value.  if mtask is $defined,     }
  1302.     { then the calls to the ECOMDOS routines for interfacing with     }
  1303.     { multitaskers will be generated.                                 }
  1304. {$IFDEF MTASK}
  1305.     if timesharingactive then turnofftimesharing;
  1306. {$ENDIF}
  1307.     async_find_delay(async_onemsdelay);
  1308. {$IFDEF MTASK}
  1309.     if timesharingactive then turnontimesharing;
  1310. {$ENDIF}
  1311.   end;
  1312.  
  1313.  
  1314.  
  1315.  
  1316.   function async_carrier_detect: boolean;
  1317.   begin
  1318.     async_carrier_detect := 
  1319.       odd(port[uart_msr + async_base] shr 7) or
  1320.         async_hard_wired_on;
  1321.   end;
  1322.  
  1323.  
  1324.  
  1325.  
  1326.   function async_carrier_drop: boolean;
  1327.   begin
  1328.     async_carrier_drop := not(
  1329.       odd(port[ uart_msr + async_base ] shr 7) or
  1330.       async_hard_wired_on
  1331.     );
  1332.   end;
  1333.  
  1334.  
  1335.  
  1336.  
  1337.  
  1338.   procedure async_term_ready(ready_status: boolean);
  1339.   var mcr_value: byte;
  1340.   begin
  1341.     mcr_value := port[uart_mcr + async_base];
  1342.     if odd(mcr_value) then mcr_value := mcr_value - 1;
  1343.     if ready_status then mcr_value := mcr_value + 1;
  1344.     port[ uart_mcr + async_base ] := mcr_value;
  1345.     async_clear_errors;
  1346.   end;
  1347.  
  1348.  
  1349.  
  1350.  
  1351.   function async_buffer_check: boolean;
  1352.   begin
  1353.     async_buffer_check := (async_buffer_head <> async_buffer_tail);
  1354.   end;
  1355.  
  1356.  
  1357.  
  1358.  
  1359.   function async_line_error(var error_flags: byte): boolean;
  1360.   begin
  1361.     async_line_error := (async_line_error_flags <> 0);
  1362.     error_flags := async_line_error_flags;
  1363.     async_line_error_flags := 0;
  1364.   end;
  1365.  
  1366.  
  1367.  
  1368.  
  1369.   function async_ring_detect: boolean;
  1370.   begin
  1371.     async_ring_detect := odd(port[uart_msr + async_base] shr 6);
  1372.   end;
  1373.  
  1374.  
  1375.  
  1376.   
  1377.   procedure async_send_break;
  1378.   var
  1379.     old_lcr  : byte;
  1380.     break_lcr: byte;
  1381.  
  1382.   begin
  1383.     old_lcr  := port[ uart_lcr + async_base ];
  1384.     break_lcr := old_lcr;
  1385.     if break_lcr > 127 then break_lcr := break_lcr - 128;
  1386.     if break_lcr <=  63 then break_lcr := break_lcr +  64;
  1387.     port[ uart_lcr + async_base ] := break_lcr;
  1388.     delay(async_break_length * 10);
  1389.     port[ uart_lcr + async_base ] := old_lcr;
  1390.   end;
  1391.  
  1392.  
  1393.  
  1394.  
  1395.   procedure async_send_string(s: string);
  1396.   var i: integer;
  1397.   begin
  1398.     for i := 1 to length(s) do async_send(s[i])
  1399.   end;
  1400.  
  1401.  
  1402.  
  1403.  
  1404.   procedure async_send_string_with_delays(
  1405.     s : string; char_delay: integer; eos_delay : integer
  1406.   );
  1407.   var i: integer;
  1408.   begin
  1409.     if char_delay <= 0 then async_send_string(s) else
  1410.       for i :=1 to length(s) do begin async_send(s[i]);delay(char_delay) end;
  1411.     if eos_delay > 0 then delay(eos_delay);
  1412.   end;
  1413.  
  1414.  
  1415.  
  1416.  
  1417.   function async_percentage_used: real;
  1418.   begin
  1419.     async_percentage_used := async_buffer_used / (async_buffer_size + 1);
  1420.   end;
  1421.  
  1422.  
  1423.  
  1424.  
  1425.   procedure async_purge_buffer;
  1426.   var c: char; l: integer;
  1427.   begin
  1428.     l := 10000 div async_baud_rate;
  1429.     if l <= 0 then l := 3;
  1430.     repeat delay(l) until (not async_receive(c));
  1431.   end;
  1432.  
  1433.  
  1434.  
  1435.  
  1436.  
  1437.   function async_peek(nchars: integer): char;
  1438.   var i: integer;
  1439.   begin
  1440.     i := (async_buffer_tail + nchars) mod async_buffer_size;
  1441.     if (i > async_buffer_head) then async_peek := chr(0) else
  1442.       async_peek := async_buffer_ptr^[ i ];
  1443.   end;
  1444.  
  1445.  
  1446.  
  1447.  
  1448.   procedure async_setup_port(
  1449.     comport      : integer;
  1450.     base_address : integer;
  1451.     irq_line     : integer;
  1452.     int_numb     : integer
  1453.   );
  1454.   var port_offset: integer;
  1455.   begin
  1456.     if ((comport > 0) and (comport <= maxcomports)) then begin
  1457.       if (base_address = -1) then base_address := default_com_base[comport];
  1458.       if (irq_line = -1) then irq_line := default_com_irq[comport];
  1459.       if (int_numb = -1) then int_numb := default_com_int[comport];
  1460.       com_base[comport] := base_address;
  1461.       com_irq[comport] := irq_line;
  1462.       com_int[comport] := int_numb;
  1463.       port_offset := rs232_base + (pred(comport) shl 1);
  1464.       memw[$0:port_offset] := base_address;
  1465.     end;
  1466.   end;
  1467.  
  1468.  
  1469.  
  1470.  
  1471.   procedure async_release_buffers;
  1472.   begin { if port open, close it down first.  }
  1473.     if async_open_flag then async_close(false);
  1474.     freemem(async_buffer_ptr, async_buffer_size + 1);
  1475.     freemem(async_obuffer_ptr, async_obuffer_size + 1);
  1476.   end;
  1477.  
  1478.  
  1479.  
  1480.  
  1481.   procedure async_flush_output_buffer;
  1482.   begin
  1483.     async_obuffer_head := async_obuffer_tail; async_obuffer_used := 0;
  1484.   end;
  1485.  
  1486.  
  1487.  
  1488.  
  1489.   procedure async_drain_output_buffer(max_wait_time: integer);
  1490.   var t1: longint;
  1491.   begin
  1492.     t1 := timeofday;
  1493.     while(
  1494.       (async_obuffer_head <> async_obuffer_tail) and
  1495.       (timediff(t1 , timeofday) <= max_wait_time)
  1496.     ) do
  1497. {$IFDEF MTASK}
  1498.       giveuptime(1);
  1499. {$ELSE}
  1500.       ;
  1501. {$ENDIF}
  1502.   end;
  1503.  
  1504.  
  1505.  
  1506.  
  1507.   function async_port_address_given(com_port: integer): boolean;
  1508.   var port_offset: integer;
  1509.   begin
  1510.     if ((com_port > 0) and (com_port < maxcomports)) then begin
  1511.       port_offset := rs232_base + (pred(com_port) shl 1);
  1512.       async_port_address_given := (memw[$0:port_offset] <> 0);
  1513.     end else async_port_address_given := false;
  1514.   end;
  1515.  
  1516.  
  1517.  
  1518.  
  1519.   function yesno(st: string): boolean;
  1520.   var c: char;
  1521.   begin
  1522.     writeln(st); repeat c :=readkey until upcase(c) in ['Y','N'];
  1523.     if upcase(c)='Y' then yesno :=true else yesno :=false;
  1524.   end;
  1525.  
  1526.  
  1527.  
  1528.  
  1529.   procedure send_modem_command(modem_text: string);
  1530.   {----------------------------------------------------------------------}
  1531.   {     remarks:                                                         }
  1532.   {                                                                      }
  1533.   {          if the string to be sent has not "Wait For" markers, then   }
  1534.   {          it is sent in its entirety in one call here.  if there are  }
  1535.   {          "Wait For" characters, then the flag waitstring_mode is set }
  1536.   {          true, script_when_text is set to the character to be found, }
  1537.   {          and  script_when_reply_text is set to the remainder of the  }
  1538.   {          function key string.  this allows the terminal emulation to }
  1539.   {          properly process any received characters while pibterm is   }
  1540.   {          waiting for the selected string to appear.                  }
  1541.   {                                                                      }
  1542.   {----------------------------------------------------------------------}
  1543.   var
  1544.     i       : integer;
  1545.     l       : integer;
  1546.     ch      :    char;
  1547.     mo_char :    char;
  1548.     done    : boolean;
  1549.  
  1550.   begin { send_modem_command }
  1551.     l := length(modem_text); i := 1; done := false;
  1552.     while(i <= l) and (not done) do begin
  1553.       mo_char :=modem_text[i];
  1554.       if mo_char = fk_cr then async_send_now(chr(cr)) else
  1555.         if mo_char = fk_delay then delay(one_second_delay) else
  1556.           if mo_char = fk_wait_for then begin   { wait for }
  1557.           {
  1558.             inc(i);
  1559.             if (i<=l) then begin
  1560.               with script_wait_list[1] do begin
  1561.                 new(wait_text);
  1562.                 if (wait_text<>nil) then wait_text^ :=modem_text[i];
  1563.                 new(wait_reply); inc(i);
  1564.                 if (wait_reply<>nil) then begin
  1565.                 if (i<=l) then wait_reply^ :=copy(modem_text,i,succ(l-i))
  1566.               end else wait_reply^ :=''; script_wait_check_length :=1;
  1567.             end;
  1568.           end;
  1569.           script_wait_count    :=1;
  1570.           waitstring_mode      :=true;
  1571.           really_wait_string   :=true;
  1572.           script_wait_time     :=script_default_wait_time;
  1573.           if (script_wait_time<=0) then script_wait_time :=60;
  1574.           script_wait_failure  :=0;
  1575.           done                 :=true;
  1576.           script_wait_start    :=timeofday;
  1577.           }
  1578.         end else if mo_char = fk_ctrl_mark then begin
  1579.           if ((i+2)<=l) then if (modem_text[succ(i)] = '''') then inc(i,2);
  1580.           async_send_now(modem_text[i]);
  1581.         end else begin
  1582.           async_send_now(modem_text[i]);
  1583.           if (modem_command_delay>0) then delay(modem_command_delay);
  1584.         end; inc(i);
  1585.     end;
  1586.   end;
  1587.  
  1588.  
  1589.  
  1590.  
  1591.   function set_params(first_time: boolean): boolean;
  1592.   var i: integer;
  1593.   begin { set_params }
  1594.     if first_time then begin
  1595.       for i := 1 to maxcomports do async_setup_port(
  1596.         i, default_com_base[i], default_com_irq[i], default_com_int[i]
  1597.       );
  1598.       async_init(async_buffer_length, async_obuffer_length, 0, 0, 0);
  1599.       if ((async_buffer_ptr = nil) or (async_obuffer_ptr = nil)) then
  1600.         set_params := false else set_params := async_open(
  1601.           comm_port, baud_rate, parity, data_bits, stop_bits
  1602.         );
  1603.     end else begin
  1604.       set_params :=true;
  1605.       if reset_comm_port then async_reset_port(
  1606.         comm_port, baud_rate, parity, data_bits, stop_bits
  1607.       );
  1608.     end;
  1609.     async_do_cts := check_cts;              { reset cts check on/off        }
  1610.     async_do_dsr := check_dsr;              { reset dsr check on/off        }
  1611.     async_do_xonxoff := do_xon_xoff_checks; { reset xon/xoff check on/off   }
  1612.     async_ov_xonxoff := do_xon_xoff_checks;
  1613.     async_hard_wired_on := hard_wired;      { reset hard-wired status       }
  1614.     async_break_length := break_length;     { reset break length            }
  1615.   end;
  1616.  
  1617.  
  1618.  
  1619.  
  1620.  
  1621.  
  1622.   {████████████████████████████████████████████████████████████████████████}
  1623.  
  1624.  
  1625.  
  1626.  
  1627.  
  1628.  
  1629.   procedure initialize_modem;
  1630.   var
  1631.     done_flag: boolean;
  1632.     f        :    text;
  1633.     ch       :    char;
  1634.     do_init  : boolean;
  1635.  
  1636.  
  1637.     function modem_connected: boolean;
  1638.     var
  1639.       start_time: longint;
  1640.       timed_out: boolean;
  1641.     begin 
  1642.       port[uart_mcr+async_base] :=$0b;{ turn on out2, dtr, and rts }
  1643.       async_clear_errors;             { clear pending async errors   }
  1644.       start_time :=timeofday;        { wait for dsr using busy wait }
  1645.       timed_out :=false;
  1646.       if async_do_dsr then begin
  1647.         while (
  1648.           (not timed_out) and ((port[uart_msr+async_base] and $20)=0)
  1649.         ) do timed_out :=(timediff(start_time,timeofday) > 2);
  1650.         if timed_out then if attended_mode then begin
  1651.           async_do_dsr := yesno(
  1652.             '*** Data Set ready Doesn''t Work, turn it off (Y/N) ? '
  1653.           );
  1654.           timed_out :=async_do_dsr;
  1655.         end else writeln('*** Data Set ready turned off.');
  1656.       end;
  1657.       start_time :=timeofday;       { wait for cts using busy wait }
  1658.       if async_do_cts then begin
  1659.         while (
  1660.           (not timed_out) and ((port[uart_msr+async_base] and $10) = 0)
  1661.         ) do timed_out :=(timediff(start_time , timeofday) > 2);
  1662.         if timed_out then if attended_mode then begin
  1663.           async_do_cts := yesno(
  1664.             '*** Clear To send Doesn''t Work, turn it off (Y/N) ? '
  1665.           );
  1666.           timed_out :=async_do_cts;
  1667.         end else writeln('*** Clear To sEnd turned off.');
  1668.       end; { wait for transmit hold register empty (thre) }
  1669.       start_time := timeofday;
  1670.       while (
  1671.         (not timed_out) and ((port[uart_lsr+async_base] and $20) = 0)
  1672.       ) do timed_out :=(timediff(start_time , timeofday) > 2);
  1673.                  { if we looped through, modem probably not connected. }
  1674.       modem_connected := (not timed_out);
  1675.     end;
  1676.  
  1677.  
  1678.   begin
  1679.     { ensure correct setting of carrier detect status variables. }
  1680.     current_carrier_status := async_carrier_detect;
  1681.     new_carrier_status := current_carrier_status;
  1682.     { check status of hardware lines }
  1683.     if (not modem_connected) then begin
  1684.       if (not hard_wired) then begin
  1685.         writeln('*** Modem appears to be turned off.');
  1686.         writeln('*** Please turn it on and then hit any key to continue.');
  1687.       end else begin
  1688.         writeln('*** Hard-wired connection may be bad.');
  1689.         writeln('*** You may want to turn off CTS And DSR checking.');
  1690.         writeln('*** Hit any key to continue.');
  1691.       end;
  1692.       if attended_mode then begin
  1693.         ch := readkey; if (ch=#0) and keypressed then ch := readkey;
  1694.       end else writeln('*** Continuing anyway because of unattended mode.');
  1695.     end;                              { issue modem initialization string }
  1696.     if (modem_init<>'') and (not hard_wired) then begin
  1697.       if async_carrier_detect then begin
  1698.         writeln('*** Session appears to be already in progress.');
  1699.         if attended_mode then begin
  1700.           do_init := yesno('*** Send modem initialization anyway (Y/N) ? ');
  1701.         end else begin
  1702.           writeln('*** Modem initialization not performed.');
  1703.           do_init := false;
  1704.         end;
  1705.       end else do_init :=true;
  1706.       if do_init then begin
  1707.         {writeln('Modem initialization: ',write_ctrls(modem_init));}
  1708.         send_modem_command(modem_init);
  1709.         delay(one_second_delay);
  1710.         async_purge_buffer;
  1711.       end;
  1712.     end;
  1713.   end;
  1714.  
  1715.  
  1716.  
  1717.  
  1718.  
  1719.  
  1720.  
  1721.  
  1722. {unit}begin                          { default communications parameters }
  1723.   async_do_cts        := false;  async_do_dsr        := false;
  1724.   async_hard_wired_on := false;  async_break_length  := 500;
  1725.   async_do_xonxoff    := true;   async_ov_xonxoff    := true;
  1726.   async_buffer_length := 4096;   async_obuffer_length := 1132;
  1727.                                   { port addresses of each com port }
  1728.   default_com_base[1] := com1_base; default_com_base[2] := com2_base;
  1729.   default_com_base[3] := com3_base; default_com_base[4] := com4_base;
  1730.                                   { irq line for each port }
  1731.   default_com_irq [1] := com1_irq; default_com_irq [2] := com2_irq;
  1732.   default_com_irq [3] := com3_irq; default_com_irq [4] := com4_irq;
  1733.   { pick up address of send-a-character routine, which is used by inline  }
  1734.   { code.                                                                 }
  1735.   async_send_addr := addr(async_send);
  1736. {happy}end.
  1737.