home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / pibsoft / terminal / source / docisbb.mod < prev    next >
Encoding:
Text File  |  1987-12-26  |  51.6 KB  |  1,621 lines

  1. (*----------------------------------------------------------------------*)
  2. (*   CISB_DLE_Seen --- Handle DLE character seen -- Main CISB B routine *)
  3. (*----------------------------------------------------------------------*)
  4.  
  5. PROCEDURE CISB_DLE_Seen;
  6.  
  7. (*----------------------------------------------------------------------*)
  8. (*                                                                      *)
  9. (*  CISB_DLE_Seen is called from the main program when the character    *)
  10. (*  <DLE> is received from the host.                                    *)
  11. (*                                                                      *)
  12. (*  This routine calls Read_Packet and dispatches to the appropriate    *)
  13. (*  handler for the incoming packet.                                    *)
  14. (*                                                                      *)
  15. (*----------------------------------------------------------------------*)
  16.  
  17. CONST
  18.    Max_Buf_Size  = 1032            (* Largest data block we can handle  *);
  19.    Max_SA        = 2               (* Maximum number of waiting packets *);
  20.  
  21.    Def_Buf_Size  = 511             (* Default data block                *);
  22.    Def_WS        = 1               (* I can send 2 packets ahead        *);
  23.    Def_WR        = 1               (* I can receive single send-ahead   *);
  24.    Def_BS        = 8               (* I can handle 1024 bytes           *);
  25.    Def_CM        = 1               (* I can handle CRC                  *);
  26.    Def_DQ        = 1               (* I can handle non-quoted NUL       *);
  27.  
  28.    Max_Errors    =  10             (* Maximum errors allowed per block *);
  29.  
  30.                    (* Receive States *)
  31.  
  32.    R_Get_DLE      = 0;
  33.    R_Get_B        = 1;
  34.    R_Get_Seq      = 2;
  35.    R_Get_Data     = 3;
  36.    R_Get_CheckSum = 4;
  37.    R_Send_ACK     = 5;
  38.    R_Timed_Out    = 6;
  39.    R_Success      = 7;
  40.  
  41.                    (* Send States *)
  42.  
  43.    S_Get_DLE      = 1;
  44.    S_Get_Num      = 2;
  45.    S_Get_Packet   = 3;
  46.    S_Timed_Out    = 4;
  47.    S_Send_NAK     = 5;
  48.    S_Send_Data    = 6;
  49.  
  50.                    (* Table of control characters that need to be masked *)
  51.  
  52.    Mask_Table : ARRAY[ 0..31 ] OF BYTE = (
  53.                 0, 0, 0, 1, 0, 1, 0, 0,   { NUL SOH SOB ETX EOT ENQ SYN BEL }
  54.                 0, 0, 0, 0, 0, 0, 0, 0,   { BS  HT  LF  VT  FF  CR  SO  SI  }
  55.                 1, 1, 0, 1, 0, 1, 0, 0,   { DLE DC1 DC2 DC3 DC4 NAK ^V  ^W  }
  56.                 0, 0, 0, 0, 0, 0, 0, 0    { CAN ^Y  ^Z  ESC ?   ?   ?   ?   }
  57.                                          );
  58.  
  59. TYPE
  60.    BufferType = ARRAY[ 0..Max_Buf_Size ] OF BYTE;
  61.  
  62.    Buf_Type   = RECORD
  63.                    Seq : INTEGER    (* Packet's sequence number  *);
  64.                    Num : INTEGER    (* Number of bytes in packet *);
  65.                    Buf : BufferType (* Actual packet data        *);
  66.                 END;
  67.  
  68. VAR
  69.    Timer           : INTEGER       (* Wait time for character to appear *);
  70.    R_Size          : INTEGER       (* Size of receiver buffer *);
  71.    Ch              : INTEGER       (* Current character *);
  72.    Save_Xon_Xoff   : BOOLEAN       (* Save current XON/XOFF status *);
  73.  
  74.    Timed_Out       : BOOLEAN       (* We timed out before receiving character *);
  75.    Masked          : BOOLEAN       (* TRUE if ctrl character was 'masked' *);
  76.  
  77.                                    (* Send-ahead buffers *)
  78.  
  79.    SA_Buf          : ARRAY[ 0..Max_SA ] OF Buf_Type ABSOLUTE Sector_Data;
  80.  
  81.    SA_Next_to_ACK  : INTEGER       (* Which SA_Buf is waiting for an ACK *);
  82.    SA_Next_to_Fill : INTEGER       (* Which SA_Buf is ready for new data *);
  83.    SA_Waiting      : INTEGER       (* Number of SA_Buf's waiting for ACK *);
  84.  
  85.                                    (* File buffer *)
  86.  
  87.    R_Buffer        : BufferType;
  88.  
  89.    FileName        : AnyStr        (* Name of file sent/received *);
  90.  
  91.    I               : INTEGER;
  92.    N               : INTEGER;
  93.    Dummy           : BOOLEAN;
  94.  
  95. LABEL
  96.    Error_Exit;
  97.  
  98. (*----------------------------------------------------------------------*)
  99. (*   Send_Masked_Byte -- Send character with possible <DLE> masking     *)
  100. (*----------------------------------------------------------------------*)
  101.  
  102. PROCEDURE Send_Masked_Byte( Ch : INTEGER );
  103.  
  104. BEGIN (* Send_Masked_Byte *)
  105.  
  106.    Ch := Ch AND $FF;
  107.                                    (* If character is control character,   *)
  108.                                    (* and is in table of characters to     *)
  109.                                    (* mask, then send <DLE><Ch+31> instead *)
  110.                                    (* of character itself.                 *)
  111.  
  112.    IF ( Ch < 32 ) THEN
  113.       IF ( Mask_Table[Ch] <> 0 ) THEN
  114.          BEGIN
  115.             Async_Send( CHR( DLE ) );
  116.             Async_Send( CHR( Ch + ORD('@') ) );
  117.          END
  118.       ELSE
  119.          Async_Send( CHR( Ch ) )
  120.    ELSE
  121.       Async_Send( CHR( Ch ) );
  122.  
  123. END   (* Send_Masked_Byte *);
  124.  
  125. (*----------------------------------------------------------------------*)
  126. (*                Send_ACK -- Send acknowledgement to host              *)
  127. (*----------------------------------------------------------------------*)
  128.  
  129. PROCEDURE Send_ACK;
  130.  
  131. BEGIN (* Send_ACK *)
  132.  
  133.    Async_Send( CHR( DLE ) );
  134.    Async_Send( CHR( Seq_Num + ORD('0') ) );
  135.  
  136.    Update_B_Display;
  137.  
  138. END   (* Send_ACK *);
  139.  
  140. (*----------------------------------------------------------------------*)
  141. (*       Send_NAK --- Send negative acknowledge for block to host       *)
  142. (*----------------------------------------------------------------------*)
  143.  
  144. PROCEDURE Send_NAK;
  145.  
  146. BEGIN (* Send_NAK *)
  147.  
  148.    Display_Message_With_Number( 'Sending NAK for block ', Total_Blocks );
  149.  
  150.    Async_Send( CHR( NAK ) );
  151.  
  152.    Update_B_Display;
  153.  
  154. END   (* Send_NAK *);
  155.  
  156. (*----------------------------------------------------------------------*)
  157. (*                 Send_ENQ --- Send ENQ to host                        *)
  158. (*----------------------------------------------------------------------*)
  159.  
  160. PROCEDURE Send_ENQ;
  161.  
  162. BEGIN (* Send_ENQ *)
  163.  
  164.    Async_Send( CHR( ENQ ) );
  165.  
  166. END   (* Send_ENQ *);
  167.  
  168. (*----------------------------------------------------------------------*)
  169. (*     Read_Byte --- Read one character from serial port with timer     *)
  170. (*----------------------------------------------------------------------*)
  171.  
  172. FUNCTION Read_Byte : BOOLEAN;
  173.  
  174. VAR
  175.    I: INTEGER;
  176.  
  177. BEGIN (* Read_Byte *)
  178.  
  179.    I := 0;
  180.  
  181.    REPEAT
  182.       INC( I );
  183.       Async_Receive_With_Timeout( 1 , Ch );
  184.       Check_Keyboard;
  185.    UNTIL ( I > Timer ) OR ( Ch <> TimeOut ) OR Halt_Transfer;
  186.  
  187.    Timed_Out := ( Ch = TimeOut ) OR ( I > Timer );
  188.  
  189.    Read_Byte := ( NOT Timed_Out     ) AND
  190.                 ( NOT Halt_Transfer );
  191.  
  192. END   (* Read_Byte *);
  193.  
  194. (*----------------------------------------------------------------------*)
  195. (*     Read_Masked_Byte --- Read possibly masked character from port    *)
  196. (*----------------------------------------------------------------------*)
  197.  
  198. FUNCTION Read_Masked_Byte : BOOLEAN;
  199.  
  200. BEGIN (* Read_Masked_Byte *)
  201.  
  202.    Masked := FALSE;
  203.  
  204.    IF ( NOT Read_Byte ) THEN
  205.       BEGIN
  206.          Read_Masked_Byte := FALSE;
  207.          EXIT;
  208.       END;
  209.                                    (* Check for <DLE> -- indicates   *)
  210.                                    (* following character is masked. *)
  211.    IF ( Ch = DLE ) THEN
  212.      BEGIN
  213.  
  214.          IF ( NOT Read_Byte ) THEN
  215.             BEGIN
  216.                Read_Masked_Byte := FALSE;
  217.                EXIT;
  218.             END;
  219.  
  220.          Ch := Ch AND $1F;
  221.  
  222.          Masked := TRUE;
  223.  
  224.       END;
  225.  
  226.    Read_Masked_Byte := TRUE;
  227.  
  228. END   (* Read_Masked_Byte *);
  229.  
  230. (*----------------------------------------------------------------------*)
  231. (*                 Incr_Seq --- Increment block sequence number         *)
  232. (*----------------------------------------------------------------------*)
  233.  
  234. FUNCTION Incr_Seq( Value : INTEGER ) : INTEGER;
  235.  
  236. BEGIN (* Incr_Seq *)
  237.  
  238.    IF ( Value = 9 ) THEN
  239.       Incr_Seq := 0
  240.    ELSE
  241.       Incr_Seq := SUCC( Value );
  242.  
  243. END   (* Incr_Seq *);
  244.  
  245. (*----------------------------------------------------------------------*)
  246. (*              Send_Failure -- Send failure code to host               *)
  247. (*----------------------------------------------------------------------*)
  248.  
  249. PROCEDURE Send_Failure( Code : CHAR );
  250.    FORWARD;
  251.  
  252. (*----------------------------------------------------------------------*)
  253. (*               Read_Packet --- Read packet from host                  *)
  254. (*----------------------------------------------------------------------*)
  255.  
  256. FUNCTION Read_Packet( Lead_In_Seen     : BOOLEAN;
  257.                       From_Send_Packet : BOOLEAN ) : BOOLEAN;
  258.  
  259. (*----------------------------------------------------------------------*)
  260. (*                                                                      *)
  261. (*   Lead_In_Seen is TRUE if the <DLE><B> has been seen already.        *)
  262. (*                                                                      *)
  263. (*   From_Send_Packet is TRUE if called from Send_Packet                *)
  264. (*   (causes exit on first error detected)                              *)
  265. (*                                                                      *)
  266. (*   Returns True if packet is available from host.                     *)
  267. (*                                                                      *)
  268. (*----------------------------------------------------------------------*)
  269.  
  270. VAR
  271.    State      : INTEGER;
  272.    Next_Seq   : INTEGER;
  273.    Block_Num  : INTEGER;
  274.    Errors     : INTEGER;
  275.    New_Cks    : INTEGER;
  276.    I          : INTEGER;
  277.  
  278.    NAK_Sent   : BOOLEAN;
  279.    Do_Exit    : BOOLEAN;
  280.    Got_Packet : BOOLEAN;
  281.  
  282. (*----------------------------------------------------------------------*)
  283.  
  284. PROCEDURE Do_R_Get_DLE;
  285.  
  286. BEGIN (* Do_R_Get_DLE *)
  287.  
  288.    IF Halt_Transfer THEN
  289.       BEGIN
  290.          Display_Message('Transfer terminated by keyboard request.',
  291.                          Err_Mess_Line);
  292.          Send_Failure( 'A' );
  293.          Got_Packet := FALSE;
  294.          Do_Exit    := TRUE;
  295.       END
  296.    ELSE
  297.       IF ( NOT Read_Byte ) THEN
  298.          State := R_Timed_Out
  299.       ELSE IF ( ( Ch AND $7F ) = DLE ) THEN
  300.          State := R_Get_B
  301.       ELSE IF ( ( Ch AND $7F ) = ENQ ) THEN
  302.          State := R_Send_ACK;
  303.  
  304. END   (* Do_R_Get_DLE *);
  305.  
  306. (*----------------------------------------------------------------------*)
  307.  
  308. PROCEDURE Do_R_Get_B;
  309.  
  310. BEGIN (* Do_R_Get_B *)
  311.  
  312. {
  313. IF Debug_Mode THEN
  314.    Write_Log('   R_Get_B State', FALSE, FALSE );
  315. }
  316.    IF ( NOT Read_Byte ) THEN
  317.       State := R_Timed_Out
  318.    ELSE IF ( ( Ch AND $7F ) = ORD('B') ) THEN
  319.       State := R_Get_Seq
  320.    ELSE IF ( Ch = ENQ ) THEN
  321.       State := R_Send_ACK
  322.    ELSE
  323.       State := R_Get_DLE;
  324.  
  325. END   (* Do_R_Get_B *);
  326.  
  327. (*----------------------------------------------------------------------*)
  328.  
  329. PROCEDURE Do_R_Get_Seq;
  330.  
  331. BEGIN (* Do_R_Get_Seq *)
  332. {
  333. IF Debug_Mode THEN
  334.    Write_Log('   R_Get_Seq State', FALSE, FALSE );
  335. }
  336.    IF ( NOT Read_Byte ) THEN
  337.       State := R_Timed_Out
  338.    ELSE IF ( Ch = ENQ ) THEN
  339.       State := R_Send_ACK
  340.    ELSE
  341.       BEGIN
  342.  
  343.          IF ( Quick_B AND Use_CRC ) THEN
  344.             CheckSum := -1
  345.          ELSE
  346.             CheckSum := 0;
  347.  
  348.          Block_Num := Ch - ORD('0');
  349.  
  350.          Do_CheckSum( Ch );
  351.  
  352.          I     := 0;
  353.          State := R_Get_Data;
  354.  
  355.       END;
  356.  
  357. END   (* Do_R_Get_Seq *);
  358.  
  359. (*----------------------------------------------------------------------*)
  360.  
  361. PROCEDURE Do_R_Get_Data;
  362.  
  363. BEGIN (* Do_R_Get_Data *)
  364. {
  365. IF Debug_Mode THEN
  366.    Write_Log('   R_Get_Data State', FALSE, FALSE );
  367. }
  368.    IF ( NOT Read_Masked_Byte ) THEN
  369.       State := R_Timed_Out
  370.    ELSE IF ( ( Ch = ETX ) AND ( NOT Masked ) ) THEN
  371.       BEGIN
  372.          Do_CheckSum( ETX );
  373.          State := R_Get_CheckSum;
  374.       END
  375.    ELSE
  376.       BEGIN
  377.          R_Buffer[ I ] := Ch;
  378.          INC( I );
  379.          Do_CheckSum( Ch );
  380.       END;
  381.  
  382. END   (* Do_R_Get_Data *);
  383.  
  384. (*----------------------------------------------------------------------*)
  385.  
  386. PROCEDURE Do_R_Get_CheckSum;
  387.  
  388. BEGIN (* Do_R_Get_CheckSum *)
  389. {
  390. IF Debug_Mode THEN
  391.    Write_Log('   R_Get_CheckSum State', FALSE, FALSE );
  392. }
  393.    IF ( NOT Read_Masked_Byte ) THEN
  394.       State := R_Timed_Out
  395.    ELSE
  396.       BEGIN
  397.  
  398.          IF ( Quick_B AND Use_CRC ) THEN
  399.             BEGIN
  400.  
  401.                CheckSum := SWAP( CheckSum ) XOR Ch;
  402.                CheckSum := CheckSum XOR ( LO( CheckSum ) SHR 4 );
  403.                CheckSum := CheckSum XOR ( SWAP( LO( CheckSum ) ) SHL 4 ) XOR
  404.                                         ( LO( CheckSum ) SHL 5 );
  405.  
  406.                IF ( NOT Read_Masked_Byte ) THEN
  407.                   New_Cks := CheckSum XOR $FF
  408.                ELSE
  409.                   BEGIN
  410.                      CheckSum := SWAP( CheckSum ) XOR Ch;
  411.                      CheckSum := CheckSum XOR ( LO( CheckSum ) SHR 4 );
  412.                      CheckSum := CheckSum XOR ( SWAP( LO( CheckSum ) ) SHL 4 ) XOR
  413.                                               ( LO( CheckSum ) SHL 5 );
  414.                      New_Cks  := 0;
  415.                   END;
  416.  
  417.             END
  418.          ELSE
  419.             New_Cks := Ch;
  420.  
  421.          IF ( New_Cks <> CheckSum ) THEN
  422.             State := R_Timed_Out
  423.                                    (* Watch for failure packet *)
  424.                                    (* which is always accepted *)
  425.  
  426.          ELSE IF ( R_Buffer[0] = ORD('F') ) THEN
  427.             State := R_Success
  428.                                    (* Watch for duplicate block *)
  429.  
  430.          ELSE IF ( Block_Num = Seq_Num ) THEN
  431.             State := R_Success
  432.  
  433.                                    (* Watch for bad sequence number *)
  434.  
  435.          ELSE IF ( Block_Num <> Next_Seq ) THEN
  436.             State := R_Timed_Out
  437.  
  438.          ELSE
  439.             State := R_Success;
  440.  
  441.       END;
  442.  
  443. END   (* Do_R_Get_CheckSum *);
  444.  
  445. (*----------------------------------------------------------------------*)
  446.  
  447. PROCEDURE Do_R_Timed_Out;
  448.  
  449. BEGIN (* Do_R_Timed_Out *)
  450. {
  451. IF Debug_Mode THEN
  452.    Write_Log('   R_Timed_Out State', FALSE, FALSE );
  453. }
  454.    INC( Errors );
  455.  
  456.    IF ( ( Errors > Max_Errors ) OR From_Send_Packet ) THEN
  457.       BEGIN
  458.          Got_Packet  := FALSE;
  459.          Do_Exit     := TRUE;
  460.       END
  461.    ELSE
  462.       BEGIN
  463.  
  464.          IF ( NOT NAK_Sent ) THEN
  465.             BEGIN
  466.                NAK_Sent := TRUE;
  467.                Send_NAK;
  468.             END;
  469.  
  470.          IF From_Send_Packet THEN
  471.             BEGIN
  472.                Got_Packet := FALSE;
  473.                Do_Exit    := TRUE;
  474.             END
  475.          ELSE
  476.             State := R_Get_DLE;
  477.  
  478.       END;
  479.  
  480. END   (* Do_R_Timed_Out *);
  481.  
  482. (*----------------------------------------------------------------------*)
  483.  
  484. PROCEDURE Do_R_Send_ACK;
  485.  
  486. BEGIN (* Do_R_Send_ACK *)
  487. {
  488. IF Debug_Mode THEN
  489.    Write_Log('   R_Send_ACK State', FALSE, FALSE );
  490. }
  491.    Send_ACK;
  492.  
  493.    NAK_Sent := FALSE;              (* Start with clean slate  *)
  494.    State    := R_Get_DLE;          (* wait for the next block *)
  495.  
  496. END   (* Do_R_Send_ACK *);
  497.  
  498. (*----------------------------------------------------------------------*)
  499.  
  500. PROCEDURE Do_R_Success;
  501.  
  502. BEGIN (* Do_R_Success *)
  503. {
  504. IF Debug_Mode THEN
  505.    Write_Log('   R_Success State', FALSE, FALSE );
  506. }
  507.    Seq_Num     := Block_Num;
  508.    R_Size      := I;
  509.    Got_Packet  := TRUE;
  510.  
  511. END   (* Do_R_Success *);
  512.  
  513. (*----------------------------------------------------------------------*)
  514.  
  515. BEGIN (* Read_Packet *)
  516.                                    (* No packet received yet *)
  517.    Got_Packet := FALSE;
  518.                                    (* Fill received packet with 0s *)
  519.  
  520.    FillChar( R_Buffer, Buffer_Size, 0 );
  521.  
  522.                                    (* Get sequence number of next packet *)
  523.  
  524.    Next_Seq := SUCC( Seq_Num ) MOD 10;
  525.  
  526.                                    (* No errors yet *)
  527.    Errors   := 0;
  528.                                    (* No NAK sent yet *)
  529.    NAK_Sent := FALSE;
  530.                                    (* Increment packets received count *)
  531.    INC( Total_Packets );
  532.                                    (* Get starting state *)
  533.    IF Lead_In_Seen THEN
  534.       State := R_Get_Seq
  535.    ELSE
  536.       State := R_Get_DLE;
  537.                                    (* Get the packet! *)
  538.    Do_Exit := FALSE;
  539.  
  540.    WHILE ( NOT ( Halt_Transfer OR Got_Packet OR Do_Exit ) )  DO
  541.       BEGIN
  542.                                    (* Set long timer *)
  543.          Timer := 300;
  544.                                    (* Check keyboard input *)
  545.          Check_KeyBoard;
  546.  
  547.          CASE State OF
  548.  
  549.             R_Get_DLE      : Do_R_Get_DLE      (* Look for leading DLE     *);
  550.             R_Get_B        : Do_R_Get_B        (* Look for 'B' packet type *);
  551.             R_Get_Seq      : Do_R_Get_Seq      (* Get sequence number      *);
  552.             R_Get_Data     : Do_R_Get_Data     (* Get data                 *);
  553.             R_Get_CheckSum : Do_R_Get_CheckSum (* Get checksum/CRC         *);
  554.             R_Timed_Out    : Do_R_Timed_Out    (* Handle time out          *);
  555.             R_Send_ACK     : Do_R_Send_ACK     (* Send ACK                 *);
  556.             R_Success      : Do_R_Success      (* Handle received OK       *);
  557.  
  558.          END (* CASE *);
  559.  
  560.       END (* WHILE *);
  561.  
  562.    Read_Packet := Got_Packet AND ( NOT Halt_Transfer );
  563.  
  564. END   (* Read_Packet *);
  565.  
  566. (*----------------------------------------------------------------------*)
  567. (*           Send_Data --- Send buffer-full of data to host             *)
  568. (*----------------------------------------------------------------------*)
  569.  
  570. PROCEDURE Send_Data( Buffer_Number : INTEGER );
  571.  
  572. VAR
  573.    I : INTEGER;
  574.  
  575. BEGIN (* Send_Data *)
  576.                                    (* Choose send-ahead buffer *)
  577.  
  578.    WITH SA_Buf[ Buffer_Number ] DO
  579.       BEGIN
  580.                                    (* Initialize checksum *)
  581.  
  582.          IF ( Quick_B AND Use_CRC ) THEN
  583.             CheckSum := -1
  584.          ELSE
  585.             CheckSum := 0;
  586.                                    (* Send <DLE>B to start packet *)
  587.  
  588.          Async_Send( CHR( DLE ) );
  589.          Async_Send( 'B' );
  590.                                    (* Send sequence number of packet *)
  591.  
  592.          Async_Send( CHR( Seq + ORD('0') ) );
  593.  
  594.          Do_CheckSum( Seq + ORD('0') );
  595.  
  596.                                    (* Send data and get checksum/CRC *)
  597.          FOR I := 0 TO Num DO
  598.             BEGIN
  599.                Send_Masked_Byte( Buf[ I ] );
  600.                Do_CheckSum( Buf[ I ] );
  601.             END;
  602.                                    (* Send ETX to mark end of data *)
  603.  
  604.          Async_Send ( CHR( ETX ) );
  605.  
  606.          Do_CheckSum( ETX );
  607.                                    (* Send Checksum or CRC *)
  608.  
  609.          IF ( Quick_B AND Use_CRC ) THEN
  610.             Send_Masked_Byte( CheckSum SHR 8 );
  611.  
  612.          Send_Masked_Byte( CheckSum );
  613.  
  614.       END;
  615.  
  616. END   (* Send_Data *);
  617.  
  618. (*----------------------------------------------------------------------*)
  619. (*           Incr_SA --- Increment send ahead slot number               *)
  620. (*----------------------------------------------------------------------*)
  621.  
  622. FUNCTION Incr_SA( Old_Value : INTEGER ) : INTEGER;
  623.  
  624. BEGIN (* Incr_SA *)
  625.  
  626.    IF ( Old_Value = Max_SA ) THEN
  627.       Incr_SA := 0
  628.    ELSE
  629.       Incr_SA := SUCC( Old_Value );
  630.  
  631. END   (* Incr_SA *);
  632.  
  633. (*----------------------------------------------------------------------*)
  634. (*           Get_ACK --- Wait for ACK of packet from host               *)
  635. (*----------------------------------------------------------------------*)
  636.  
  637. FUNCTION Get_ACK : BOOLEAN;
  638.  
  639. (*----------------------------------------------------------------------*)
  640. (*                                                                      *)
  641. (*  Get_ACK is called to wait until the SA_Buf indicated by             *)
  642. (*  SA_Next_to_ACK has been ACKed by the host.                          *)
  643. (*                                                                      *)
  644. (*----------------------------------------------------------------------*)
  645.  
  646. VAR
  647.    State      : INTEGER;
  648.    Errors     : INTEGER;
  649.    Block_Num  : INTEGER;
  650.    New_Cks    : INTEGER;
  651.    Sent_ENQ   : BOOLEAN;
  652.    Sent_NAK   : BOOLEAN;
  653.    SA_Index   : INTEGER;
  654.    Do_Exit    : BOOLEAN;
  655.    Got_An_Ack : BOOLEAN;
  656.  
  657. (*----------------------------------------------------------------------*)
  658.  
  659. PROCEDURE Do_S_Get_DLE;
  660.  
  661. BEGIN (* Do_S_Get_DLE *)
  662.  
  663.    Timer := 300;
  664.  
  665.    IF Halt_Transfer THEN
  666.       BEGIN
  667.  
  668.          Display_Message('Transfer terminated by keyboard request.',
  669.                          Err_Mess_Line);
  670.  
  671.          Send_Failure('A');
  672.  
  673.          Do_Exit := TRUE;
  674.  
  675.       END
  676.    ELSE
  677.       IF ( NOT Read_Byte ) THEN
  678.          State := S_Timed_Out
  679.       ELSE IF ( Ch = DLE ) THEN
  680.          State := S_Get_Num
  681.       ELSE IF ( Ch = NAK ) THEN
  682.          BEGIN
  683.             INC( Errors );
  684.             IF ( Errors > Max_Errors ) THEN
  685.                Do_Exit := TRUE
  686.             ELSE
  687.                State := S_Send_Data;
  688.          END
  689.       ELSE IF ( Ch = ETX ) THEN
  690.          State := S_Send_NAK;
  691.  
  692. END   (* Do_S_Get_DLE *);
  693.  
  694. (*----------------------------------------------------------------------*)
  695.  
  696. PROCEDURE Do_S_Get_Num;
  697.  
  698. BEGIN (* Do_S_Get_Num *)
  699.  
  700.    IF ( NOT Read_Byte ) THEN
  701.       State := S_Timed_Out
  702.    ELSE IF ( ( Ch >= ORD('0') ) AND ( Ch <= ORD('9') ) ) THEN
  703.       BEGIN (* Received ACK *)
  704.  
  705.          Sent_ENQ  := FALSE;
  706.          Sent_NAK  := FALSE;
  707.          Block_Num := Ch - ORD('0');
  708.  
  709.          IF ( SA_Buf[SA_Next_to_ACK].Seq = Block_Num ) THEN
  710.             BEGIN (* This is the one we're waiting for *)
  711.                SA_Next_to_ACK := Incr_SA( SA_Next_to_ACK );
  712.                DEC( SA_Waiting );
  713.                Got_An_ACK := TRUE;
  714.                Do_Exit    := TRUE;
  715.             END
  716.          ELSE IF ( SA_Buf[ Incr_SA( SA_Next_to_ACK ) ].Seq = Block_Num ) THEN
  717.             BEGIN (* Must have missed an ACK *)
  718.                SA_Next_to_ACK := Incr_SA (SA_Next_to_ACK);
  719.                SA_Next_to_ACK := Incr_SA (SA_Next_to_ACK);
  720.                DEC( SA_Waiting , 2 );
  721.                Got_An_ACK := TRUE;
  722.                Do_Exit    := TRUE;
  723.             END
  724.          ELSE IF ( SA_Buf[ SA_Next_to_ACK ].Seq = Incr_Seq( Block_Num ) ) THEN
  725.             State := S_Get_DLE    (* Duplicate ACK *)
  726.          ELSE
  727.             State := S_Timed_Out;
  728.       END (* Received ACK *)
  729.    ELSE IF ( Ch = ORD('B') ) THEN
  730.       State := S_Get_Packet        (* Try to receive a packet *)
  731.    ELSE IF ( Ch = NAK ) THEN
  732.       BEGIN
  733.          INC( Errors );
  734.          IF ( Errors > Max_Errors ) THEN
  735.             Do_Exit := TRUE
  736.          ELSE
  737.             State := S_Send_Data
  738.       END
  739.    ELSE
  740.       State := S_Timed_Out;
  741.  
  742. END   (* Do_S_Get_Num *);
  743.  
  744. (*----------------------------------------------------------------------*)
  745.  
  746. PROCEDURE Do_S_Get_Packet;
  747.  
  748. BEGIN (* Do_S_Get_Packet *)
  749.                                    (* Read a packet *)
  750.  
  751.    IF Read_Packet( TRUE , TRUE ) THEN
  752.       BEGIN
  753.                                    (* If failure packet, send ACK *)
  754.                                    (* but indicate we didn't get  *)
  755.                                    (* ACK packet.                 *)
  756.  
  757.          IF ( R_Buffer[0] = ORD('F') ) THEN
  758.             Send_ACK
  759.          ELSE
  760.             Got_An_ACK := TRUE;
  761.  
  762.          Do_Exit := TRUE;
  763.  
  764.       END
  765.                                    (* On a bad receive, try again. *)
  766.    ELSE
  767.       State := S_Timed_Out;
  768.  
  769. END   (* Do_S_Get_Packet *);
  770.  
  771. (*----------------------------------------------------------------------*)
  772.  
  773. PROCEDURE Do_S_Timed_Out;
  774.  
  775. BEGIN (* Do_S_Timed_Out *)
  776.                                    (* Increment error count *)
  777.    INC( Errors );
  778.                                    (* If too many time outs, quit *)
  779.    IF ( Errors > 4 ) THEN
  780.       Do_Exit := TRUE
  781.                                    (* Send ENQ to wake up host if  *)
  782.                                    (* we haven't already sent one. *)
  783.    ELSE
  784.       BEGIN
  785.  
  786.          IF ( NOT Sent_ENQ ) THEN
  787.             BEGIN
  788.                Send_ENQ;
  789.                Sent_ENQ := TRUE;
  790.             END;
  791.  
  792.          State := S_Get_DLE;
  793.  
  794.       END;
  795.  
  796. END   (* Do_S_Timed_Out *);
  797.  
  798. (*----------------------------------------------------------------------*)
  799.  
  800. PROCEDURE Do_S_Send_NAK;
  801.  
  802. BEGIN (* Do_S_Send_NAK *)
  803.                                    (* Increment error count *)
  804.    INC( Errors );
  805.                                    (* If too many, quit. *)
  806.    IF ( Errors > Max_Errors ) THEN
  807.       Do_Exit    := TRUE
  808.                                    (* If we didn't send NAK yet, *)
  809.                                    (* send one.                  *)
  810.    ELSE
  811.       BEGIN
  812.  
  813.          IF ( NOT Sent_NAK ) THEN
  814.             BEGIN
  815.                Send_NAK;
  816.                Sent_NAK := TRUE;
  817.             END;
  818.  
  819.          State := S_Get_DLE;
  820.  
  821.       END;
  822.  
  823. END   (* Do_S_Send_NAK *);
  824.  
  825. (*----------------------------------------------------------------------*)
  826.  
  827. PROCEDURE Do_S_Send_Data;
  828.  
  829. VAR
  830.    I : INTEGER;
  831.  
  832. BEGIN (* Do_S_Send_Data *)
  833.                                    (* Get slot of data to send *)
  834.    SA_Index := SA_Next_to_ACK;
  835.                                    (* Send data *)
  836.    FOR I := 1 TO SA_Waiting DO
  837.       BEGIN
  838.          Send_Data( SA_Index );
  839.          SA_Index := Incr_SA( SA_Index );
  840.       END;
  841.  
  842.    State    := S_Get_DLE;
  843.  
  844.    Sent_ENQ := FALSE;
  845.    Sent_NAK := FALSE;
  846.  
  847. END   (* Do_S_Send_Data *);
  848.  
  849. (*----------------------------------------------------------------------*)
  850.  
  851. BEGIN (* Get_ACK *)
  852.  
  853.    Errors          := 0;
  854.    Sent_ENQ        := FALSE;
  855.    Sent_NAK        := FALSE;
  856.    State           := S_Get_DLE;
  857.                                    (* Increment packet count *)
  858.    INC( Total_Packets );
  859.                                    (* No ACK found yet *)
  860.    Do_Exit    := FALSE;
  861.    Got_An_ACK := FALSE;
  862.                                    (* Loop looking for ACK *)
  863.  
  864.    WHILE ( NOT ( Halt_Transfer OR Do_Exit OR Got_An_ACK ) ) DO
  865.       BEGIN
  866.                                    (* Check keyboard input *)
  867.          Check_Keyboard;
  868.                                    (* Handle current ACK state *)
  869.          CASE State OF
  870.  
  871.             S_Get_DLE    : Do_S_Get_DLE     (* Get initial <DLE> *);
  872.             S_Get_Num    : Do_S_Get_Num     (* Get packet number *);
  873.             S_Get_Packet : Do_S_Get_Packet  (* Get packet itself *);
  874.             S_Timed_Out  : Do_S_Timed_Out   (* Handle time out   *);
  875.             S_Send_NAK   : Do_S_Send_NAK    (* Send NAK to host  *);
  876.             S_Send_Data  : Do_S_Send_Data   (* Send data to host *);
  877.  
  878.          END (* CASE *);
  879.  
  880.       END (* WHILE *);
  881.  
  882.    Get_ACK := Got_An_ACK;
  883.  
  884. END   (* Get_ACK *);
  885.  
  886. (*----------------------------------------------------------------------*)
  887. (*           Send_Packet --- Send packet to host                        *)
  888. (*----------------------------------------------------------------------*)
  889.  
  890. FUNCTION Send_Packet( Size : INTEGER ) : BOOLEAN;
  891.  
  892. BEGIN (* Send_Packet *)
  893.                                    (* If window full, look for ACK *)
  894.                                    (* to open slot.  If not found, *)
  895.                                    (* don't send this packet.      *)
  896.  
  897.    IF ( SA_Waiting = SA_Max ) THEN
  898.       IF ( NOT Get_ACK ) THEN
  899.          BEGIN
  900.             Send_Packet := FALSE;
  901.             EXIT;
  902.          END;
  903.                                    (* Get next slot and fill in size, *)
  904.                                    (* sequence number of packet.      *)
  905.  
  906.    Seq_Num                     := Incr_Seq( Seq_Num );
  907.    SA_Buf[SA_Next_to_Fill].Seq := Seq_Num;
  908.    SA_Buf[SA_Next_to_Fill].Num := Size;
  909.  
  910.                                    (* Send the data. *)
  911.    Send_Data( SA_Next_to_Fill );
  912.                                    (* Get slot to be filled next. *)
  913.  
  914.    SA_Next_to_Fill := Incr_SA( SA_Next_to_Fill );
  915.  
  916.                                    (* Increment count of packets *)
  917.                                    (* waiting for ACK            *)
  918.    INC( SA_Waiting );
  919.  
  920.    Send_Packet     := TRUE;
  921.  
  922. END   (* Send_Packet *);
  923.  
  924. (*----------------------------------------------------------------------*)
  925. (*           SA_Flush --- Synchronize last packet with host             *)
  926. (*----------------------------------------------------------------------*)
  927.  
  928. FUNCTION SA_Flush : BOOLEAN;
  929.  
  930. (*----------------------------------------------------------------------*)
  931. (*                                                                      *)
  932. (*  SA_Flush is called after sending the last packet to get host's      *)
  933. (*  ACKs on outstanding packets.                                        *)
  934. (*                                                                      *)
  935. (*----------------------------------------------------------------------*)
  936.  
  937. BEGIN (* SA_Flush *)
  938.  
  939.    WHILE( SA_Waiting <> 0 ) DO
  940.       IF ( NOT Get_ACK ) THEN
  941.          BEGIN
  942.             SA_Flush := FALSE;
  943.             EXIT;
  944.          END;
  945.  
  946.    SA_Flush := TRUE;
  947.  
  948. END   (* SA_Flush *);
  949.  
  950. (*----------------------------------------------------------------------*)
  951. (*           Send_Failure --- Send failure code to host                 *)
  952. (*----------------------------------------------------------------------*)
  953.  
  954. PROCEDURE Send_Failure (* Code : CHAR *);
  955.  
  956. VAR
  957.    Dummy : BOOLEAN;
  958.  
  959. BEGIN (* Send_Failure *)
  960.                                    (* Reinitialize send-ahead variables *)
  961.    SA_Next_to_ACK  := 0;
  962.    SA_Next_to_Fill := 0;
  963.    SA_Waiting      := 0;
  964.                                    (* Prepare failure packet *)
  965.    WITH SA_Buf[0] DO
  966.       BEGIN
  967.          Buf[0] := ORD( 'F'  );
  968.          Buf[1] := ORD( Code );
  969.       END;
  970.                                    (* Send failure packet and wait *)
  971.                                    (* for host to ACK it           *)
  972.    IF Send_Packet( 1 ) THEN
  973.       Dummy := SA_Flush;
  974.  
  975. END   (* Send_Failure *);
  976.  
  977. (*----------------------------------------------------------------------*)
  978. (*           Read_File --- Read data from file being sent out           *)
  979. (*----------------------------------------------------------------------*)
  980.  
  981. FUNCTION Read_File( VAR Data_File : FILE;
  982.                     VAR S_Buffer  : BufferType;
  983.                     N             : INTEGER;
  984.                     Xmt_Size      : INTEGER ) : INTEGER;
  985.  
  986. VAR
  987.    L : INTEGER;
  988.  
  989. BEGIN (* Read_File *)
  990.  
  991.    BlockRead( Data_File, S_Buffer[N], Xmt_Size, L );
  992.  
  993.    Read_File := L;
  994.  
  995. END    (* Read_File *);
  996.  
  997. (*----------------------------------------------------------------------*)
  998. (*           Send_File --- Handle file sending using CISB B             *)
  999. (*----------------------------------------------------------------------*)
  1000.  
  1001. FUNCTION Send_File( Name : AnyStr ) : BOOLEAN;
  1002.  
  1003. VAR
  1004.    N         : INTEGER;
  1005.    Data_File : FILE;
  1006.    IO_Error  : INTEGER;
  1007.    Cps_S     : STRING[10];
  1008.    CPS       : INTEGER;
  1009.    Send_Mess : AnyStr;
  1010.    Open_OK   : BOOLEAN;
  1011.  
  1012. LABEL Error;
  1013.  
  1014. BEGIN (* Send_File *)
  1015.                                    (* Assume send fails        *)
  1016.    Send_File := FALSE;
  1017.  
  1018.    FileMode := 0;
  1019.  
  1020.    ASSIGN( Data_File , Name );
  1021.    RESET ( Data_File , 1    );
  1022.  
  1023.    FileMode := 2;
  1024.  
  1025.    IO_Error := Int24Result;
  1026.                                    (* If file can't be opened, halt *)
  1027.                                    (* transfer.                     *)
  1028.  
  1029.    IF ( IO_Error <> 0 ) THEN
  1030.       BEGIN
  1031.          Send_Failure('E');
  1032.          Display_Message('Can''t open file to be sent, transfer stopped.',
  1033.                          Err_Mess_Line);
  1034.          TFile_Size := 0;
  1035.          GOTO Error;
  1036.       END;
  1037.                                    (* Remember file size *)
  1038.  
  1039.    TFile_Size := FileSize( Data_File );
  1040.  
  1041.                                    (* Remember starting time for transfer *)
  1042.    Starting_Time := TimeOfDay;
  1043.  
  1044.    REPEAT
  1045.                                    (* Read next sector of data *)
  1046.  
  1047.       WITH SA_Buf[ SA_Next_to_Fill ] DO
  1048.          BEGIN
  1049.             Buf[0] := ORD('N');
  1050.             N      := Read_File( Data_File, Buf, 1, Buffer_Size );
  1051.          END;
  1052.  
  1053.      IF ( Int24Result <> 0 ) THEN
  1054.         BEGIN
  1055.            N             := -1;
  1056.            Halt_Transfer := TRUE;
  1057.         END;
  1058.                                    (* Send data packet if anything *)
  1059.                                    (* to send.                     *)
  1060.       IF ( N > 0 ) THEN
  1061.          BEGIN
  1062.                                    (* If packet not sent, report *)
  1063.                                    (* failure.                   *)
  1064.             INC( Total_Blocks    );
  1065.             INC( Total_Bytes , N );
  1066.  
  1067.             IF ( NOT Send_Packet( N ) ) THEN
  1068.                BEGIN
  1069.                   Display_Message('Can''t send packet, transfer stopped.',
  1070.                                   Err_Mess_Line);
  1071.                   Halt_Transfer := TRUE;
  1072.                END;
  1073.  
  1074.          END;
  1075.                                    (* Check for keyboard input halting *)
  1076.                                    (* transfer.                        *)
  1077.  
  1078.       IF ( NOT Halt_Transfer ) THEN
  1079.          BEGIN
  1080.  
  1081.             Check_Keyboard;
  1082.  
  1083.             IF Halt_Transfer THEN
  1084.                BEGIN
  1085.                   Send_Failure('E');
  1086.                   Display_Message('Transfer terminated by keyboard request.',
  1087.                                   Err_Mess_Line);
  1088.                END;
  1089.  
  1090.          END;
  1091.  
  1092.       Update_B_Display;
  1093.  
  1094.    UNTIL ( N <= 0 ) OR Halt_Transfer;
  1095.  
  1096.    IF ( N < 0 ) THEN
  1097.       BEGIN (* Read failure *)
  1098.          Send_Failure('E');
  1099.          Display_Message('Error reading file, transfer stopped.',
  1100.                          Err_Mess_Line);
  1101.       END   (* Read failure *);
  1102.  
  1103.                                    (* Close file *)
  1104.    Ending_Time := TimeOfDay;
  1105.  
  1106.    CLOSE( Data_File );
  1107.  
  1108.    IO_Error := Int24Result;
  1109.  
  1110.    IF ( NOT Halt_Transfer ) THEN
  1111.       BEGIN
  1112.                                    (* Send end of file packet. *)
  1113.  
  1114.          WITH SA_Buf[ SA_Next_to_Fill ] DO
  1115.             BEGIN
  1116.                Buf[0] := ORD('T');
  1117.                Buf[1] := ORD('C');
  1118.             END;
  1119.  
  1120.          IF ( NOT Send_Packet( 2 ) ) THEN
  1121.             Display_Message('Can''t send end of file packet, transfer stopped.',
  1122.                             Err_Mess_Line )
  1123.          ELSE
  1124.             BEGIN
  1125.                IF SA_Flush THEN
  1126.                   BEGIN
  1127.                      Send_File  := TRUE;
  1128.                      Total_Time := TimeDiff( Starting_Time , Ending_Time );
  1129.                      Send_Mess  := 'Send complete.';
  1130.                      IF ( Total_Time > 0 ) THEN
  1131.                         BEGIN
  1132.                            CPS := TRUNC( Total_Bytes / Total_Time );
  1133.                            STR( CPS , Cps_S );
  1134.                            Send_Mess := Send_Mess + ' Transfer rate: ' + Cps_S +
  1135.                                         ' CPS.';
  1136.                         END;
  1137.                      Display_Message( Send_Mess , Err_Mess_Line );
  1138.                  END;
  1139.             END;
  1140.  
  1141.       END;
  1142.                                    (* Reset serial port if necessary *)
  1143. Error:
  1144.    IF Reset_Port THEN
  1145.       Async_Reset_Port( Comm_Port, Baud_Rate,
  1146.                         Xmodem_Parity_Save,
  1147.                         Xmodem_Bits_Save,
  1148.                         Xmodem_Stop_Save );
  1149.  
  1150.    Reset_Port := FALSE;
  1151.  
  1152.    Window_Delay;
  1153.  
  1154. END    (* Send_File *);
  1155.  
  1156. (*----------------------------------------------------------------------*)
  1157. (*   Do_Transport_Parameters --- Handle '+' packet for Quick B settings *)
  1158. (*----------------------------------------------------------------------*)
  1159.  
  1160. PROCEDURE Do_Transport_Parameters;
  1161.  
  1162. (*----------------------------------------------------------------------*)
  1163. (*                                                                      *)
  1164. (*  Do_Transport_Parameters is called when a Packet type of + is        *)
  1165. (*  received.  It sends a packet of our local Quick B parameters and    *)
  1166. (*  sets the Our_xx parameters to the minimum of the sender's and our   *)
  1167. (*  own parameters.                                                     *)
  1168. (*                                                                      *)
  1169. (*----------------------------------------------------------------------*)
  1170.  
  1171. BEGIN (* Do_Transport_Parameters *)
  1172.  
  1173.                                    (* Pick out sender's parameters *)
  1174.    His_WS := R_Buffer[1];
  1175.    His_WR := R_Buffer[2];
  1176.    His_BS := R_Buffer[3];
  1177.    His_CM := R_Buffer[4];
  1178.                                    (* Prepare to return our own parameters *)
  1179.    WITH SA_Buf[SA_Next_to_Fill] DO
  1180.       BEGIN
  1181.          Buf[0] := ORD('+');
  1182.          Buf[1] := Def_WS;
  1183.          Buf[2] := Def_WR;
  1184.          Buf[3] := Def_BS;
  1185.          Buf[4] := Def_CM;
  1186.          Buf[5] := Def_DQ;
  1187.       END;
  1188.  
  1189.    IF ( NOT Send_Packet( 5 ) ) THEN
  1190.       EXIT;
  1191.  
  1192.    IF SA_Flush THEN                 (* Wait for host's ACK on our packet *)
  1193.       BEGIN
  1194.                                     (* ** Take minimal subset of Transport Params. **  *)
  1195.  
  1196.                                     (* If he can send ahead, we can receive it. *)
  1197.  
  1198.          Our_WR := MIN( His_WS , Def_WR );
  1199.  
  1200.                                     (* If he can receive send ahead, we can send it. *)
  1201.  
  1202.          Our_WS := MIN( His_WR , Def_WS );
  1203.          Our_BS := MIN( His_BS , Def_BS );
  1204.          Our_CM := MIN( His_CM , Def_CM );
  1205.  
  1206.                                     (* Set Our_BS = 4 as default if not given *)
  1207.          IF ( Our_BS = 0 ) THEN
  1208.             Our_BS := 4;
  1209.                                     (* Set buffer size *)
  1210.  
  1211.          Buffer_Size := Our_BS * 128;
  1212.  
  1213.                                    (* Quick B protocol is available *)
  1214.          Quick_B := TRUE;
  1215.                                    (* Set CRC mode *)
  1216.          Use_CRC := ( Our_CM = 1 );
  1217.  
  1218.          IF ( Our_WS <> 0 ) THEN
  1219.             BEGIN
  1220.                SA_Enabled := TRUE;
  1221.                SA_Max     := Max_SA;
  1222.             END;
  1223.  
  1224.       END;
  1225.                                    (* Reinitialize display with new params *)
  1226.    Initialize_Transfer_Display;
  1227.  
  1228. END   (* Do_Transport_Parameters *);
  1229.  
  1230. (*----------------------------------------------------------------------*)
  1231. (*   Do_Application_Parameters --- Handle '?' packet                    *)
  1232. (*----------------------------------------------------------------------*)
  1233.  
  1234. PROCEDURE Do_Application_Parameters;
  1235.  
  1236. (*----------------------------------------------------------------------*)
  1237. (*                                                                      *)
  1238. (*  Do_Application_Parameters is called when a ? packet is received.    *)
  1239. (*  This version ignores the host's packet and returns a ? packet       *)
  1240. (*  saying that normal B Protocol File Transfer is supported.           *)
  1241. (*  (Well, actually it says that no extended application packets are    *)
  1242. (*  supported.  The T packet is assumed to be standard.)                *)
  1243. (*                                                                      *)
  1244. (*----------------------------------------------------------------------*)
  1245.  
  1246. VAR
  1247.    Dummy : BOOLEAN;
  1248.  
  1249. BEGIN (* Do_Application_Parameters *)
  1250.  
  1251.    WITH SA_Buf[ SA_Next_to_Fill ] DO
  1252.       BEGIN
  1253.          Buf[0] := ORD('?');       (* Build the ? packet *)
  1254.          Buf[1] := 1;              (* The T packet flag  *)
  1255.       END;
  1256.  
  1257.    IF Send_Packet( 1 ) THEN              (* Send the packet *)
  1258.       Dummy := SA_Flush;
  1259.  
  1260. END   (* Do_Application_Parameters *);
  1261.  
  1262. (*----------------------------------------------------------------------*)
  1263. (*            Write_File --- Write received data to PC file             *)
  1264. (*----------------------------------------------------------------------*)
  1265.  
  1266. FUNCTION Write_File( VAR Data_File : FILE;
  1267.                          R_Buffer  : BufferType;
  1268.                          N         : INTEGER;
  1269.                          Size      : INTEGER) : INTEGER;
  1270.  
  1271. VAR
  1272.    Size_Written : INTEGER;
  1273.  
  1274. BEGIN (* Write_File *)
  1275.  
  1276.    BlockWrite( Data_File, R_Buffer[ N ], Size, Size_Written );
  1277.    Write_File := Size_Written;
  1278.  
  1279. END   (* Write_File *);
  1280.  
  1281. (*----------------------------------------------------------------------*)
  1282. (*            Receive_File --- Handle file reception using CIS B        *)
  1283. (*----------------------------------------------------------------------*)
  1284.  
  1285. FUNCTION Receive_File( Name : AnyStr ) : BOOLEAN;
  1286.  
  1287. VAR
  1288.    Data_File : FILE;
  1289.    Status    : INTEGER;
  1290.    R_File    : BOOLEAN;
  1291.    Cps_S     : STRING[10];
  1292.    CPS       : INTEGER;
  1293.    Rec_Mess  : AnyStr;
  1294.  
  1295. LABEL  Error;
  1296.  
  1297. BEGIN (* Receive_File *)
  1298.                                    (* Assume transfer fails   *)
  1299.    R_File := FALSE;
  1300.                                    (* Open file to be created *)
  1301.  
  1302.    Add_Path( Name, Download_Dir_Path, Name );
  1303.  
  1304.    ASSIGN ( Data_File , Name );
  1305.    REWRITE( Data_File , 1  );
  1306.                                    (* Halt transfer if file can't be *)
  1307.                                    (* opened.                        *)
  1308.    Status := Int24Result;
  1309.  
  1310.    IF ( Status <> 0 ) THEN
  1311.       BEGIN
  1312.          Send_Failure('E');
  1313.          Display_Message('Can''t open output file, transfer stoppped.',
  1314.                          Err_Mess_Line);
  1315.          Receive_File := FALSE;
  1316.          GOTO Error;
  1317.       END;
  1318.                                    (* Send ACK to start transfer  *)
  1319.    Send_ACK;
  1320.                                    (* Remember starting time for transfer *)
  1321.    Starting_Time := TimeOfDay;
  1322.                                    (* Begin loop over packets *)
  1323.  
  1324.    WHILE ( NOT ( Halt_Transfer OR R_File  ) ) DO
  1325.       BEGIN
  1326.                                    (* Get next packet *)
  1327.  
  1328.          IF Read_Packet( FALSE , FALSE ) THEN
  1329.             BEGIN
  1330.                                    (* Select Action based upon packet type *)
  1331.  
  1332.                CASE CHR( R_Buffer[0] ) OF
  1333.  
  1334.                                    (* Data for file -- write it and *)
  1335.                                    (* acknowledge it.               *)
  1336.                   'N': BEGIN
  1337.                           Status := Write_File( Data_File, R_Buffer, 1,
  1338.                                                 PRED( R_Size ) );
  1339.  
  1340.                           IF ( Int24Result <> 0 ) THEN
  1341.                              BEGIN
  1342.                                 Display_Message('** Write failure...aborting',
  1343.                                                 Err_Mess_Line);
  1344.                                 ClrEol;
  1345.                                 Send_Failure ('E');
  1346.                                 Halt_Transfer := TRUE;
  1347.                              END
  1348.                           ELSE
  1349.                              BEGIN
  1350.                                 Send_ACK;
  1351.                                 Total_Blocks := Total_Blocks + 1;
  1352.                                 Total_Bytes  := Total_Bytes  + R_Size - 1;
  1353.                              END;
  1354.                        END;
  1355.  
  1356.                                    (* End of transfer -- close file *)
  1357.                                    (* and acknowledge end of file   *)
  1358.                   'T': BEGIN
  1359.  
  1360.                           IF ( R_Buffer[1] = ORD('C') ) THEN
  1361.                              BEGIN
  1362.                                 Ending_Time  := TimeOfDay;
  1363.                                 CLOSE( Data_File );
  1364.                                 Status := Int24Result;
  1365.                                 IF ( Status <> 0 ) THEN
  1366.                                    BEGIN
  1367.                                       Display_Message('** Failure during close...aborting',
  1368.                                                       Err_Mess_Line);
  1369.                                       Send_Failure ('E');
  1370.                                       Halt_Transfer := TRUE;
  1371.                                    END
  1372.                                 ELSE
  1373.                                    BEGIN
  1374.                                       Send_ACK;
  1375.                                       R_File  := TRUE;
  1376.                                       Total_Time := TimeDiff( Starting_Time ,
  1377.                                                               Ending_Time );
  1378.                                       Rec_Mess   := 'Receive complete.';
  1379.                                       IF ( Total_Time > 0 ) THEN
  1380.                                          BEGIN
  1381.                                             CPS := TRUNC( Total_Bytes / Total_Time );
  1382.                                             STR( CPS , Cps_S );
  1383.                                             Rec_Mess := Rec_Mess + ' Transfer rate: ' + Cps_S +
  1384.                                                         ' CPS.';
  1385.                                          END;
  1386.  
  1387.                                       Display_Message( Rec_Mess , Err_Mess_Line );
  1388.                                    END;
  1389.  
  1390.                              END;
  1391.  
  1392.                        END;
  1393.                                    (* Stop transfer received -- halt *)
  1394.                                    (* transfer and acknowledge.      *)
  1395.                   'F': BEGIN
  1396.                           Send_ACK;
  1397.                           Halt_Transfer := TRUE;
  1398.                           Display_Message('Host cancelled transfer.', Err_Mess_Line);
  1399.                        END;
  1400.  
  1401.                 END   (* CASE *);
  1402.  
  1403.             END  (* IF *)
  1404.          ELSE
  1405.             BEGIN (* No packet received *)
  1406.                Halt_Transfer := TRUE;
  1407.                Display_Message('Failed to received packet, transfer aborted.',
  1408.                                Err_Mess_Line);
  1409.                ClrEol;
  1410.             END   (* No packet received *);
  1411.  
  1412.                                    (* Check for keyboard input halting *)
  1413.                                    (* transfer.                        *)
  1414.  
  1415.          IF ( NOT Halt_Transfer ) THEN
  1416.             BEGIN
  1417.  
  1418.                Check_Keyboard;
  1419.  
  1420.                IF Halt_Transfer THEN
  1421.                   BEGIN
  1422.                      Send_Failure('E');
  1423.                      Display_Message('Transfer terminated by keyboard request.',
  1424.                                      Err_Mess_Line);
  1425.                      ClrEol;
  1426.                   END;
  1427.  
  1428.             END;
  1429.  
  1430.       END  (* WHILE *);
  1431.  
  1432.    Receive_File := R_File AND ( NOT Halt_Transfer );
  1433.    Ending_Time  := TimeOfDay;
  1434.                                    (* Close received file *)
  1435.    CLOSE( Data_File );
  1436.  
  1437.    Status := Int24Result;
  1438.                                    (* If we are to delete partially *)
  1439.                                    (* received files, do so.        *)
  1440.  
  1441.    IF ( ( NOT R_File ) AND Evict_Partial_Trans ) THEN
  1442.       ERASE( Data_File );
  1443.  
  1444.    Status := Int24Result;
  1445.  
  1446. Error:
  1447.    IF Reset_Port THEN
  1448.       Async_Reset_Port( Comm_Port, Baud_Rate,
  1449.                         Xmodem_Parity_Save,
  1450.                         Xmodem_Bits_Save,
  1451.                         Xmodem_Stop_Save );
  1452.    Reset_Port := FALSE;
  1453.  
  1454.    Window_Delay;
  1455.  
  1456. END   (* Receive_File *);
  1457.  
  1458. (*----------------------------------------------------------------------*)
  1459. (*            CISB_DLE_Seen --- M A I N   R O U T I N E                 *)
  1460. (*----------------------------------------------------------------------*)
  1461.  
  1462. BEGIN (* CISB_DLE_Seen *)
  1463.                                    (* Begin by getting the next character.  *)
  1464.                                    (* If it is <B> then enter the           *)
  1465.                                    (* B_Protocol State.  Otherwise simply   *)
  1466.                                    (* return.                               *)
  1467.    Timer         := 10;
  1468.    Halt_Transfer := FALSE;
  1469.  
  1470.    IF ( NOT Read_Byte ) THEN
  1471.       EXIT
  1472.    ELSE IF ( Ch <> ORD('B') ) THEN
  1473.       EXIT;
  1474.                                    (* Initialize send-ahead variables *)
  1475.    SA_Next_to_ACK  := 0;
  1476.    SA_Next_to_Fill := 0;
  1477.    SA_Waiting      := 0;
  1478.                                    (* Reset comm parms to 8,n,1 if we aren't *)
  1479.                                    (* set to that already.                   *)
  1480.    Xmodem_Bits_Save   := Data_Bits;
  1481.    Xmodem_Parity_Save := Parity;
  1482.    Xmodem_Stop_Save   := Stop_Bits;
  1483.  
  1484.    IF ( ( Data_Bits = 8 ) AND ( Parity = 'N' ) ) THEN
  1485.       Reset_Port := FALSE
  1486.    ELSE
  1487.       BEGIN
  1488.          Async_Reset_Port( Comm_Port, Baud_Rate, 'N', 8, 1 );
  1489.          Reset_Port := TRUE;
  1490.          IF Do_Status_Line THEN
  1491.             BEGIN
  1492.                Set_Status_Line_Name( Short_Terminal_Name );
  1493.                Write_To_Status_Line( Status_Line_Name, 1 );
  1494.             END;
  1495.       END;
  1496.                                    (* Announce protocol starts *)
  1497.  
  1498.    Save_Partial_Screen( Saved_Screen, 5, 10, 75, 20 );
  1499.  
  1500.    Comp_Title := 'CompuServe B Protocol';
  1501.  
  1502.    Receiving_File := TRUE;
  1503.  
  1504.    Initialize_Transfer_Display;
  1505.  
  1506.    Halt_Transfer  := FALSE;
  1507.    Receiving_File := TRUE;
  1508.    Display_Status := TRUE;
  1509.    Comp_Title     := 'CIS B -- ';
  1510.    Total_Blocks   := 0;
  1511.    Total_Packets  := 0;
  1512.    Total_Errors   := 0;
  1513.    Total_Bytes    := 0;
  1514.                                    (* Read initial packet *)
  1515.  
  1516.    IF Read_Packet( TRUE , FALSE ) THEN
  1517.       BEGIN
  1518.                                    (* Select Action based upon packet type *)
  1519.  
  1520.          CASE CHR( R_Buffer[0] ) OF
  1521.  
  1522.                                    (* Upload or download *)
  1523.             'T': BEGIN
  1524.  
  1525.                     CASE CHR( R_Buffer[1] ) OF
  1526.                        'D' : BEGIN
  1527.                                 Comp_Title := 'Receiving ';
  1528.                                 Receiving_File := TRUE;
  1529.                              END;
  1530.                        'U' : BEGIN
  1531.                                 Comp_Title := 'Sending ';
  1532.                                 Receiving_File := FALSE;
  1533.                              END;
  1534.                        ELSE
  1535.                              BEGIN
  1536.                                 Send_Failure('N');
  1537.                                 GOTO Error_Exit;
  1538.                              END;
  1539.                     END  (* CASE *);
  1540.  
  1541.                                    (* Get file name *)
  1542.  
  1543.                     CASE CHR( R_Buffer[2] ) OF
  1544.                        'A': Comp_Title := Comp_Title + 'ASCII file "';
  1545.                        'B': Comp_Title := Comp_Title + 'Binary file "';
  1546.                        ELSE
  1547.                           BEGIN
  1548.                              Send_Failure('N');        (* Not implemented *)
  1549.                              GOTO Error_Exit;
  1550.                           END;
  1551.                     END   (* CASE *);
  1552.  
  1553.                     I        := 2;
  1554.                     FileName := '';
  1555.  
  1556.                     WHILE ( R_Buffer[I] <> 0 ) AND ( I < R_Size ) DO
  1557.                        BEGIN
  1558.                           INC( I );
  1559.                           FileName := FileName + CHR( R_Buffer[I] );
  1560.                        END;
  1561.  
  1562.                     Comp_Title := Comp_Title + FileName + '"';
  1563.  
  1564.                                    (* Display file transfer header *)
  1565.  
  1566.                     Initialize_Transfer_Display;
  1567.  
  1568.                                    (* Perform transfer *)
  1569.  
  1570.                     IF ( R_Buffer[1] = ORD('U') ) THEN
  1571.                        Dummy := Send_File( FileName )
  1572.                     ELSE
  1573.                        Dummy := Receive_File( FileName );
  1574.  
  1575.                  END;
  1576.                                    (* Received Transport Parameters Packet *)
  1577.  
  1578.             '+': Do_Transport_Parameters;
  1579.  
  1580.                                    (* Received Application Parameters Packet *)
  1581.  
  1582.             '?': Do_Application_Parameters;
  1583.  
  1584.                                    (* Unknown packet; tell the host we don't know *)
  1585.             ELSE Send_Failure ('N');
  1586.  
  1587.          END (* CASE *);
  1588.  
  1589.       END (* BEGIN *)
  1590.                                    (* No initial packet -- quit *)
  1591.     ELSE
  1592.        BEGIN
  1593.           Display_Message('Can''t get first packet, transfer cancelled',
  1594.                           Err_Mess_Line);
  1595.           IF Reset_Port THEN
  1596.              Async_Reset_Port( Comm_Port, Baud_Rate, Xmodem_Parity_Save,
  1597.                                Xmodem_Bits_Save, Xmodem_Stop_Save );
  1598.           Reset_Port := FALSE;
  1599.           Window_Delay;
  1600.        END;
  1601.  
  1602. Error_Exit:
  1603.                                    (* Reset comm parms back *)
  1604.    IF Reset_Port THEN
  1605.       Async_Reset_Port( Comm_Port, Baud_Rate, Xmodem_Parity_Save,
  1606.                         Xmodem_Bits_Save, Xmodem_Stop_Save );
  1607.  
  1608.    IF Do_Status_Line THEN
  1609.       BEGIN
  1610.          Set_Status_Line_Name( Short_Terminal_Name );
  1611.          Write_To_Status_Line( Status_Line_Name, 1 );
  1612.       END;
  1613.                                    (* Restore previous screen *)
  1614.  
  1615.    Restore_Screen_And_Colors( Saved_Screen );
  1616.  
  1617.                                    (* Restore cursor *)
  1618.    CursorOn;
  1619.  
  1620. END   (* CISB_DLE_Seen *);
  1621.