home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TMODEM.ZIP / TMODEM.IN1 < prev    next >
Encoding:
Text File  |  1987-06-16  |  27.8 KB  |  862 lines

  1. (****************************************************************************)
  2. (*                      DETERMINE MEMORY AVAILABLE                          *)
  3. (****************************************************************************)
  4.    function
  5.       memory   : integer;
  6.    var
  7.       memspace : real;
  8.    begin
  9.       memspace := maxavail;
  10.       if memspace < 0 then
  11.          memspace := 65536.0 + memspace;
  12.       memory := round( (memspace * 16.0) / 1024.0 );
  13.    end;
  14.  
  15. (****************************************************************************)
  16. (*                         EN-QUE SERIAL PORT INPUT &                       *)
  17. (*                         DE-QUE SERIAL PORT OUTPUT                        *)
  18. (*                             INTERRUPT DRIVEN                             *)
  19. (****************************************************************************)
  20.    procedure
  21.       async_intr_handler;
  22.    begin
  23.       inline ($FB/$50/$53/$51/$52/$57/$56/$06/$1E);
  24.       inline ($2E/$A1/datasegment
  25.              /$8E/$D8);
  26.       int_ident := port[int_ident_reg];
  27.       repeat
  28.          if int_ident = 4 then begin
  29.             line_status := port[line_status_reg] and $1C;
  30.             sin_buffer[sin_store_ptr] := port[base_com_addr];
  31.             if line_status = 0 then begin
  32.                if ascii_mode then begin
  33.                   case sin_buffer[sin_store_ptr] of
  34.                      XOFF : port[int_enable_reg] := 1;
  35.                      XON  : port[int_enable_reg] := 3;
  36.                   end;
  37.                end;
  38.                if sin_store_ptr = sin_buf_size then
  39.                   sin_store_ptr := 1
  40.                else
  41.                   sin_store_ptr := sin_store_ptr + 1;
  42.             end;
  43.          end
  44.          else begin
  45.             if sout_store_ptr = sout_read_ptr then begin
  46.                port[int_enable_reg] := 1;
  47.                sout_int_off := true;
  48.             end
  49.             else begin
  50.                port[base_com_addr] := sout_buffer[sout_read_ptr];
  51.                if sout_read_ptr = sout_buf_size then
  52.                   sout_read_ptr := 1
  53.                else
  54.                   sout_read_ptr := sout_read_ptr + 1;
  55.             end;
  56.          end;
  57.          int_ident := port[int_ident_reg];
  58.       until int_ident = 1;
  59.       port[$20] := $20;
  60.       inline ($1F/$07/$5E/$5F/$5A/$59/$5B/$58/$5D/$5D/$CF);
  61.    end;
  62.  
  63. (****************************************************************************)
  64. (*                        DE-QUE SERIAL PORT INPUT                          *)
  65. (****************************************************************************)
  66.    function
  67.       read_sin_buffer : char;
  68.    begin
  69.       read_sin_buffer := chr(sin_buffer[sin_read_ptr]);
  70.       if sin_read_ptr = sin_buf_size then
  71.          sin_read_ptr := 1
  72.       else
  73.          sin_read_ptr := sin_read_ptr + 1;
  74.    end;
  75.  
  76. (****************************************************************************)
  77. (*                       EN-QUE SERIAL PORT OUTPUT                          *)
  78. (****************************************************************************)
  79.    procedure
  80.       store_sout_buffer(ch : char);
  81.    var
  82.       new_sout_store_ptr   : integer;
  83.       cnt                  : integer;
  84.    begin
  85.       if sout_store_ptr = sout_buf_size then
  86.          new_sout_store_ptr := 1
  87.       else
  88.          new_sout_store_ptr := sout_store_ptr + 1;
  89.       cnt := 0;
  90.       while new_sout_store_ptr = sout_read_ptr do begin  { Wait for room }
  91.          cnt := cnt + 1;                                 { in the queue. }
  92.          if cnt > 40 then begin
  93.             sout_store_ptr := sout_read_ptr;
  94.             continue_transfer := false;
  95.             exit;
  96.          end;
  97.          delay(wait_increment);
  98.       end;
  99.       sout_buffer[sout_store_ptr] := ord(ch);
  100.       sout_store_ptr := new_sout_store_ptr;
  101.       if sout_int_off then begin
  102.          sout_int_off := false;
  103.          port[int_enable_reg] := 3;
  104.       end;
  105.    end;
  106.  
  107. (****************************************************************************)
  108. (*                           SETUP SERIAL PORT                              *)
  109. (****************************************************************************)
  110.    procedure setserial(baudrate,stopbits,databits : integer;
  111.                       parity : parityType);
  112.    var
  113.       parameter : integer;
  114.       parn      : byte;
  115.    begin
  116.       case baudrate of
  117.          300  : begin
  118.                    baudrate:=2;
  119.                    sync_time := wait_increment div 4;
  120.                 end;
  121.          1200 : begin
  122.                    baudrate:=4;
  123.                    sync_time := wait_increment div 10;
  124.                 end;
  125.          2400 : begin
  126.                    baudrate:=5;
  127.                    sync_time := wait_increment div 20;
  128.                 end;
  129.       else
  130.          baudrate:=4;                     { Default to 1200 baud }
  131.          sync_time := wait_increment div 10;
  132.       end;
  133.       if stopbits=2 then
  134.          stopbits:=1
  135.       else
  136.          stopbits:=0;                     { Default to 1 stop bit }
  137.       case parity of
  138.          even : parn:=1;
  139.          odd  : parn:=2;
  140.       else
  141.          parn:=0;
  142.       end;
  143.       if databits=7 then
  144.          databits:=2
  145.       else begin
  146.          databits:=3;                     { Default to 8 data bits }
  147.          parn:=0;
  148.       end;
  149.       parameter:=(baudrate shl 5)+(stopbits shl 2)+databits;
  150.       case parn of
  151.          1 : parameter:=parameter+24;
  152.          2 : parameter:=parameter+8;
  153.       end;
  154.       regs.DX := 0;                       { 0 = COM1;   1 = COM2 }
  155.       regs.AX := parameter;
  156.       regs.FLAGS := 0;
  157.       intr($14,regs);
  158.       port[int_enable_reg] := 1;
  159.       port[modem_control_reg] := $0B;
  160.       port[$21] := port[$21] and turn_IRQ_on;
  161.       sout_int_off := true;
  162.    end;
  163.  
  164. (****************************************************************************)
  165. (*                         DISPLAY PROMPTS LINE                             *)
  166. (****************************************************************************)
  167.    procedure
  168.       clear_pos( i,j : integer );
  169.    begin
  170.       escape_win;
  171.       textcolor( BGcolor );
  172.       textbackground( FGcolor );
  173.       gotoxy(i,j);
  174.       write(' ');
  175.       textcolor( FGcolor );
  176.       textbackground( BGcolor );
  177.       reset_win;
  178.    end;
  179.  
  180.    procedure
  181.       display_prompts;
  182.    begin
  183.       escape_win;
  184.       textcolor( BGcolor );
  185.       textbackground( FGcolor );
  186.       gotoxy(1,25);
  187.       clreol;
  188.       write('   Alt: X=Exit, PgDn=Receive, PgUp=Transmit, C=Capture, S=Chg Prms, F10=Help  ');
  189.       textcolor( FGcolor );
  190.       textbackground( BGcolor );
  191.       reset_win;
  192.    end;
  193.  
  194. (****************************************************************************)
  195. (*                         SAVE CAPTURE BUFFERS                             *)
  196. (****************************************************************************)
  197.    procedure
  198.       save_capture_buffers;
  199.    var
  200.       r        : real;
  201.    begin
  202.       writeln;
  203.       write(' Enter Filename for Capture Buffer Save: ');
  204.       readln(filename);
  205.       if length(filename)=0 then exit;
  206.       assign(recv_file,filename);
  207.       rewrite(recv_file);
  208.       capture_curr := capture_first;
  209.       repeat
  210.          if capture_curr^.capture_store_ptr <= 1024 then
  211.             capture_curr^.capture_buffer[capture_curr^.capture_store_ptr] := ^Z
  212.          else
  213.             capture_curr^.capture_store_ptr := 1024;
  214.          if capture_curr^.capture_store_ptr > 1 then begin
  215.             r := (capture_curr^.capture_store_ptr / 128.0) + 0.999;
  216.             blockwrite(recv_file,capture_curr^.capture_buffer,trunc(r));
  217.          end;
  218.          capture_curr := capture_curr^.capture_next;
  219.       until capture_curr = nil;
  220.       close(recv_file);
  221.    end;
  222.  
  223. (****************************************************************************)
  224. (*                      ENTER / LEAVE  CAPTURE MODE                         *)
  225. (****************************************************************************)
  226.    procedure
  227.       toggle_capture_mode;
  228.    var
  229.       yes_no   : strtype;
  230.    begin
  231.       if capture_flag then begin
  232.          capture_flag := false;
  233.          mkwin(11,8,67,14,'Exit Capture Mode');
  234.          writeln;
  235.          write(' Do you wish to save capture buffer? ');
  236.          readln(yes_no);
  237.          if upcase(yes_no[1]) = 'Y' then
  238.             save_capture_buffers;
  239.          capture_curr := capture_first;
  240.          repeat
  241.             capture_first := capture_curr;
  242.             capture_curr := capture_curr^.capture_next;
  243.             dispose(capture_first);
  244.          until capture_curr = nil;
  245.          rmwin;
  246.          clear_pos(1,25);
  247.       end
  248.       else begin
  249.          capture_flag := true;
  250.          capture_warning := false;
  251.          escape_win;
  252.          gotoxy(1,25);
  253.          write('*');
  254.          reset_win;
  255.          new(capture_first);
  256.          capture_curr := capture_first;
  257.          capture_curr^.capture_store_ptr := 1;
  258.          capture_curr^.capture_next := nil;
  259.       end;
  260.    end;
  261.  
  262. (****************************************************************************)
  263. (*                          CAPTURE A CHARACTER                             *)
  264. (****************************************************************************)
  265.    procedure
  266.       capture( c : char );
  267.    begin
  268.       capture_curr^.capture_buffer[capture_curr^.capture_store_ptr] := c;
  269.       capture_curr^.capture_store_ptr := capture_curr^.capture_store_ptr + 1;
  270.       if capture_curr^.capture_store_ptr > 1024 then begin
  271.          if memory < 6 then
  272.             toggle_capture_mode
  273.          else begin
  274.             new(capture_curr^.capture_next);
  275.             capture_curr := capture_curr^.capture_next;
  276.             capture_curr^.capture_store_ptr := 1;
  277.             capture_curr^.capture_next := nil;
  278.             if (not capture_warning and (memory < 10)) then begin
  279.                capture_warning := true;
  280.                escape_win;
  281.                gotoxy(1,25);
  282.                write('W');
  283.                reset_win;
  284.             end;
  285.          end;
  286.       end;
  287.    end;
  288.  
  289. (****************************************************************************)
  290. (*                             PROCESS ESCAPE                               *)
  291. (****************************************************************************)
  292.    procedure
  293.       wrt( c : char );
  294.    begin
  295.       if c = FF then
  296.          clrscr
  297.       else
  298.          write( c );
  299.       if capture_flag then capture(c);
  300.    end;
  301.  
  302.    procedure
  303.       set_graphics;
  304.    var
  305.       i     : integer;
  306.       FG,BG : integer;
  307.    begin
  308.       FG := FGcolor;
  309.       BG := BGcolor;
  310.       for i:=1 to escape_number do begin
  311.          case escape_register[i] of
  312.             0 : lowvideo;
  313.             1 : normvideo;
  314.             5 : FG := FG + blink;
  315.             7 : begin
  316.                    FG := BG;
  317.                    BG := FG;
  318.                 end;
  319.            30 : FG := black;
  320.            31 : FG := red;
  321.            32 : FG := green;
  322.            33 : FG := yellow;
  323.            34 : FG := blue;
  324.            35 : FG := magenta;
  325.            36 : FG := cyan;
  326.            37 : FG := white;
  327.            40 : BG := black;
  328.            41 : BG := red;
  329.            42 : BG := green;
  330.            43 : BG := yellow;
  331.            44 : BG := blue;
  332.            45 : BG := magenta;
  333.            46 : BG := cyan;
  334.            47 : BG := white;
  335.          else
  336.             ;
  337.          end;
  338.       end;
  339.       textcolor( FG );
  340.       textbackground( BG );
  341.       escape_mode := false;
  342.    end;
  343.  
  344.    procedure
  345.       addr_cursor;
  346.    begin
  347.       case escape_number of
  348.          0 : begin
  349.                 escape_register[1]:=1;
  350.                 escape_register[2]:=1;
  351.              end;
  352.          1 : escape_register[2]:=1;
  353.       else
  354.          ;
  355.       end;
  356.       if escape_register[1]=25 then
  357.          gotoxy(escape_register[2],24)
  358.       else
  359.          gotoxy(escape_register[2],escape_register[1]);
  360.       escape_mode := false;
  361.    end;
  362.  
  363.    procedure
  364.       clear_scr;
  365.    begin
  366.       if ( escape_number = 1 )  and  ( escape_register[1] = 2 ) then
  367.          clrscr;
  368.       escape_mode := false;
  369.    end;
  370.  
  371.    procedure
  372.       clear_line;
  373.    begin
  374.       if ( escape_number = 1 )  and  ( escape_register[1] = 0 ) then
  375.          clreol;
  376.       escape_mode := false;
  377.    end;
  378.  
  379.    procedure
  380.       process_escape( c : char );
  381.    var
  382.       i    : integer;
  383.       ch   : char;
  384.    begin
  385.       case c of
  386.          ' ', '['
  387.              : exit;
  388.          'f','H'
  389.              : begin
  390.                   addr_cursor;
  391.                   exit;
  392.                end;
  393.          'J' : begin
  394.                   clear_scr;
  395.                   exit;
  396.                end;
  397.          'k' : begin
  398.                   clear_line;
  399.                   exit;
  400.                end;
  401.          'm' : begin
  402.                   set_graphics;
  403.                   exit;
  404.                end;
  405.       end;
  406.       ch := upcase( c );
  407.       escape_str := escape_str + ch;
  408.       if ch in [ 'A'..'G','L'..'P' ] then exit;
  409.       if ch in [ '0'..'9' ] then begin
  410.          escape_register[escape_number] := (escape_register[escape_number] * 10) + ord( ch ) - ord( '0' );
  411.          exit;
  412.       end;
  413.       case ch of
  414.          ';', ',' : begin
  415.                        escape_number := escape_number + 1;
  416.                        escape_register[escape_number] := 0;
  417.                     end;
  418.          'T', 'S', '#', '+', '-', '>', '<', '.'
  419.                   : ;
  420.       else
  421.          escape_mode := false;
  422.          for i:=1 to length( escape_str ) do
  423.             wrt( escape_str[i] );
  424.       end;
  425.    end;
  426.  
  427. (****************************************************************************)
  428. (*                             SCREEN HANDLER                               *)
  429. (****************************************************************************)
  430.    procedure
  431.       scrwrite( c : char );
  432.    var
  433.       i  : integer;
  434.    begin
  435.       if c = ESC then begin
  436.          if escape_mode then begin
  437.             for i:=1 to length( escape_str ) do
  438.                wrt( escape_str[i] );
  439.          end;
  440.          escape_str := '';
  441.          escape_number := 1;
  442.          escape_register[escape_number] := 0;
  443.          escape_mode := true;
  444.       end
  445.       else
  446.          if escape_mode then
  447.             process_escape(c)
  448.          else
  449.             wrt( c );
  450.    end;
  451.  
  452. (****************************************************************************)
  453. (*                       COMMUNICATIONS PROBLEMS !!!                        *)
  454. (****************************************************************************)
  455.    procedure
  456.       ask_operator(var ch : char);
  457.    var
  458.       yes_no   : string[4];
  459.    begin
  460.       mkwin(60,18,80,22,'');
  461.       error_count := 0;
  462.       writeln;
  463.       write(' Continue? y/n ');
  464.       readln(yes_no);
  465.       if upcase(yes_no[1]) = 'Y' then
  466.          ch := NAK
  467.       else begin
  468.          ch := CAN;
  469.          continue_transfer := false;
  470.       end;
  471.       rmwin;
  472.    end;
  473.  
  474. (****************************************************************************)
  475. (*                              SEND BLOCK                                  *)
  476. (****************************************************************************)
  477.    procedure
  478.       xmit_data(data_block : strtype);
  479.    var
  480.       i         : integer;
  481.    begin
  482.       i := 0;
  483.       while ( i < length(data_block) ) and continue_transfer do begin
  484.          i := i+1;
  485.          store_sout_buffer(data_block[i]);
  486.          if keypressed then begin
  487.             read(kbd,kbd_char);
  488.             ask_operator(kbd_char);
  489.          end;
  490.       end;
  491.       sin_read_ptr := sin_store_ptr;         { Flush the buffer. }
  492.    end;
  493.  
  494. (****************************************************************************)
  495. (*                             RECEIVE BLOCK                                *)
  496. (****************************************************************************)
  497.    procedure
  498.       recv_data(var data_block : strtype; char_cnt : integer);
  499.    var
  500.       cnt      : integer;
  501.       time     : integer;
  502.       max_loop : byte;
  503.    begin
  504.       data_block := '';
  505.       cnt := 0;
  506.       time := wait_increment;
  507.       max_loop := 40;
  508.       repeat
  509.          if cnt > 0 then
  510.             delay(time);
  511.          if sin_store_ptr <> sin_read_ptr then begin
  512.             data_block := data_block + read_sin_buffer;
  513.             cnt := 0;
  514.             time := sync_time;
  515.             max_loop := 5;
  516.          end
  517.          else
  518.             cnt := cnt + 1;
  519.          if keypressed then begin
  520.             read(kbd,kbd_char);
  521.             ask_operator(kbd_char);
  522.          end;
  523.       until ( cnt > max_loop )
  524.          or ( char_cnt = length(data_block) )
  525.          or ( not continue_transfer );
  526.    end;
  527.  
  528. (****************************************************************************)
  529. (*                             SYNC WITH REMOTE                             *)
  530. (****************************************************************************)
  531.    procedure
  532.       sync_with_remote;
  533.    begin
  534.       sout_read_ptr := sout_store_ptr;
  535.       delay(sync_time);
  536.       while sin_read_ptr <> sin_store_ptr do begin
  537.          sin_read_ptr := sin_store_ptr;
  538.          delay(sync_time);
  539.          delay(sync_time);
  540.       end;
  541.    end;
  542.    procedure
  543.       sync_NAK;
  544.    var
  545.       i   : integer;
  546.    begin
  547.       for i:=1 to 20 do sync_with_remote;
  548.    end;
  549.  
  550. (****************************************************************************)
  551. (*                       PROCESS XMODEM INPUT BUFFER                        *)
  552. (****************************************************************************)
  553.    procedure
  554.       process_xmodem_buffer(var xbuf : strtype; var resp : char);
  555.    label
  556.       SEND_NAK;
  557.    var
  558.       i      : integer;
  559.       chk    : integer;
  560.       xcnt   : integer;
  561.    begin
  562.       if length(xbuf) <> 132 then
  563.          goto SEND_NAK;
  564.       if xbuf[1] <> SOH then
  565.          goto SEND_NAK;
  566.       if (ord(xbuf[2]) <> ( ord(xbuf[3]) xor $FF) ) then
  567.          goto SEND_NAK;
  568.       if lo(block_count) = ord(xbuf[2]) then begin
  569.          resp := ACK;
  570.          exit;
  571.       end;
  572.       if lo(block_count + 1) <> ord(xbuf[2]) then
  573.          goto SEND_NAK;
  574.       chk := 0;
  575.       xcnt := xmodem_buf_cnt + 1;
  576.       for i:=4 to 131 do begin
  577.          chk := chk + ord(xbuf[i]);
  578.          xmodem_table[xcnt,i-3] := xbuf[i];
  579.       end;
  580.       if lo(chk) <> ord(xbuf[132]) then
  581.          goto SEND_NAK;
  582.       block_count := block_count + 1;
  583.       xmodem_buf_cnt := xmodem_buf_cnt + 1;
  584.       if xmodem_buf_cnt = max_xmodem_buffers then begin
  585.          blockwrite(recv_file,xmodem_table,max_xmodem_buffers);
  586.          xmodem_buf_cnt := 0;
  587.       end;
  588.       resp := ACK;
  589.       exit;
  590.    SEND_NAK:
  591.       error_count := error_count + 1;
  592.       if error_count > 30 then
  593.          ask_operator(resp)
  594.       else
  595.          resp := NAK;
  596.       sync_NAK;
  597.    end;
  598.  
  599. (****************************************************************************)
  600. (*                             RECEIVE FILE                                 *)
  601. (****************************************************************************)
  602.    procedure
  603.       receive_file;
  604.    var
  605.       buf          : strtype;
  606.       response     : char;
  607.    begin
  608.       xmodem_buf_cnt := 0;
  609.       error_count := 0;
  610.       block_count := 0;
  611.       continue_transfer := true;
  612.       mkwin(15,4,62,12,'Download XMODEM');
  613.       write(' Enter Filename to Receive: ');
  614.       readln(filename);
  615.       if length(filename)=0 then begin
  616.          rmwin;
  617.          exit;
  618.       end;
  619.       setserial(baud,stopbits,8,paritytype(0));
  620.       assign(recv_file,filename);
  621.       rewrite(recv_file);
  622.       writeln;
  623.       writeln('        Block Count     Error Count');
  624.       writeln('        -----------     -----------');
  625.       writeln;
  626.       sync_with_remote;
  627.       store_sout_buffer( NAK );        { NAK the sender to start things off. }
  628.       recv_data(buf,132);              { Get the 1st block from sender.      }
  629.       while ( buf <> CAN )
  630.         and ( buf <> EOT )
  631.         and ( continue_transfer )
  632.       do begin
  633.          process_xmodem_buffer(buf,response);
  634.          if continue_transfer then begin
  635.             gotoxy(12,5);
  636.             writeln(block_count:4,'              ',error_count:2);
  637.             sync_with_remote;
  638.             store_sout_buffer( response );
  639.             recv_data(buf,132);
  640.          end;
  641.       end;
  642.       sync_with_remote;
  643.       if not continue_transfer then begin
  644.          store_sout_buffer( CAN );
  645.          buf := CAN;
  646.       end;
  647.       if xmodem_buf_cnt > 0 then
  648.          blockwrite(recv_file,xmodem_table,xmodem_buf_cnt);
  649.       close(recv_file);
  650.       setserial(baud,stopbits,databits,paritytype(par));
  651.       if buf = CAN then
  652.          writeln(' File transfer canceled!')
  653.       else begin
  654.          store_sout_buffer( ACK );
  655.          writeln(' File transfer complete.');
  656.       end;
  657.       wait_for_key;
  658.       rmwin;
  659.    end;
  660.  
  661. (****************************************************************************)
  662. (*                            ALLOCATE BUFFERS                              *)
  663. (****************************************************************************)
  664.    procedure
  665.       get_buffer( var final : boolean );
  666.    begin
  667.       if xmodem_buf_cnt = 0 then begin
  668.          xmodem_rd := 1;
  669.          while ( xmodem_buf_cnt < max_xmodem_buffers ) and ( xmodem_rd <> 0 )
  670.          do begin
  671.             xmodem_buf_cnt := xmodem_buf_cnt + 1;
  672.             blockread(xmit_file,xmodem_table[xmodem_buf_cnt],1,xmodem_rd);
  673.          end;
  674.          xmodem_ptr := 0;
  675.       end;
  676.       xmodem_ptr := xmodem_ptr + 1;
  677.       xmodem_buf_cnt := xmodem_buf_cnt - 1;
  678.       if ( xmodem_buf_cnt = 0 ) and ( xmodem_rd = 0 ) then
  679.          final := true
  680.       else
  681.          final := false;
  682.    end;
  683.  
  684. (****************************************************************************)
  685. (*                    FORMAT XMODEM OUTPUT BUFFER                           *)
  686. (****************************************************************************)
  687.    procedure
  688.       build_xmodem_buffer(var xbuf : strtype; var last_block : boolean);
  689.    var
  690.       i       : integer;
  691.       chk     : integer;
  692.       ch      : char;
  693.    begin
  694.       get_buffer( last_block );
  695.       xbuf := SOH + chr(lo(block_count)) + chr(lo(block_count) xor $FF);
  696.       chk := 0;
  697.       for i:=1 to 128 do begin
  698.          ch := xmodem_table[xmodem_ptr,i];
  699.          xbuf := xbuf + ch;
  700.          chk := chk + ord( ch );
  701.       end;
  702.       xbuf := xbuf + chr(lo(chk));
  703.    end;
  704.  
  705. (****************************************************************************)
  706. (*                        GET REMOTE RESPONSE                               *)
  707. (****************************************************************************)
  708.    procedure
  709.       get_response(var resp : char);
  710.    var
  711.       cnt          : integer;
  712.       answer_back  : strtype;
  713.    begin
  714.       cnt := 0;
  715.       repeat
  716.          recv_data(answer_back,1);
  717.          cnt := cnt + 1;
  718.       until ( cnt = 3 ) or ( answer_back <> '' );
  719.       if ( answer_back[1] = CAN ) or ( answer_back = '' ) then begin
  720.          continue_transfer := false;
  721.          resp := CAN;
  722.       end
  723.       else
  724.          resp := answer_back[1];
  725.    end;
  726.  
  727. (****************************************************************************)
  728. (*                            TRANSMIT FILE                                 *)
  729. (****************************************************************************)
  730.    procedure
  731.       transmit_file;
  732.    var
  733.       buf          : strtype;
  734.       response     : char;
  735.       cnt          : integer;
  736.       last_block   : boolean;
  737.    begin
  738.       error_count := 0;
  739.       mkwin(15,4,62,13,'Upload XMODEM');
  740.       repeat
  741.          write(' Enter Filename to Transmit: ');
  742.          readln(filename);
  743.          if length(filename)=0 then begin
  744.             rmwin;
  745.             exit;
  746.          end;
  747.          assign(xmit_file,filename);
  748.          {$I-}
  749.          reset(xmit_file);
  750.          {$I+}
  751.          ok := (ioresult = 0);
  752.          if not ok then
  753.             writeln(' Cannot find file: ',filename);
  754.       until ok;
  755.       setserial(baud,stopbits,8,paritytype(0));
  756.       writeln(' Files Size is ',filesize(xmit_file)+1,' Blocks.');
  757.       xmodem_buf_cnt := 0;
  758.       block_count := 1;
  759.       build_xmodem_buffer(buf,last_block);
  760.       continue_transfer := true;
  761.       xmit_data('Holding for start of transfer...'+CRLF);
  762.       writeln(' Waiting for start... ');
  763.       writeln;
  764.       get_response(response);
  765.       if response <> CAN then begin
  766.          sync_with_remote;
  767.          xmit_data(buf);
  768.          get_response(response);
  769.          gotoxy(1,3);
  770.          writeln('                                   ');
  771.          writeln('        Block Count     Error Count');
  772.          writeln('        -----------     -----------');
  773.          gotoxy(12,6);
  774.          writeln(block_count:4,'              ',error_count:2);
  775.       end;
  776.       while ( response <> EOT )
  777.         and ( response <> CAN )
  778.         and ( continue_transfer )
  779.       do begin
  780.          sync_with_remote;
  781.          case response of
  782.             NAK : begin
  783.                      error_count := error_count + 1;
  784.                      if error_count > 30 then
  785.                         ask_operator(response);
  786.                      sync_NAK;
  787.                      if continue_transfer then begin
  788.                         xmit_data(buf);
  789.                         get_response(response);
  790.                      end;
  791.                   end;
  792.             ACK : begin
  793.                      if last_block then
  794.                         response := EOT
  795.                      else begin
  796.                         block_count := block_count + 1;
  797.                         build_xmodem_buffer(buf,last_block);
  798.                         xmit_data(buf);
  799.                         get_response(response);
  800.                      end;
  801.                   end;
  802.          else
  803.             response := NAK;
  804.             error_count := error_count + 1;
  805.          end;
  806.          gotoxy(12,6);
  807.          writeln(block_count:4,'              ',error_count:2);
  808.       end;
  809.       sync_with_remote;
  810.       if not continue_transfer then begin
  811.          store_sout_buffer( CAN );
  812.          response := CAN;
  813.       end
  814.       else begin
  815.          cnt := 0;
  816.          repeat
  817.             store_sout_buffer( EOT );
  818.             get_response(response);
  819.             cnt := cnt + 1;
  820.          until ( response = ACK ) or ( response = CAN ) or ( cnt = 5 );
  821.       end;
  822.       close(xmit_file);
  823.       setserial(baud,stopbits,databits,paritytype(par));
  824.       if response = CAN then
  825.          writeln(' File transfer canceled!')
  826.       else
  827.          writeln(' File transmission complete.');
  828.       wait_for_key;
  829.       rmwin;
  830.    end;
  831.  
  832. (****************************************************************************)
  833. (*                                H E L P                                   *)
  834. (****************************************************************************)
  835.    procedure
  836.       give_help;
  837.    begin
  838.       mkwin(28,1,72,24,'Command List');
  839.       writeln(' Use with the ALT key:');
  840.       writeln;
  841.       writeln('    A = Transmit using ASCII XON/XOFF.');
  842.       writeln('    L = Display the disk directory.');
  843.       writeln('    N = New directory and/or drive.');
  844.       writeln('    V = View a file.   K = Kill a file.');
  845.       writeln('    M = Macro keys, define and modify.');
  846.       writeln('    C = Toggle capture mode ON/OFF.');
  847.       writeln('    S = Change communication parameters.');
  848.       writeln('    D = Modem and dialing management.');
  849.       writeln('    O = Order the dialing directory.');
  850.       writeln('    G = Redial the last number.');
  851.       writeln('    E = Toggle between FULL/HALF duplex.');
  852.       writeln('    Q = Hang up, put modem "ON HOOK".');
  853.       writeln('    W = Wipe the screen, clear it');
  854.       writeln('    X = Terminate and Return to DOS');
  855.       writeln('  F10 = Command List');
  856.       writeln('Pg-Dn = Download a File in XMODEM');
  857.       writeln('Pg-Up = Upload a File in XMODEM');
  858.       writeln;
  859.       wait_for_key;
  860.       rmwin;
  861.    end;
  862.