home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / bbs / turbobbs.ark / MACHDEP.INT < prev    next >
Encoding:
Text File  |  1986-12-21  |  17.3 KB  |  535 lines

  1. {This is an expanded overlay file for IBM machines and compatibles
  2.  using the addresses corresponding to COM1:. It works on an IBM XT
  3.  using a Hayes Internal Modem (for sure!). The modem initialization
  4.  is for a Hayes Smartmodem. - Clarence Rudd CompuServe Id 73055,1740}
  5.  
  6. const
  7.   iodata    = $3f8;
  8.  
  9. (******************** Interupt handler *******************************)
  10.   CONST
  11.     irq4       = $30;                         { Interrupt vector address for }
  12.                                               { COM1.                        }
  13.     eoi        = $20;                         {                              }
  14.     ComPort1   = $03F8;                       { Port address of COM1.        }
  15.                                               { Offset to add  for           }
  16.     intenreg   = 1;                           {   Interrupt enable register  }
  17.     intidreg   = 2;                           {   Interrupt id register      }
  18.     linectrl   = 3;                           {   Line control register      }
  19.     modemctrl  = 4;                           {   Modem control register     }
  20.     linestat   = 5;                           {   Line status register       }
  21.     modemstat  = 6;                           {   Modem status register      }
  22.     buffsize   = 2048;                        { Size of the ring buffer      }
  23.  
  24.   TYPE                                        { Type declarations            }
  25.     bytechar   = record case boolean of
  26.                    true :(o:byte);
  27.                    false:(c:char)
  28.                  end;
  29.  
  30.     regrec     = record
  31.                    ax,bx,cx,dx,bp,di,si,ds,es,flags : integer;
  32.                  end;
  33.  
  34.   VAR
  35.     segment      : integer absolute cseg:$00A0;  { Address for storing DS    }
  36.     intbuffer    : array [0..buffsize] of bytechar;    { Ring buffer         }
  37.     oldvecseg,                                { Segment of DOS set           }
  38.     oldvecoff,                                { Offset of DOS set com int.   }
  39.     head,                                     { Index to the head of the     }
  40.                                               { ring buffer.                 }
  41.     tail,                                     { Tail index of the ring buff  }
  42.     i            : integer;                   { Counter                      }
  43.     ch,                                       { Temperary character buffer   }
  44.     tbyte,
  45.     lbyte        : byte;
  46.     showok       : boolean;
  47.     registers    : regrec;                    { Registers used in DOS call   }
  48.  
  49. {----------------------------------------------------------------------------
  50.  This is the interrupt handler for ComPort1.
  51.  Notice  the restoration of the DS register through a move to the AX from
  52.  address CS:00A0.  The absolute variable "segment" is initialized at the
  53.  begining of the program to contain the value of "DSEG".  The inline statments
  54.  should replace the current ones in the Turbo reference manual.
  55. ----------------------------------------------------------------------------}
  56.  
  57.   PROCEDURE IntHandler;
  58.  
  59.     BEGIN
  60.       inline( $50            { push ax        }
  61.              /$53            { push bx        }
  62.              /$51            { push cx        }
  63.              /$52            { push dx        }    { Save all the registers }
  64.              /$57            { push di        }
  65.              /$56            { push si        }
  66.              /$06            { push es        }
  67.              /$1E            { push ds        }
  68.              /$2E            { cs:            }
  69.              /$A1 /$A0 /$00  { mov ax, [00A0] }    { Get the Current data    }
  70.              /$50            { push ax        }    { segment                 }
  71.              /$1F            { pop ds         } ); { Restore the DS register }
  72.       tbyte := port[ ComPort1 ];               { Get the character in the port}
  73.       lbyte := port[ ComPort1 + linestat ];    { Get the status of the port   }
  74.       If ( head < buffsize ) then             { Check bounds of the ring     }
  75.         head := head + 1                      { buffer,  and if smaller then }
  76.       else                                    { increment by one otherwise   }
  77.         head := 0;                            { set to the first element     }
  78.       intbuffer[ head ].o := tbyte;           { Load the buffer w/ the char. }
  79.       port[$20] := $20;                       {                              }
  80.       inline( $1F            { pop ds         }
  81.              /$07            { pop es         }
  82.              /$5E            { pop si         }
  83.              /$5F            { pop di         }
  84.              /$5A            { pop dx         }
  85.              /$59            { pop cx         }   { Restore all registers  }
  86.              /$5B            { pop bx         }
  87.              /$58            { pop ax         }
  88.              /$5D            { pop     bp     }   { Reset the stack to its }
  89.              /$89 /$EC       { mov     sp,bp  }   { proper position        }
  90.              /$5D            { pop     bp     }
  91.              /$CF );         { iret           }   { Return                 }
  92.     END;
  93.  
  94. {-------------------------------------------------------------------------
  95.       The procedure IntOn sets up the interrupt handler vectors,  and
  96.  communication protocal.
  97. -------------------------------------------------------------------------}
  98.  
  99.   PROCEDURE IntOn;
  100.  
  101.     CONST
  102.       bits5=0;
  103.       bits6=1;
  104.       bits7=2;
  105.       bits8=3;
  106.       stopbit1=0;                             { These are constants used     }
  107.       stopbit2=4;                             { to define parity, stop bits, }
  108.       noparity=0;                             { data bits, etc.              }
  109.       parity=8;
  110.       evenparity=16;
  111.       dtrtrue=1;
  112.       rtstrue=2;
  113.       bit3true=8;
  114.  
  115.     VAR
  116.       tbyte   : byte;                         { Temperary byte buffer        }
  117.       i       : integer;                      { counter                      }
  118.  
  119.     BEGIN
  120.       head:=0;                                { Initialize the ring buffer   }
  121.       tail:=0;                                { indexes                      }
  122.       tbyte := port[ ComPort1 ];              { Read the ports to clear any  }
  123.       tbyte := port[ ComPort1 + linestat ];   { error conditions             }
  124.       port[ ComPort1 + linectrl ] := bits7 + stopbit1 + noparity;
  125.       port[ ComPort1 + intenreg ] := 1;       { Enable com port interrupts   }
  126.       tbyte := port[$21];                     {                              }
  127.       with registers do
  128.         begin
  129.           ax:=$2500;                          { Load the function number for }
  130.                                               { redefining an interrupt      }
  131.           ds:=cseg;                           { Get and set the segment and  }
  132.           dx:=ofs(IntHandler);                { offset of the handler        }
  133.         end;
  134.       oldvecoff:=memw[0000:irq4];             { Save the segment and offset  }
  135.       oldvecseg:=memw[0000:irq4+2];           { of the DOS interrupt handler }
  136.       registers.ax:=registers.ax+$0c;         { Use the COM1: interrupt    }
  137.       intr($21,registers);                    { Call DOS to reset INT 0C     }
  138.       port[$21]:=tbyte and $ef;               {                              }
  139.       inline($fb);                            { Enable interrupts            }
  140.     END;
  141.  
  142. {-----------------------------------------------------------------------------
  143.       This procedure restores the original system values to what they
  144.  were before the interrupt handler was set into action.
  145. -----------------------------------------------------------------------------}
  146.  
  147.   PROCEDURE IntOff;
  148.  
  149.     VAR
  150.       tbyte:byte;
  151.  
  152.     BEGIN
  153.       inline($FA);  { CLI }                   { Disable interrupts           }
  154.       tbyte:=port[$21];                       {                              }
  155.       port[ComPort1+intenreg]:=0;              { Disable COM interrupts       }
  156.       port[$21]:=tbyte or $10;            {                              }
  157.       memw[0000:irq4]:=oldvecoff;         { Restore the DOS interrupt    }
  158.       memw[0000:irq4+2]:=oldvecseg;       { handler                      }
  159.     END;
  160. {---------------------------------------------------------------------------
  161.       When the interrupt routine is called because of a com port interrupt
  162.  the head index is incremented by one,  but does not increment the tail
  163.  index.  This causes the two indexes to be unequal.
  164.  --------------------------------------------------------------------------}
  165.  
  166. (****************** End of interupt handler ******************)
  167.  
  168.  
  169. procedure lineout(message: line); forward;
  170.  {lineout is in IO.INC - don't change this declaration!}
  171.  
  172.  
  173.  
  174. procedure clearstatus;
  175. {Resets latching status flags on SIO chip -
  176.  replace with empty procedure if not needed}
  177.  
  178.   begin
  179.   end;
  180.  
  181. function outready: boolean;
  182. {Returns true if serial output port is
  183.  ready to transmit a new character}
  184.  
  185.   begin
  186.     outready := ((port[$3fd] and 32) > 0);
  187.   end;
  188.  
  189. procedure xmitchar(ch: char);
  190. {Transmits ch when serial output port is ready,
  191.    unless we're in the local mode.}
  192.  
  193.   begin
  194.     if not local then begin
  195.       repeat until outready;
  196.       port[iodata] := ord(ch);
  197.     end;
  198.   end;
  199.  
  200. function cts: boolean;
  201. {This function returns true if a carrier tone is present on the modem
  202.  and is frequently checked to see if the caller is still present.
  203.  It always returns "true" in the local mode.}
  204.  
  205.   begin
  206.     cts := ((port[$3fe] and 128) = 128) or local;
  207.   end;
  208.  
  209. function inready: boolean;
  210. {Returns true if we've got a character received
  211.  from the serial port or keyboard.}
  212.  
  213.   begin
  214.     inready := keypressed or (head<>tail);;
  215.   end;
  216.  
  217.  
  218. {-----------------------------------------------------------------------------
  219.       If the ring buffer indexes are not equal then recvchar returns the
  220.  char from either the COM1: or COM2: port.  The character is read from the
  221.  ring buffer and is stored in the FUNCTION result.
  222. -----------------------------------------------------------------------------}
  223. function recvchar: char;
  224. {Returns character from serial input port,
  225.   REGARDLESS of the status of inready.}
  226.     begin
  227.       If ( head <> tail ) then           { Check for ring buffer character   }
  228.         begin
  229.           If ( tail < buffsize ) then    { Check the limits of the ring      }
  230.             tail := tail + 1             { and set tail accordingly          }
  231.           else
  232.             tail := 0;
  233.           recvchar := intbuffer[tail].c;  { Get the character                 }
  234.         end
  235.       else recvchar := #0;
  236.     end;
  237.  
  238. procedure setbaud(speed: rate);
  239. {For changing the hardware baud rate setting}
  240.  
  241.   begin
  242.     port[$3fb] := 131;
  243.     case speed of
  244.       slow: begin
  245.               port[$3f8] := $80;
  246.               port[$3f9] := 1;
  247.             end;
  248.       fast: begin
  249.               port[$3f8] := $60;
  250.               port[$3f9] := $0;
  251.             end;
  252.     end;
  253.     port[$3fb] := 3;
  254.     baud := speed;
  255.   end;
  256.  
  257. procedure clearSIO;
  258. { Initializes serial I/O chip:
  259.   sets up for 8 bits, no parity and one stop bit on both
  260.   transmit and receive, and allows character transmission
  261.   with CTS low. Also sets RTS line high. }
  262.  
  263.   begin
  264.     port[$3fb] := 3;
  265.     port[$3f9] := 0;
  266.     port[$3fc] := 11;
  267.   end;
  268.  
  269. procedure SETmodem;        (* Modem Dependent *)
  270. {Sets modem for auto-answer, CTS line as carrier detect, no command echo}
  271.  
  272.   var buffer: line;
  273.       loop  : byte;
  274.       ch,t    : char;
  275.  
  276.   begin
  277.     buffer := 'ATS0=1 S2=255 S7=30 Q1 E0  ';
  278.     writeln('Setting modem for BBS operation');
  279.     for loop := 1 to length(buffer) do begin
  280.       ch := buffer[loop];
  281.       xmitchar(ch);
  282.       t := recvchar;
  283.       if t in [' '..'~'] then write(t);
  284.       delay(100);
  285.     end;
  286.     xmitchar(#13);
  287.     writeln;
  288.     write('Delaying...');
  289.     delay(1000); {Delays while modem digests initialization codes}
  290.     writeln;
  291.   end;
  292.  
  293.  
  294.  
  295.  
  296. procedure RESETmodem;        (* Modem Dependent *)
  297. {Sets modem for normal command mode}
  298.  
  299.   var buffer: line;
  300.       loop  : byte;
  301.       ch,t    : char;
  302.  
  303.   begin
  304.     buffer := 'ATS0=0 S2=43 Q0 E1  ';
  305.     writeln('Re-setting modem for normal use');
  306.     for loop := 1 to length(buffer) do begin
  307.       ch := buffer[loop];
  308.       xmitchar(ch);
  309.       t := recvchar;
  310.       if t in [' '..'~'] then write(t);
  311.       delay(100);
  312.     end;
  313.     xmitchar(#13);
  314.     writeln;
  315.     write('Delaying...');
  316.     delay(1000); {Delays while modem digests initialization codes}
  317.     writeln;
  318.   end;
  319.  
  320. procedure setup;
  321. {Hardware initializion for system to start BBS program}
  322.  
  323.   begin
  324.     clearSIO;
  325.     head := 0;
  326.     tail := 0;
  327.     segment := dseg;                { segment is an absolute variable used  }
  328.                                     { by the interrupt routine to restore   }
  329.                                     { the DS register to point to the DSEG  }
  330.     IntOn;                          { Set up the interrupt routine          }
  331.     setbaud(fast);
  332.     SETmodem;
  333.   end;
  334.  
  335. procedure ResetSystem;
  336.   begin
  337.     ReSetModem;  { prevent modem from answering call while system down }
  338.     IntOff;      { turn off the interupts }
  339.     if D_Dos then
  340.       begin
  341.         Time_Share(True);
  342.         Set_Low;
  343.       end;
  344.      window(1,1,80,25); { return screen to normal}
  345.   end;
  346.  
  347.  
  348. function badframe: boolean;
  349. {Indicates Framing Error on serial I/O chip - return false if not available.}
  350.  
  351.   begin
  352.   end;
  353.  
  354. procedure dropRTS;
  355. { Lowers RS-232 RTS line - used to inhibit auto-answer
  356.    and to cause modem to hang up }
  357.  
  358.   begin
  359.     port[$3fc] := 8;
  360.   end;
  361.  
  362. procedure raiseRTS;
  363. (* Raises RTS line to enable auto-answer *)
  364.  
  365.   begin
  366.     port[$3fc] := 11;
  367.   end;
  368.  
  369. procedure setlocal;
  370. {Sets local flag true and inhibits modem auto-answer}
  371.  
  372.   begin
  373.     dropRTS; {Inhibits auto-answer}
  374.     local := true;
  375.   end;
  376.  
  377. procedure clearlocal;
  378. {Clears local flag and allows modem auto-answer}
  379.  
  380.   begin
  381.     raiseRTS; {Enables Auto-answer}
  382.     local := false;
  383.   end;
  384.  
  385. procedure unload;
  386. {Halts Kaypro disk drives - normally they run for about 15 secs.}
  387.  
  388.   begin
  389.   end;
  390.  
  391. procedure dispcaller;
  392. {Displays caller's name on protected 25th line of host CRT;
  393.  Replace with empty procedure if not desired.}
  394.   var
  395.     x, y : integer;
  396.  
  397.   begin
  398.     x := wherex;
  399.     y := wherey;
  400.     window(1,1,80,25);
  401.     textcolor(LightGreen);
  402.     gotoxy(10,25);
  403.     write(caller);
  404.     if clockin then write(' called at ',timeon);
  405.     clreol;
  406.     textcolor(Green);
  407.     window(1,1,80,24);
  408.     gotoxy(x,y);
  409.   end;
  410.  
  411. procedure hangup;
  412. {Signals modem to hang up - in this case by lowering RTS line for 500 msec.}
  413.  
  414.   begin
  415.     if cts then lineout('--- Disconnected ---' + cr + lf);
  416.     dropRTS;
  417.     delay(1000);
  418.     if local then clearlocal else repeat until not cts;
  419.     raiseRTS;
  420.   end;
  421.  
  422. procedure flush_input;
  423.  
  424.   begin
  425.     head := 0;
  426.     Tail := 0;
  427.   end;
  428.  
  429. procedure CallBack(buffer: longname);        (* Modem Dependent *)
  430. {has modem place call }
  431.  
  432.   var loop  : byte;
  433.       ch,t    : char;
  434.  
  435.   begin
  436.     delay(1000);
  437.     flush_input;
  438.     for loop := 1 to length(buffer) do begin
  439.       ch := buffer[loop];
  440.       xmitchar(ch);
  441.       t := recvchar;
  442.       if t in [' '..'~'] then write(t);
  443.       delay(100);
  444.     end;
  445.     xmitchar(#13);
  446.     loop := 0;
  447.     repeat
  448.       loop := loop + 1;
  449.       delay(1000);
  450.     until (loop = 60) or cts;
  451.   end;
  452.  
  453.  
  454.  
  455. {Real-time clock support begins here - this routine is called
  456.  even if there is NO clock, so leave it and set clockin accordingly}
  457.  
  458. procedure clock(var month,date,hour,min,sec: byte);
  459.  
  460. {Returns with month in range 1(Jan)..12(Dec),
  461.  date in 1..length of month, hour in 0..23 (24-hr clock),
  462.  minute and second in 0..59}
  463.  
  464.   var
  465.     temp: integer;
  466.     tempint: integer;
  467.     temp1: byte;
  468.  
  469.   const monthmask = $000F;
  470.         daymask = $001F;
  471.         minutemask = $003F;
  472.         secondmask = $001F;
  473.   type  dtstr = string[8];
  474.         Register        = Record
  475.                           AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : Integer;
  476.                           End;
  477.   var  tstr : dtstr;
  478.  
  479.   function getdate : dtstr;
  480.  
  481.   var
  482.     allregs : register;
  483.     month, day,
  484.     year    : string[2];
  485.     i       : integer;
  486.     tstr    : dtstr;
  487.  
  488.   begin
  489.      allregs.ax := $2A * 256;
  490.      MsDos(allregs);
  491.      str((allregs.dx div 256):2,month);
  492.      str((allregs.dx mod 256):2,day);
  493.      str((allregs.cx - 1900):2,year);
  494.      tstr := month + '/' + day + '/' + year;
  495.      for i := 1 to 8 do
  496.        if tstr[i] = ' ' then
  497.          tstr[i] := '0';
  498.      getdate := tstr;
  499.   end;  {getdate}
  500.  
  501.   function gettime : dtstr;
  502.  
  503.   var
  504.    allregs : register;
  505.    hour, minute,
  506.    second  : string[2];
  507.    i       : integer;
  508.    tstr    : dtstr;
  509.  
  510.   begin
  511.      allregs.ax := $2C * 256;
  512.      MsDos(allregs);
  513.      str((allregs.cx div 256):2,hour);
  514.      str((allregs.cx mod 256):2,minute);
  515.      str((allregs.dx div 256):2,second);
  516.      tstr := hour + ':' + minute + ':' + second;
  517.      for i := 1 to 8 do
  518.        if tstr[i] = ' ' then
  519.          tstr[i] := '0';
  520.      gettime := tstr;
  521.   end;  {gettime}
  522.  
  523.   begin
  524.     val(copy(getdate,1,2),tempint,temp);
  525.     month := lo(tempint);
  526.     val(copy(getdate,4,2),tempint,temp);
  527.     date := lo(tempint);
  528.     val(copy(gettime,1,2),tempint,temp);
  529.     hour := lo(tempint);
  530.     val(copy(gettime,4,2),tempint,temp);
  531.     min := lo(tempint);
  532.     val(copy(gettime,7,2),tempint,temp);
  533.     sec := lo(tempint);
  534.   end;
  535.