home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1988 / 02 / lindley / lindley.ls5 < prev   
Text File  |  1987-08-16  |  38KB  |  1,624 lines

  1. {************************************************}
  2. {***                                          ***}
  3. {***                Turbo Pascal              ***}
  4. {***         Serial Protocol Analyzer         ***}
  5. {***                 written by               ***}
  6. {***              Craig A. Lindley            ***}
  7. {***                                          ***}
  8. {***    Ver: 2.0     Last update: 08/15/87    ***}
  9. {***                                          ***}
  10. {************************************************}
  11.  
  12. {$K-,U-,C-,G30,D-}
  13.  
  14. { ------- Notes on compiler directives --------- }
  15. { K-     No stack checking otherwise multitasking}
  16. {         kernal will not run.                   }
  17. { U-,C-  Turn off user break checks to speed     }
  18. {         screen I/O.                            }
  19. { G30,D- Buffer standard input device (keyboard) }
  20. {         and disable device checks. This makes  }
  21. {         keyboard respond much faster and be    }
  22. {         buffered.                              }
  23.  
  24. CONST
  25.  
  26.  HexDigits:  STRING[16] = '0123456789ABCDEF';
  27.  
  28.  AsciiStrs: ARRAY[0..31] OF STRING[3] =
  29.  ('Nul','Soh','Stx','Etx','Eot','Enq','Ack','Bel',
  30.   'Bs' ,'Ht' ,'Lf' ,'Vt' ,'Ff' ,'Cr' ,'So' ,'Si' ,
  31.   'Dle','Dc1','Dc2','Dc3','Dc4','Nak','Syn','Etb',
  32.   'Can','Em' ,'Sub','Esc','Fs' ,'Gs' ,'Rs' ,'Vs');
  33.  
  34.  
  35.  SerialDataFifoSize = 2000;  {serial data fifo size}
  36.  DisplayFifoSize    = 3000;  {display fifo size}
  37.  
  38.  {$I multi.pas}              {include the}
  39.                              {multitasking kernel}
  40.  
  41. TYPE
  42.  
  43.  FullString  = STRING[255];
  44.  Str80       = STRING[80];
  45.  Str3        = STRING[3];
  46.  
  47.  DataRec = RECORD
  48.   Data,
  49.   Status:  Byte;
  50.  END;
  51.  
  52.  DisplayRec = RECORD
  53.   Tag: (FromCOM1,FromCOM2);
  54.   DR: DataRec;
  55.  END;
  56.  
  57. {This fifo overhead structure is the same for}
  58. {all fifo types regardless of the items to be}
  59. {stored in the fifo. Two types are fifos are }
  60. {defined.}
  61.  
  62.  OverHead = RECORD     {fifo overhead data}
  63.                        {structure}
  64.     Count,             {# of items in fifo}
  65.     Inptr,             {ptr to where items are}
  66.                        {stored}
  67.     Outptr:   Integer; {ptr to where items are}
  68.                        {fetched}
  69.     NotEmpty,         {ptrs to waiting tasks}
  70.     NotFull:  tcbptr;
  71.  END;
  72.  
  73.  
  74.  {definition of a serial data fifo}
  75.  SerialDataFifo = RECORD
  76.    Ovd:  OverHead;           {fifo overhead}
  77.    Data: ARRAY[1..SerialDataFifoSize]
  78.            OF DataRec;       {fifo data area}
  79.  END;
  80.  
  81.  {definition of display fifo}
  82.  DisplayFifoType = RECORD
  83.    Ovd:  OverHead;
  84.    Data: ARRAY[1..DisplayFifoSize]
  85.            OF DisplayRec;
  86.  END;
  87.  
  88.  DisplayTriggerType = (Before,After);
  89.  
  90. VAR
  91.  
  92.  regs:        register_type;
  93.  
  94.  {storage for the original IRQ3 & 4 code segment}
  95.  {and instruction pointer addresses}
  96.  
  97.  OldIRQ3_CS,
  98.  OldIRQ3_IP,
  99.  OldIRQ4_CS,
  100.  OldIRQ4_IP:  Integer;
  101.  
  102.  {UART status storage variables}
  103.  
  104.  OldCOM1_Status,
  105.  OldCOM2_Status,
  106.  COM1_Status,
  107.  COM2_Status: Byte;
  108.  
  109.  {Display formatting boolean flags}
  110.  
  111.  UpdateScreenStatus,
  112.  AsciiDisplay,
  113.  HandShakeDisplay,
  114.  AddSpace,
  115.  
  116.  {Data display boolean flags}
  117.  {If true the data from the specified COM port}
  118.  {is tagged and then moved into the display fifo}
  119.  
  120.  COM1_Display_Data,
  121.  COM2_Display_Data,
  122.  
  123.  {Data Acquisition boolean flags}
  124.  {Controls acquisiton of data by the Interrupt}
  125.  {Serivce Routines. If true then serial data is}
  126.  {stored by the ISR.}
  127.  
  128.  COM1_Data_Acquire,
  129.  COM2_Data_Acquire,
  130.  
  131.  {Variables used for the triggering function}
  132.  
  133.  TriggerEnabled,
  134.  COM1_Is_Triggered,
  135.  COM2_Is_Triggered:  Boolean;
  136.  TriggerPattern:     Integer;
  137.  TriggerMode:        DisplayTriggerType;
  138.  
  139.  {Fifo declarations}
  140.  
  141.  COM1_Input_Fifo,
  142.  COM2_Input_Fifo,
  143.  COM1_Output_Fifo,
  144.  COM2_Output_Fifo:   SerialDataFifo;
  145.  
  146.  DisplayFifo:        DisplayFifoType;
  147.  
  148.  {Screen formatting strings built at run time to}
  149.  {format the screen.}
  150.  
  151.  Line1, Line2,
  152.  Line3, Line4,
  153.  Line5, Line6,
  154.  Line24:        Str80;
  155.  
  156.  {Cursor storage for DisplayCOMData procedure}
  157.  
  158.  OldXPos,
  159.  OldYPos:  Integer;
  160.  
  161.  {Lock for screen control}
  162.  ScreenAccess: Semaphore;
  163.  
  164. {************ Begin FIFO Procedures ************}
  165.  
  166. PROCEDURE Init_Fifos;
  167.  
  168.  PROCEDURE Initialize_fifo(VAR o:OverHead);
  169.  
  170.  {Initialize a fifo's overhead data structure.}
  171.  {This procedure will work with any type fifo.}
  172.  {This makes the fifo appear empty.}
  173.  
  174.  BEGIN
  175.  
  176.     o.Count  := 0;       {count is empty}
  177.     o.Inptr  := 1;       {ptrs to 1st entry}
  178.     o.Outptr := 1;       {put in and take out at}
  179.                          {entry 1}
  180.     o.NotEmpty :=NIL;    {signals to nil}
  181.     o.NotFull  :=NIL;
  182.  
  183.  END;
  184.  
  185. BEGIN
  186.  
  187.    Initialize_fifo(COM1_Input_fifo.Ovd);
  188.    Initialize_fifo(COM1_Output_fifo.Ovd);
  189.    Initialize_fifo(COM2_Input_fifo.Ovd);
  190.    Initialize_fifo(COM2_Output_fifo.Ovd);
  191.    Initialize_fifo(DisplayFifo.Ovd);
  192.  
  193. END;
  194.  
  195.  
  196. PROCEDURE PutSerialData (d:DataRec;
  197.                          VAR f:SerialDataFifo);
  198.  
  199. BEGIN
  200.  
  201.    WITH f.Ovd DO
  202.    BEGIN                {check if fifo full}
  203.       IF Count = SerialDataFifoSize THEN
  204.       BEGIN             {if so go to sleep}
  205.          waitfor := addr (NotFull);
  206.          wait;
  207.       END;              {when not full add}
  208.       Count:=Count+1;   {one more to count}
  209.       f.data[Inptr]:=d; {store the data record}
  210.       Inptr:=Inptr+1;   {bump input pointer}
  211.       IF Inptr > SerialDataFifoSize THEN
  212.          Inptr:=1;      {wrap ptr if necessary}
  213.  
  214.       {if waiters for this fifo wake them}
  215.  
  216.       IF NotEmpty <> NIL THEN
  217.          send(NotEmpty);
  218.    END;
  219.  
  220. END;
  221.  
  222.  
  223. PROCEDURE GetSerialData (VAR f:SerialDataFifo;
  224.                          VAR d:DataRec);
  225.  
  226. BEGIN
  227.  
  228.    WITH f.Ovd DO
  229.    BEGIN               {check if fifo empty}
  230.       IF Count = 0 THEN
  231.       BEGIN            {if so go to sleep}
  232.          waitfor := addr (NotEmpty);
  233.          wait;
  234.       END;
  235.                        {when data is available}
  236.       Count:=Count-1;  {one less to count}
  237.       d :=f.data[Outptr];  {get the data record}
  238.       Outptr:=Outptr+1;{bump output pointer}
  239.       IF Outptr > SerialDataFifoSize THEN
  240.          Outptr:=1;    {wrap ptr if necessary}
  241.       {if waiters for this fifo wake them}
  242.  
  243.       IF NotFull <> NIL THEN
  244.          send(NotFull);
  245.    END;
  246.  
  247. END;
  248.  
  249.  
  250. PROCEDURE PutDisplayData (d:DisplayRec;
  251.                       VAR f:DisplayFifoType);
  252.  
  253. BEGIN
  254.  
  255.    WITH f.Ovd DO
  256.    BEGIN                {check if fifo full}
  257.       IF Count = DisplayFifoSize THEN
  258.       BEGIN             {if so go to sleep}
  259.          waitfor := addr (NotFull);
  260.          wait;
  261.       END;              {when not full add}
  262.       Count:=Count+1;   {one more to count}
  263.       f.data[Inptr]:=d; {store the data record}
  264.       Inptr:=Inptr+1;   {bump input pointer}
  265.       IF Inptr > DisplayFifoSize THEN
  266.          Inptr:=1;      {wrap ptr if necessary}
  267.  
  268.       {if waiters for this fifo wake them}
  269.  
  270.       IF NotEmpty <> NIL THEN
  271.          send(NotEmpty);
  272.    END;
  273.  
  274. END;
  275.  
  276.  
  277. PROCEDURE GetDisplayData (VAR f:DisplayFifoType;
  278.                           VAR d:DisplayRec);
  279.  
  280. BEGIN
  281.  
  282.    WITH f.Ovd DO
  283.    BEGIN               {check if fifo empty}
  284.       IF Count = 0 THEN
  285.       BEGIN            {if so go to sleep}
  286.          waitfor := addr (NotEmpty);
  287.          wait;
  288.       END;
  289.                        {when data is available}
  290.       Count:=Count-1;  {one less to count}
  291.       d :=f.data[Outptr];  {get the data record}
  292.       Outptr:=Outptr+1;{bump output pointer}
  293.       IF Outptr > DisplayFifoSize THEN
  294.          Outptr:=1;    {wrap ptr if necessary}
  295.  
  296.       {if waiters for this fifo wake them}
  297.  
  298.       IF NotFull <> NIL THEN
  299.          send(NotFull);
  300.  
  301.    END;
  302.  
  303. END;
  304.  
  305. {Include the menuing system}
  306.  
  307. {$I menu.pas}
  308.  
  309. {Include the serial procedures}
  310.  
  311. {$I serial.pas}
  312.  
  313. {********* Additional Serial Procedures *********}
  314.  
  315.  
  316. PROCEDURE SetBreak (PortAddr:Integer; State:Boolean);
  317.  
  318. {Controls the break generation for the specified}
  319. {COM port.}
  320.  
  321. VAR
  322.  
  323.  Temp:  Byte;
  324.  
  325. BEGIN
  326.  
  327.    {Read the LineControl reg of the 8250}
  328.    {either set or reset the break bit D6}
  329.    {as specified. Write the new reg value}
  330.    {back to the port}
  331.  
  332.    Temp := port[PortAddr+LineControl];
  333.    IF State THEN
  334.       Temp := Temp OR $40
  335.    ELSE
  336.       Temp := Temp AND $BF;
  337.    port[PortAddr+LineControl] := Temp;
  338.  
  339. END;
  340.  
  341.  
  342. PROCEDURE MakeHandShake (PortAddr:Integer;
  343.                          Status:Byte);
  344.  
  345. VAR
  346.  
  347.  Temp:   Byte;
  348.  
  349. BEGIN
  350.  
  351.    {Set the bits in the ModemControl reg of the}
  352.    {specified COM port according to the bits}
  353.    {of the variable Status. This procedure is}
  354.    {used to always force the handshake lines of}
  355.    {the COM ports to agree}
  356.  
  357.    Temp := port[PortAddr+ModemControl];
  358.  
  359.    IF (Status AND BrkBit) <> 0 THEN
  360.       SetBreak(PortAddr,True)
  361.    ELSE
  362.       SetBreak(PortAddr,False);
  363.  
  364.    IF (Status AND CTSBit) <> 0 THEN
  365.       Temp := Temp OR $02
  366.    ELSE
  367.       Temp := Temp AND $FD;
  368.  
  369.    IF (Status AND DSRBit) <> 0 THEN
  370.       Temp := Temp OR $01
  371.    ELSE
  372.       Temp := Temp AND $FE;
  373.  
  374.    {Store the new value of the ModemControl}
  375.    {register back}
  376.  
  377.    port[PortAddr+ModemControl] := Temp;
  378.  
  379. END;
  380.  
  381.  
  382. {************** Display Procedures *************}
  383.  
  384. PROCEDURE BuildDisplay;
  385.  
  386. {Setup the main SPA display screen}
  387. {The OldCOM?_Status variables are consciencely}
  388. {clobbered to force the screen to be updated}
  389. {after it is built or rebuilt after the menus}
  390. {are displayed}
  391.  
  392. BEGIN
  393.  
  394.    OldCOM1_Status    := $FF;
  395.    OldCOM2_Status    := $FF;
  396.  
  397.    WriteStringAt(Line1,High,1,1);
  398.    WriteStringAt(Line2,Low,1,2);
  399.    WriteStringAt(Line3,Low,1,3);
  400.    WriteStringAt(Line4,Low,1,4);
  401.    WriteStringAt(Line5,Low,1,5);
  402.    WriteStringAt(Line6,Low,1,6);
  403.    WriteStringAt(Line24,Rev,1,24);
  404.  
  405. END;
  406.  
  407.  
  408. PROCEDURE DisplayHandShakeStatus (PortAddr:Integer;
  409.                                   InStatus,
  410.                                   OutStatus:Byte);
  411.  
  412. CONST
  413.  
  414.  StatLineNum = 3; {screen line of line status}
  415.  InLineNum   = 4; {screen line of in handshake}
  416.                   {lines}
  417.  OutLineNum  = 5; {screen line of out handshake}
  418.                   {lines}
  419.  
  420.  CDOffset  = 11;  {offsets on a screen line for}
  421.  RIOffset  = 16;  {the individual items to be}
  422.  DSROffset = 22;  {displayed}
  423.  CTSOffset = 28;
  424.  BRKOffset = 13;
  425.  FEOffset  = 18;
  426.  PEOffset  = 23;
  427.  OROffset  = 28;
  428.  DTROffset = 12;
  429.  RTSOffset = 22;
  430.  
  431. VAR
  432.  
  433.  DisplayOffset:  Integer;
  434.  Ind:            Char;
  435.  
  436. BEGIN
  437.  
  438.    {Where an item is displayed is determined in}
  439.    {part by which COM status is being displayed}
  440.    {COM1's offset is 0 whereas COM2's offset is}
  441.    {51 character positions.}
  442.  
  443.    IF PortAddr = COM1 THEN
  444.       DisplayOffset := 0
  445.    ELSE
  446.       DisplayOffset := 51;
  447.  
  448.    IF (InStatus AND BrkBit) <> 0 THEN
  449.       Ind := 'B'
  450.    ELSE
  451.       Ind := '-';
  452.    WriteStringAt(Ind,High,
  453.                  BRKOffset+DisplayOffset,
  454.                  StatLineNum);
  455.  
  456.    IF (InStatus AND FEBit) <> 0 THEN
  457.       Ind := 'E'
  458.    ELSE
  459.       Ind := '-';
  460.    WriteStringAt(Ind,High,
  461.                  FEOffset+DisplayOffset,
  462.                  StatLineNum);
  463.  
  464.    IF (InStatus AND PEBit) <> 0 THEN
  465.       Ind := 'E'
  466.    ELSE
  467.       Ind := '-';
  468.    WriteStringAt(Ind,High,
  469.                  PEOffset+DisplayOffset,
  470.                  StatLineNum);
  471.  
  472.    IF (InStatus AND ORBit) <> 0 THEN
  473.       Ind := 'E'
  474.    ELSE
  475.       Ind := '-';
  476.    WriteStringAt(Ind,High,
  477.                  OROffset+DisplayOffset,
  478.                  StatLineNum);
  479.  
  480.    IF (InStatus AND CDBit) <> 0 THEN
  481.       Ind := 'M'
  482.    ELSE
  483.       Ind := 'S';
  484.    WriteStringAt(Ind,High,
  485.                  CDOffset+DisplayOffset,
  486.                  InLineNum);
  487.  
  488.    IF (InStatus AND RIBit) <> 0 THEN
  489.       Ind := 'M'
  490.    ELSE
  491.       Ind := 'S';
  492.    WriteStringAt(Ind,High,
  493.                  RIOffset+DisplayOffset,
  494.                  InLineNum);
  495.  
  496.    IF (InStatus AND DSRBit) <> 0 THEN
  497.       Ind := 'M'
  498.    ELSE
  499.       Ind := 'S';
  500.    WriteStringAt(Ind,High,
  501.                  DSROffset+DisplayOffset,
  502.                  InLineNum);
  503.  
  504.    IF (InStatus AND CTSBit) <> 0  THEN
  505.       Ind := 'M'
  506.    ELSE
  507.       Ind := 'S';
  508.    WriteStringAt(Ind,High,
  509.                  CTSOffset+DisplayOffset,
  510.                  InLineNum);
  511.  
  512.    {Note: The OTHER COM port is consulted about}
  513.    {the output status. DTR of this port should}
  514.    {equal DSR of other port. RTS of this port}
  515.    {should equal CTS of other port}
  516.  
  517.    IF (OutStatus AND DSRBit) <> 0 THEN
  518.       Ind := 'M'
  519.    ELSE
  520.       Ind := 'S';
  521.    WriteStringAt(Ind,High,
  522.                  DTROffset+DisplayOffset,
  523.                  OutLineNum);
  524.  
  525.    IF (OutStatus AND CTSBit) <> 0  THEN
  526.       Ind := 'M'
  527.    ELSE
  528.       Ind := 'S';
  529.    WriteStringAt(Ind,High,
  530.                  RTSOffset+DisplayOffset,
  531.                  OutLineNum);
  532.  
  533. END;
  534.  
  535.  
  536. PROCEDURE DisplayBufferStatus;
  537.  
  538. VAR
  539.  
  540.  PerCentage:  Integer;
  541.  PerCentStr:  Str80;
  542.  
  543. BEGIN
  544.  
  545.    PerCentage := Round((COM1_Input_Fifo.Ovd.Count/
  546.                         SerialDataFifoSize) * 100);
  547.    Str(PerCentage:2,PerCentStr);
  548.    WriteStringAt(PerCentStr + '%',High,12,2);
  549.  
  550.    PerCentage := Round((COM1_Output_Fifo.Ovd.Count/
  551.                         SerialDataFifoSize) * 100);
  552.    Str(PerCentage:2,PerCentStr);
  553.    WriteStringAt(PerCentStr + '%',High,26,2);
  554.  
  555.    PerCentage := Round((COM2_Input_Fifo.Ovd.Count/
  556.                         SerialDataFifoSize) * 100);
  557.    Str(PerCentage:2,PerCentStr);
  558.    WriteStringAt(PerCentStr + '%',High,63,2);
  559.  
  560.    PerCentage := Round((COM2_Output_Fifo.Ovd.Count/
  561.                         SerialDataFifoSize) * 100);
  562.    Str(PerCentage:2,PerCentStr);
  563.    WriteStringAt(PerCentStr + '%',High,77,2);
  564.  
  565.    PerCentage := Round((DisplayFifo.Ovd.Count/
  566.                         DisplayFifoSize) * 100);
  567.    Str(PerCentage:2,PerCentStr);
  568.    WriteStringAt(PerCentStr + '%',High,47,5);
  569.  
  570. END;
  571.  
  572.  
  573. FUNCTION FormatCharAscii (Num:Integer) : Str3;
  574.  
  575. BEGIN
  576.  
  577.    IF Num < ORD(' ') THEN
  578.        FormatCharAscii := AsciiStrs[Num]
  579.    ELSE
  580.        FormatCharAscii := chr(Num);
  581.  
  582. END;
  583.  
  584.  
  585. FUNCTION FormatCharHex (Num:Integer) : Str3;
  586.  
  587. BEGIN
  588.  
  589.    FormatCharHex :=
  590.       HexDigits[(Num SHR 4) AND $000F +1 ] +
  591.       HexDigits[(Num AND $000F) + 1];
  592.  
  593. END;
  594.  
  595.  
  596. FUNCTION DisplayData (D:DisplayRec) : Integer;
  597.  
  598. VAR
  599.  
  600.  VideoAttrib:  AttribType;
  601.  Temp:         STRING[7];
  602.  
  603. BEGIN
  604.  
  605.    WITH D DO
  606.    BEGIN
  607.       {If data from either channel should be}
  608.       {displayed then...}
  609.  
  610.       IF (((Tag = FromCOM1) AND COM1_Display_Data)  OR
  611.           ((Tag = FromCOM2) AND COM2_Display_Data)) THEN
  612.       BEGIN
  613.          {set video attribute depending upon}
  614.          {which COM channel it is from}
  615.          IF Tag = FromCOM1 THEN
  616.             VideoAttrib := Low
  617.          ELSE
  618.             VideoAttrib := Rev;
  619.  
  620.          {choose ASCII or Hex format}
  621.          IF AsciiDisplay THEN
  622.             Temp := FormatCharAscii(DR.Data)
  623.          ELSE
  624.             Temp := FormatCharHex(DR.Data);
  625.  
  626.          IF HandShakeDisplay THEN
  627.             Temp := Temp + ':$'+
  628.                FormatCharHex(DR.Status);
  629.  
  630.          {write serial data string to display}
  631.          WriteString(Temp,VideoAttrib);
  632.  
  633.          {if formatting with spaces}
  634.          IF AddSpace THEN
  635.          BEGIN
  636.             {output space to display and add}
  637.             {a space to string for length calc}
  638.             write(' ');
  639.             Temp := Temp + ' ';
  640.          END;
  641.  
  642.          {ret length of formatted item}
  643.          DisplayData := length(Temp);
  644.       END
  645.       ELSE
  646.          {if no data ret 0 length}
  647.          DisplayData := 0;
  648.    END;
  649.  
  650. END;
  651.  
  652. {*********** Miscellaneous Procedures ***********}
  653.  
  654. PROCEDURE Init_Program;
  655.  
  656. {Perform default initialization for protocol}
  657. {analyzer program}
  658.  
  659. BEGIN
  660.  
  661.    Init_Fifos;
  662.  
  663.    COM1_Data_Acquire := True;
  664.    COM2_Data_Acquire := True;
  665.  
  666.    COM1_Display_Data := True;
  667.    COM2_Display_Data := True;
  668.  
  669.    TriggerEnabled    := False;
  670.    COM1_Is_Triggered := False;
  671.    COM2_Is_Triggered := False;
  672.  
  673.    AsciiDisplay      := True;
  674.    HandShakeDisplay  := False;
  675.    AddSpace          := True;
  676.  
  677.    COM1_Status       := 0;
  678.    COM2_Status       := 0;
  679.  
  680.    {set serial com defaults 1200 baud, 8 bit word,
  681.    {1 stopbit, no parity}
  682.    {both COM ports always set the same}
  683.  
  684.    COM_Rate     := 8;          {1200 baud}
  685.    COM_StopBits := 1;
  686.    COM_DataBits := 8;
  687.    COM_Parity   := none;
  688.  
  689.    SetNewCOMParameter; {apply the parameters}
  690.  
  691. END;
  692.  
  693.  
  694. PROCEDURE VerifyHardware;
  695.  
  696. CONST
  697.  
  698.  TestByte = $5A;   {try to store and retrieve}
  699.                    {this value}
  700.  SafeByte = $03;   {set default 8 bits 1 stop}
  701.  
  702. BEGIN
  703.  
  704.    ClrScr;
  705.    {just in case of reentry}
  706.    Disable_Serial_Devices;
  707.  
  708.    WriteString('  Serial Protocol Analyzer Hardware Verification Check  '
  709.                ,Rev);
  710.    WriteStringAt('Checking COM1',HighBlink,2,3);
  711.    port[COM1+LineControl] := TestByte;
  712.    delay(700);
  713.    IF port[COM1+LineControl] <> TestByte THEN
  714.    BEGIN
  715.       WriteStringAt('COM1 Hardware Bad or Missing',
  716.                     Rev,2,3);
  717.       Halt;
  718.    END;
  719.    port[COM1+LineControl] := SafeByte;
  720.    WriteStringAt('COM1 Hardware Verified',
  721.                  Low,2,3);
  722.  
  723.    delay(700);
  724.    WriteStringAt('Checking COM2',HighBlink,
  725.                  2,4);
  726.    port[COM2+LineControl] := TestByte;
  727.    delay(500);
  728.    IF port[COM2+LineControl] <> TestByte THEN
  729.    BEGIN
  730.       WriteStringAt('COM2 Hardware Bad or Missing',
  731.                     Rev,2,4);
  732.       Halt;
  733.    END;
  734.    port[COM2+LineControl] := SafeByte;
  735.    WriteStringAt('COM2 Hardware Verified',Low,2,4);
  736.  
  737.    delay(2000);
  738.    ClrScr;
  739.  
  740. END;
  741.  
  742.  
  743. {****** Menu Command Processing Procedure *******}
  744.  
  745. {Declared forward previously}
  746.  
  747. PROCEDURE ProcessCmd;
  748.  
  749. VAR
  750.  
  751.  HexStr:    Str3;
  752.  HexChar,
  753.  ErrCode:   Integer;
  754.  Ch:        Char;
  755.  
  756. BEGIN
  757.  
  758.    IF cmd_code <> 0 THEN
  759.    BEGIN
  760.       CASE cmd_code OF
  761.          1: ExitMenu := True;
  762.          2: BEGIN   {300 baud}
  763.                COM_Rate := 6;
  764.                SetNewCOMParameter;
  765.             END;
  766.  
  767.         3: BEGIN   {600 baud}
  768.               COM_Rate := 7;
  769.               SetNewCOMParameter;
  770.            END;
  771.  
  772.        4: BEGIN   {1200 baud}
  773.              COM_Rate := 8;
  774.              SetNewCOMParameter;
  775.           END;
  776.  
  777.        5: BEGIN   {2400 baud}
  778.              COM_Rate := 11;
  779.              SetNewCOMParameter;
  780.           END;
  781.  
  782.        6: BEGIN   {4800 baud}
  783.              COM_Rate := 13;
  784.              SetNewCOMParameter;
  785.           END;
  786.  
  787.        7: BEGIN   {9600 baud}
  788.              COM_Rate := 15;
  789.              SetNewCOMParameter;
  790.           END;
  791.  
  792.        8: BEGIN   {1 stop bit}
  793.              COM_StopBits := 1;
  794.              SetNewCOMParameter;
  795.           END;
  796.  
  797.        9: BEGIN   {2 stop bit}
  798.              COM_StopBits := 2;
  799.              SetNewCOMParameter;
  800.           END;
  801.  
  802.       10: BEGIN   {5 bit word}
  803.              COM_DataBits := 5;
  804.              SetNewCOMParameter;
  805.           END;
  806.  
  807.       11: BEGIN   {6 bit word}
  808.              COM_DataBits := 6;
  809.              SetNewCOMParameter;
  810.           END;
  811.  
  812.       12: BEGIN   {7 bit word}
  813.              COM_DataBits := 7;
  814.              SetNewCOMParameter;
  815.           END;
  816.  
  817.      13: BEGIN   {8 bit word}
  818.             COM_DataBits := 8;
  819.             SetNewCOMParameter;
  820.          END;
  821.  
  822.      14: BEGIN   {Odd Parity}
  823.             COM_Parity := Odd;
  824.             SetNewCOMParameter;
  825.          END;
  826.  
  827.      15: BEGIN   {Even Parity}
  828.             COM_Parity := Even;
  829.             SetNewCOMParameter;
  830.          END;
  831.  
  832.      16: BEGIN   {No Parity}
  833.             COM_Parity := None;
  834.             SetNewCOMParameter;
  835.          END;
  836.  
  837.      17: BEGIN   {Display COM1 only}
  838.             COM1_Display_Data := True;
  839.             COM2_Display_Data := False;
  840.          END;
  841.  
  842.      18: BEGIN   {Display COM2 only}
  843.             COM1_Display_Data := False;
  844.             COM2_Display_Data := True;
  845.          END;
  846.  
  847.      19: BEGIN   {Display both COM1 and COM2}
  848.             COM1_Display_Data := True;
  849.             COM2_Display_Data := True;
  850.          END;
  851.  
  852.      20: BEGIN   {COM1 is triggered}
  853.             GoToXY(1,25);
  854.             ClrEol;
  855.             COM1_Is_Triggered := True;
  856.             COM2_Is_Triggered := False;
  857.             WriteStringAt('COM1 awaiting trigger',
  858.                           HighBlink,3,25);
  859.          END;
  860.  
  861.      21: BEGIN   {COM2 is triggered}
  862.             GoToXY(1,25);
  863.             ClrEol;
  864.             COM1_Is_Triggered := False;
  865.             COM2_Is_Triggered := True;
  866.             WriteStringAt('COM2 awaiting trigger',
  867.                            HighBlink,3,25);
  868.          END;
  869.  
  870.      22: BEGIN   {Input trigger pattern}
  871.             GoToXY(1,MenuLine4);  {position cursor}
  872.             ClrEol;               {clear line}
  873.             WriteString(
  874.              'Input trigger pattern as two hex digits: ',
  875.              High);
  876.  
  877.             {initialize str with hex prefix}
  878.             HexStr := '$';
  879.             FOR HexChar := 1 TO 2 DO
  880.             BEGIN
  881.                REPEAT
  882.                   {get a char}
  883.                   Ch := upcase(Char(GetKey));
  884.                   {loop until valid char is input}
  885.                UNTIL pos(Ch,HexDigits) <> 0;
  886.                {display to user}
  887.                write(Ch);
  888.                {add to hex string}
  889.                HexStr := HexStr + Ch;
  890.             END;
  891.             {convert hex to int}
  892.             Val(HexStr,TriggerPattern,ErrCode);
  893.             GoToXY(28,25);
  894.             Write('Trigger Pattern: ',
  895.                   FormatCharHex(TriggerPattern));
  896.          END;
  897.  
  898.      23: BEGIN   {Display BEFORE Trigger mode}
  899.             TriggerMode := Before;
  900.             WriteStringAt('Mode: Display Before Trigger'
  901.                           ,Low,51,25);
  902.             IF COM1_Is_Triggered THEN
  903.                {start with displaying data}
  904.                COM1_Display_Data := True
  905.             ELSE
  906.             IF COM2_Is_Triggered THEN
  907.                COM2_Display_Data := True
  908.             ELSE
  909.                WriteStringAt('Mode Error -- Select channel'
  910.                              ,HighBlink,51,25);
  911.          END;
  912.  
  913.      24: BEGIN   {Display AFTER Trigger mode}
  914.             TriggerMode := After;
  915.             WriteStringAt('Mode: Display After Trigger'
  916.                           ,Low,51,25);
  917.             IF COM1_Is_Triggered THEN
  918.                {start without displaying data}
  919.                COM1_Display_Data := False
  920.             ELSE
  921.             IF COM2_Is_Triggered THEN
  922.                COM2_Display_Data := False
  923.             ELSE
  924.             WriteStringAt('Mode Error -- Select channel'
  925.                           ,HighBlink,51,25);
  926.          END;
  927.  
  928.      25: TriggerEnabled := True; {enable trigger}
  929.  
  930.      26: BEGIN   {Stop Triggering}
  931.             TriggerEnabled := False;
  932.             {stop triggering for both channels}
  933.             COM1_Is_Triggered := False;
  934.             COM2_Is_Triggered := False;
  935.  
  936.             {start data display for both channels}
  937.             COM1_Display_Data := True;
  938.             COM2_Display_Data := True;
  939.             GoToXY(3,25);
  940.             ClrEol;
  941.             WriteString('Triggering Disabled',Low);
  942.          END;
  943.  
  944.      27: BEGIN   {Ascii Normal Data Display}
  945.             AsciiDisplay := True;
  946.             HandShakeDisplay := False;
  947.          END;
  948.  
  949.      28: BEGIN   {Ascii with handshake Data Display}
  950.             AsciiDisplay := True;
  951.             HandShakeDisplay := True;
  952.          END;
  953.  
  954.      29: BEGIN   {Hex Normal Data Display}
  955.             AsciiDisplay := False;
  956.             HandShakeDisplay := False;
  957.          END;
  958.  
  959.      30: BEGIN   {Hex with handshake Data Display}
  960.             AsciiDisplay := False;
  961.             HandShakeDisplay := True;
  962.          END;
  963.  
  964.      31: BEGIN   {Toggle adding spaces to display}
  965.             AddSpace := NOT AddSpace;
  966.          END;
  967.  
  968.      32: BEGIN   {Start data acquire}
  969.             COM1_Data_Acquire := True;
  970.             COM2_Data_Acquire := True;
  971.          END;
  972.  
  973.      33: BEGIN   {Stop data acquire}
  974.             COM1_Data_Acquire := False;
  975.             COM2_Data_Acquire := False;
  976.          END;
  977.  
  978.      34: BEGIN   {Clear the display}
  979.             {claim the screen}
  980.             Alloc(ScreenAccess);
  981.             ClrScr;
  982.             DrawMenuFrame;
  983.             {set cursor postion to home}
  984.             OldXPos := 1;
  985.             OldYPos := 1;
  986.             Dealloc(ScreenAccess);
  987.          END;
  988.  
  989.      35: Init_Program; {reset the analyzer}
  990.  
  991.      36: BEGIN   {End the analyzer program}
  992.             ExitMenu := True;
  993.             ExitProgram := True;
  994.          END;
  995.  
  996.  
  997.   END;
  998.  END;
  999. END;
  1000.  
  1001.  
  1002. {************ Begin Task Procedures *************}
  1003.  
  1004. PROCEDURE ProcessKeysTask;
  1005.  
  1006. VAR
  1007.  
  1008.  Ch:   Char;
  1009.  
  1010.  Done,
  1011.  OldCOM1Flag,
  1012.  OldCOM2Flag:  Boolean;
  1013.  
  1014. BEGIN
  1015.  
  1016.    Done := False;
  1017.  
  1018.    REPEAT
  1019.  
  1020.       {read key if available else yield}
  1021.  
  1022.       Ch := Char(GetKey);
  1023.  
  1024.       CASE Ch OF
  1025.  
  1026.       Esc: BEGIN  {if key is Esc}
  1027.               {display and process the menu}
  1028.               Done := DoMenu;
  1029.               {rebuild display when finished}
  1030.               BuildDisplay;
  1031.            END;
  1032.  
  1033.       Sp: BEGIN  {if space bar}
  1034.              {save old state}
  1035.              OldCOM1Flag := COM1_Display_Data;
  1036.              OldCOM2Flag := COM2_Display_Data;
  1037.  
  1038.              {stop filling of the display fifo so}
  1039.              {it does not overflow durin pause}
  1040.              {turn off display data both channels}
  1041.              COM1_Display_Data := False;
  1042.              COM2_Display_Data := False;
  1043.              GoToXY(1,24);
  1044.              ClrEol;
  1045.              GoToXY(23,24);
  1046.              WriteString(
  1047.                'Press <Enter> to restart the display'
  1048.                ,HighBlink);
  1049.              REPEAT
  1050.                 {loop until Cr starts display again}
  1051.                 Ch := Char(GetKey);
  1052.              UNTIL Ch = Cr;
  1053.  
  1054.             {restore previous display status}
  1055.             COM1_Display_Data := OldCOM1Flag;
  1056.             COM2_Display_Data := OldCOM2Flag;
  1057.             BuildDisplay; {rebuild display}
  1058.           END;
  1059.       END;
  1060.  
  1061.    UNTIL Done;
  1062.  
  1063. END;
  1064.  
  1065.  
  1066. PROCEDURE MoveCOM1Data;
  1067.  
  1068. {Move data from the COM1 input buffer to the}
  1069. {COM2 output buffer and to the display buffer}
  1070. {if enabled}
  1071.  
  1072. VAR
  1073.  
  1074.  Sd:   DataRec;
  1075.  Dd:   DisplayRec;
  1076.  
  1077. BEGIN
  1078.  
  1079.    REPEAT
  1080.       {yield if no data to move}
  1081.       WHILE COM1_Input_Fifo.Ovd.Count = 0 DO
  1082.          yield;
  1083.       {when data is available move it}
  1084.  
  1085.       {turn ints off, read data, turn ints on}
  1086.       INLINE($FA);
  1087.       GetSerialData(COM1_Input_Fifo,Sd);
  1088.       INLINE($FB);
  1089.  
  1090.       {store in COM2 output fifo}
  1091.       PutSerialData(Sd,COM2_Output_Fifo);
  1092.  
  1093.       {if a trigger is enabled}
  1094.       IF COM1_Is_Triggered AND
  1095.          TriggerEnabled    THEN
  1096.       BEGIN
  1097.          {and a match is found}
  1098.          IF Sd.Data = TriggerPattern THEN
  1099.          {indicate match & disable further matches}
  1100.          {trigger is single shot event}
  1101.          BEGIN
  1102.             TriggerEnabled := False;
  1103.  
  1104.             WriteStringAt('   COM1 Triggered    '
  1105.                           ,Low,3,25);
  1106.            {If displaying before trigger}
  1107.            {then stop data display}
  1108.            IF TriggerMode = Before THEN
  1109.                COM1_Display_Data := False
  1110.            ELSE
  1111.                {start the data display}
  1112.                COM1_Display_Data := True;
  1113.  
  1114.          END;
  1115.       END;
  1116.  
  1117.       {if we are displaying data}
  1118.       IF COM1_Display_Data THEN
  1119.       {move data to the display fifo also}
  1120.       BEGIN
  1121.          {tagged from this COM device}
  1122.          Dd.DR := Sd;
  1123.          Dd.Tag := FromCOM1;
  1124.          PutDisplayData(Dd,DisplayFifo);
  1125.       END;
  1126.  
  1127.    UNTIL False;
  1128.  
  1129. END;
  1130.  
  1131.  
  1132. PROCEDURE MoveCOM2Data;
  1133.  
  1134. {Move data from the COM2 input buffer to the}
  1135. {COM1 output buffer and to the display buffer}
  1136. {if enabled}
  1137.  
  1138. VAR
  1139.  
  1140.  Sd:   DataRec;
  1141.  Dd:   DisplayRec;
  1142.  
  1143. BEGIN
  1144.  
  1145.    REPEAT
  1146.       {yield if no data to move}
  1147.       WHILE COM2_Input_Fifo.Ovd.Count = 0 DO
  1148.           yield;
  1149.  
  1150.       {when data is available move it}
  1151.  
  1152.       {ints off, read data, turn ints on}
  1153.       INLINE($FA);
  1154.       GetSerialData(COM2_Input_Fifo,Sd);
  1155.       INLINE($FB);
  1156.  
  1157.       {store data in COM1 output fifo}
  1158.       PutSerialData(Sd,COM1_Output_Fifo);
  1159.  
  1160.       {if a trigger is enabled}
  1161.       IF COM2_Is_Triggered AND
  1162.          TriggerEnabled    THEN
  1163.       BEGIN
  1164.          {indicate match & disable further matches}
  1165.          {trigger is single shot event}
  1166.          IF Sd.Data = TriggerPattern THEN
  1167.          BEGIN
  1168.             TriggerEnabled := False;
  1169.             WriteStringAt('   COM2 Triggered    ',
  1170.                           Low,3,25);
  1171.             {If displaying before trigger}
  1172.             {stop data display}
  1173.             IF TriggerMode = Before THEN
  1174.                COM2_Display_Data := False
  1175.             ELSE
  1176.                {If displaying after trigger}
  1177.                {start data display}
  1178.                COM2_Display_Data := True;
  1179.  
  1180.          END;
  1181.       END;
  1182.  
  1183.       {if we are displaying data}
  1184.       IF COM2_Display_Data THEN
  1185.       BEGIN                                  
  1186.          {move data to the display fifo also}
  1187.          Dd.DR := Sd;                          
  1188.  
  1189.          {tagged from this COM device}
  1190.          Dd.Tag := FromCOM2;
  1191.          PutDisplayData(Dd,DisplayFifo);
  1192.       END;
  1193.  
  1194.    UNTIL False;
  1195.  
  1196. END;
  1197.  
  1198.  
  1199. PROCEDURE OutputCOM1Data;
  1200.  
  1201. {Move serial data from the output fifo}
  1202. {to the COM port}
  1203.  
  1204. CONST
  1205.  
  1206.  {max of 80 chars to serial port}
  1207.  {between yields to other tasks}
  1208.  
  1209.  OutputsPerYield = 80;
  1210.  
  1211.  
  1212. VAR
  1213.  
  1214.  Outs:   Integer;
  1215.  Sd:     DataRec;
  1216.  Urgent: Boolean;
  1217.  
  1218. BEGIN
  1219.  
  1220.    REPEAT
  1221.  
  1222.       {do until data is available in fifo}
  1223.       WHILE (COM1_Output_Fifo.Ovd.Count = 0) DO
  1224.       BEGIN
  1225.          {always make the handshake lines}
  1226.          {between COM1 and COM2 agree then yield}
  1227.          MakeHandshake(COM1,COM2_Status);
  1228.          yield;
  1229.       END;
  1230.  
  1231.       {we have data to output}
  1232.       {Its urgent if fifo is over half full}
  1233.  
  1234.       Urgent := (COM1_Output_Fifo.Ovd.Count >=
  1235.                        (SerialDataFifoSize/2));
  1236.  
  1237.       {Initialize output counter to max value}
  1238.       Outs := OutputsPerYield;
  1239.  
  1240.       {While there is data to output}
  1241.  
  1242.       WHILE ((COM1_Output_Fifo.Ovd.Count <> 0) AND
  1243.              (Outs <> 0)) DO
  1244.       BEGIN
  1245.  
  1246.          {test if UART is ready to transmit}
  1247.  
  1248.          WHILE (Get_Serial_Status(COM1) AND
  1249.                 TxRdyBit) = 0 DO
  1250.          BEGIN      
  1251.             {if we have time yield until ready}
  1252.             IF NOT Urgent THEN
  1253.                yield;
  1254.          END;
  1255.  
  1256.          {get data record to output}
  1257.          {set the handshake lines and output}
  1258.          {the data}
  1259.  
  1260.          GetSerialData(COM1_Output_Fifo,Sd);
  1261.          MakeHandshake(COM1,Sd.Status);
  1262.          port[COM1] := Sd.Data;
  1263.  
  1264.          {one less to output}
  1265.          Outs := Outs - 1;
  1266.  
  1267.       END;
  1268.       yield;
  1269.  
  1270.    UNTIL False;
  1271.  
  1272. END;
  1273.  
  1274.  
  1275. PROCEDURE OutputCOM2Data;
  1276.  
  1277. {Move serial data from the output fifo}
  1278. {to the COM port}
  1279.  
  1280. CONST
  1281.  
  1282.  {max of 80 chars to serial port}
  1283.  {between yields to other tasks}
  1284.  
  1285.  OutputsPerYield = 80;
  1286.  
  1287.  
  1288. VAR
  1289.  
  1290.  Outs:   Integer;
  1291.  Sd:     DataRec;
  1292.  Urgent: Boolean;
  1293.  
  1294. BEGIN
  1295.  
  1296.    REPEAT
  1297.  
  1298.       {do until data is available in fifo}
  1299.  
  1300.       WHILE (COM2_Output_Fifo.Ovd.Count = 0) DO
  1301.       BEGIN
  1302.          {always make the handshake line}
  1303.          {between COM1 and COM2 agree then yield}
  1304.          MakeHandshake(COM2,COM1_Status);
  1305.          yield;
  1306.       END;
  1307.  
  1308.       {we have data to output}
  1309.       {Its urgent if fifo is over half full}
  1310.  
  1311.       Urgent := (COM2_Output_Fifo.Ovd.Count >=
  1312.                  (SerialDataFifoSize/2));
  1313.  
  1314.       {Initialize output counter to max value}
  1315.       Outs := OutputsPerYield;
  1316.  
  1317.       {While there is data to output}
  1318.  
  1319.       WHILE ((COM2_Output_Fifo.Ovd.Count <> 0) AND
  1320.              (Outs <> 0)) DO
  1321.       BEGIN
  1322.          {test if UART is ready to transmit}
  1323.  
  1324.          WHILE (Get_Serial_Status(COM2) AND
  1325.                 TxRdyBit) = 0 DO
  1326.          BEGIN      
  1327.             {if we have time yield until ready}
  1328.             IF NOT Urgent THEN
  1329.                yield;
  1330.          END;
  1331.  
  1332.          {get data record to output}
  1333.          {set the handshake lines and output}
  1334.          {the data}
  1335.  
  1336.          GetSerialData(COM2_Output_Fifo,Sd);
  1337.          MakeHandshake(COM2,Sd.Status);
  1338.          port[COM2] := Sd.Data;
  1339.  
  1340.          {one less to output}
  1341.          Outs := Outs - 1;
  1342.  
  1343.       END;
  1344.       yield;
  1345.  
  1346.    UNTIL False;
  1347.  
  1348. END;
  1349.  
  1350.  
  1351. PROCEDURE DisplayCOMData;
  1352.  
  1353. CONST
  1354.  
  1355.  {max # of items displayed before yielding}
  1356.  
  1357.  MaxDisplayItems = 20;
  1358.  
  1359. VAR
  1360.  
  1361.  DisplayItems,
  1362.  DataLen:      Integer;
  1363.  D:            DisplayRec;
  1364.  
  1365. BEGIN
  1366.  
  1367.    {initial cursor is homed}
  1368.    {in data display window}
  1369.    OldXPos := 1;
  1370.    OldYPos := 1;
  1371.  
  1372.    REPEAT
  1373.       {if data in display fifo}
  1374.       IF DisplayFifo.Ovd.Count <> 0 THEN
  1375.       BEGIN
  1376.          {claim the screen, define the window}
  1377.          {position the cursor and initialize}
  1378.          {items counter}
  1379.          Alloc(ScreenAccess);
  1380.          Window(1,7,80,23);
  1381.          GoToXY(OldXPos,OldYPos);
  1382.          DisplayItems := MaxDisplayItems;
  1383.  
  1384.          WHILE ((DisplayFifo.Ovd.Count <> 0 ) AND
  1385.                 (DisplayItems <> 0)) DO
  1386.          {while there is data to display}
  1387.          BEGIN
  1388.             {get the data, display it, dec}
  1389.             {item counter. Save len of displayed}
  1390.             {item.}
  1391.  
  1392.             GetDisplayData(DisplayFifo,D);
  1393.             DataLen := DisplayData(D);
  1394.             DisplayItems := DisplayItems - 1;
  1395.  
  1396.             {if not room to display for another}
  1397.             {item of same length and we're on the}
  1398.             {last display line in window, then}
  1399.             {home cursor and start overwriting}
  1400.             {screen so as to avoid the scroll of}
  1401.             {the display. If not on last line of}
  1402.             {window, advance to next line. Either}
  1403.             {way, the next line must be cleared.}
  1404.  
  1405.             IF WhereX + DataLen >= 80 THEN
  1406.                IF WhereY = 17 THEN
  1407.                   GoToXY(1,1)
  1408.                ELSE
  1409.                   WriteLn;
  1410.  
  1411.             ClrEol;
  1412.          END;
  1413.  
  1414.          {save new cursor position}
  1415.          OldXPos := WhereX;
  1416.          OldYPos := WhereY;
  1417.  
  1418.          {back to full screen}
  1419.          {and release screen lock and yield}
  1420.          Window(1,1,80,25);
  1421.          Dealloc(ScreenAccess);
  1422.       END
  1423.       ELSE
  1424.          {if no data to display just yield}
  1425.          yield;
  1426.  
  1427.    UNTIL False;
  1428.  
  1429. END;
  1430.  
  1431.  
  1432. PROCEDURE Timer;
  1433.  
  1434. VAR
  1435.  
  1436.  Toggle:  Boolean;
  1437.  
  1438. BEGIN
  1439.  
  1440.    Toggle := True;
  1441.  
  1442.    REPEAT
  1443.  
  1444.       {every 1/2 second do the following}
  1445.       pause(4);
  1446.  
  1447.       {if ok to update the screen}
  1448.       IF UpdateScreenStatus THEN
  1449.       BEGIN
  1450.          {lock the screen}
  1451.          Alloc(ScreenAccess);
  1452.  
  1453.          {if status of either port has changed}
  1454.          IF ((COM1_Status <> OldCOM1_Status)  OR
  1455.              (COM2_Status <> OldCOM2_Status)) THEN
  1456.          {then update the screen}
  1457.          BEGIN
  1458.             {display new COM1 status}
  1459.             DisplayHandShakeStatus(COM1,COM1_Status
  1460.                                   ,COM2_Status);
  1461.             {save new status}
  1462.             OldCOM1_Status := COM1_Status;
  1463.  
  1464.             {display new COM2 status}
  1465.             DisplayHandShakeStatus(COM2,COM2_Status
  1466.                                   ,COM1_Status);
  1467.             OldCOM2_Status := COM2_Status;
  1468.  
  1469.          END;
  1470.  
  1471.          {every full second update}
  1472.          {buffer status on screen}
  1473.          IF Toggle THEN
  1474.             DisplayBufferStatus;
  1475.  
  1476.          {unlock the screen}
  1477.          Dealloc(ScreenAccess);
  1478.  
  1479.          Toggle := NOT Toggle;
  1480.       END;
  1481.  
  1482.    UNTIL False;
  1483.  
  1484. END;
  1485.  
  1486.  
  1487.  
  1488. BEGIN {main}
  1489.  
  1490.    {verify presence of COM1 and COM2}
  1491.    VerifyHardware;
  1492.  
  1493.    {initialize the multitasker}
  1494.    Init_Kernel;
  1495.  
  1496.    {initialize the menu structure}
  1497.    Init_Menu;
  1498.  
  1499.    {install the serial ISRs}
  1500.    Install_Serial_Handlers;
  1501.  
  1502.    {Initialize strings used to format the display}
  1503.    Line1 := Char(201)+' COM1 '+repl(16,Char(205))+
  1504.           ' Serial Protocol Analyzer Ver: 1.0 '+
  1505.           repl(15,Char(205))+ ' COM2 '+Char(187);
  1506.  
  1507.    Line2 := Char(186)+' In Fifo:'+repl(5,' ')+
  1508.             'Out Fifo:    '+ Char(186)+
  1509.             repl(10,' ')+'By'+repl(10,' ')+
  1510.             Char(186)+' In Fifo:'+repl(5,' ')+
  1511.             'Out Fifo:    '+Char(186);
  1512.  
  1513.    Line3 := Char(186)+' Stat- BRK:  FE:  PE:  OR: '+
  1514.             Char(186)+ '   Craig A. Lindley   '+
  1515.             Char(186)+ ' Stat- BRK:  FE:  PE:  OR: '+
  1516.             Char(186);
  1517.  
  1518.    Line4 := Char(186)+' In - CD:  RI:  DSR:  CTS: '+
  1519.             Char(186)+repl(22,' ')+Char(186)+
  1520.             ' In - CD:  RI:  DSR:  CTS: '+Char(186);
  1521.  
  1522.    Line5 := Char(186)+ ' Out- DTR:      RTS:'+
  1523.             repl(7,' ')+Char(186)+
  1524.             '   Display Fifo:      '+Char(186)+
  1525.             ' Out- DTR:      RTS:'+repl(7,' ')+
  1526.             Char(186);
  1527.  
  1528.    Line6 := Char(200)+repl(27,Char(205))+
  1529.             Char(202)+repl(22,Char(205))+
  1530.             Char(202)+repl(27,Char(205))+
  1531.             Char(188);
  1532.  
  1533.    Line24 := '  <Esc> for Menu  <Space Bar> to Pause'+
  1534.            '    COM1 - Normal : COM2 - Reverse Video';
  1535.  
  1536.    BuildDisplay;   {show main display}
  1537.    Init_Program;   {initialize all vars}
  1538.  
  1539.    {initialize screen lock}
  1540.    Initialize_Semaphore(ScreenAccess);
  1541.  
  1542.    {enable status update}
  1543.    UpdateScreenStatus:= True;
  1544.  
  1545.    {Fork off all tasks}
  1546.  
  1547.    Fork;
  1548.  
  1549.    IF child_process THEN
  1550.       MoveCOM1Data;
  1551.  
  1552.    Fork;
  1553.  
  1554.    IF child_process THEN
  1555.       MoveCOM2Data;
  1556.  
  1557.    Fork;
  1558.  
  1559.    IF child_process THEN
  1560.       OutputCOM1Data;
  1561.  
  1562.    Fork;
  1563.  
  1564.    IF child_process THEN
  1565.       OutputCOM2Data;
  1566.  
  1567.    Fork;
  1568.  
  1569.    IF child_process THEN
  1570.       DisplayCOMData;
  1571.  
  1572.    Fork;
  1573.  
  1574.    IF child_process THEN
  1575.       Timer;
  1576.  
  1577.  
  1578.    ProcessKeysTask;
  1579.  
  1580.    ClrScr;
  1581.    Disable_Serial_Devices;
  1582.    Remove_Serial_Handlers;
  1583.  
  1584. END
  1585.  
  1586. .
  1587.  
  1588.  
  1589.  
  1590.  
  1591.  
  1592.  
  1593.  
  1594.  
  1595.  
  1596.  
  1597.  
  1598.  
  1599.  
  1600.  
  1601.  
  1602.  
  1603.  
  1604.  
  1605.  
  1606.  
  1607.  
  1608.  
  1609.  
  1610.  
  1611.  
  1612.  
  1613.  
  1614.  
  1615.  
  1616.  
  1617.  
  1618.  
  1619.  
  1620.  
  1621.  
  1622.                                        
  1623.  
  1624.