home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / SYSPC22.ZIP / PROTOCOL.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1987-12-25  |  16.8 KB  |  696 lines

  1. (***********************
  2.  
  3. {$C-}{$I-}
  4. type anystr=string[255];
  5.      lstr=string[80];
  6.      mstr=string[30];
  7.      sstr=string[15];
  8.      regs=record
  9.        case byte of
  10.          0:(ax,bx,cx,dx,bp,si,di,ds,es,flags:integer);
  11.          1:(al,ah,bl,bh,cl,ch,dl,dh:byte)
  12.      end;
  13. {$IModem.pas}
  14. var logontime,iocode:integer;
  15. const timer=0; timeleft=1; numminsxfer=1;
  16. function keyhit:boolean;
  17. begin
  18.   keyhit:=keypressed
  19. end;
  20. function bioskey:char;
  21. var k:char;
  22. begin
  23.   read (kbd,k);
  24.   bioskey:=k
  25. end;
  26. function hungupon:boolean;
  27. begin
  28.   hungupon:=not carrier
  29. end;
  30. function strr (n:integer):mstr;
  31. var q:mstr;
  32. begin
  33.   str (n,q);
  34.   strr:=q
  35. end;
  36. function minstr (blocks:integer):mstr;
  37. begin
  38.   minstr:='<'+strr(blocks)+' blocks left>'
  39. end;
  40. procedure fileerror (s1,s2:lstr);
  41. begin
  42.   writeln ('File error ',s1,' and ',s2);
  43.   halt
  44. end;
  45. procedure starttimer (q:integer); begin end;
  46. procedure stoptimer (q:integer); begin end;
  47. procedure settimeleft (q:integer); begin end;
  48. procedure splitscreen (y:integer);
  49. begin
  50.   window (1,1,80,y-1)
  51. end;
  52. procedure top; begin end;
  53. procedure unsplit;
  54. begin
  55.   window (1,1,80,25)
  56. end;
  57.  
  58.  
  59. **************)
  60.  
  61.  
  62.  
  63. overlay function protocolxfer (send,crcmode,ymodem:boolean; fn:lstr):integer;
  64. { Return codes:  0=OK, 1=Cancelled within last three blocks, 2=Aborted }
  65.  
  66.   const can=^X; ack=^F; nak=^U; soh=^A; stx=^B; eot=^D; crcstart='C';
  67.  
  68.   var timedout:boolean;
  69.  
  70.   function tenthseconds:integer;
  71.   var r:regs;
  72.   begin
  73.     r.ah:=$2c;
  74.     intr ($21,r);
  75.     tenthseconds:=(r.dh*10)+(r.dl div 10)
  76.   end;
  77.  
  78.   function fromnow (tenths:integer):integer;
  79.   begin
  80.     tenths:=tenthseconds+tenths;
  81.     if tenths>599 then tenths:=tenths-600;
  82.     fromnow:=tenths
  83.   end;
  84.  
  85.   function timeout (en:integer):boolean;
  86.   begin
  87.     timeout:=(en=tenthseconds) or hungupon
  88.   end;
  89.  
  90.   procedure clearmodemahead;
  91.   var k:char;
  92.   begin
  93.     while numchars>0 do k:=getchar
  94.   end;
  95.  
  96.   procedure wait (tenths:integer);
  97.   begin
  98.     tenths:=fromnow (tenths);
  99.     repeat until timeout (tenths) or hungupon
  100.   end;
  101.  
  102.   function waitchar (tenths:integer):char;
  103.   begin
  104.     waitchar:=#0;
  105.     tenths:=fromnow (tenths);
  106.     repeat
  107.       if numchars>0 then begin
  108.         waitchar:=getchar;
  109.         timedout:=false;
  110.         exit
  111.       end
  112.     until timeout (tenths) or hungupon;
  113.     timedout:=true
  114.   end;
  115.  
  116.   procedure computecrc (var block; blocksize:integer; var outcrc:integer);
  117.   var crc:integer;
  118.   begin
  119.     inline (
  120.              $1E/                    {           PUSH  DS               }
  121.              $C5/$B6/block/          {           LDS   SI,[BP+block]    }
  122.              $8B/$96/blocksize/      {           MOV   DX,[BP+blocksize]}
  123.              $31/$DB/                {           XOR   BX,BX            }
  124.              $FC/                    {           CLD                    }
  125.              $AC/                    { Mainloop: LODSB                  }
  126.              $B9/$08/$00/            {           MOV   CX,0008          }
  127.              $D0/$E0/                { Byteloop: SHL   AL,1             }
  128.              $D1/$D3/                {           RCL   BX,1             }
  129.              $73/$04/                {           JNC   No_xor           }
  130.              $81/$F3/$21/$10/        {           XOR   BX,1021          }
  131.              $E2/$F4/                { No_xor:   LOOP  Byteloop         }
  132.              $4A/                    {           DEC   DX               }
  133.              $75/$ED/                {           JNZ   Mainloop         }
  134.              $89/$9E/crc/            {           MOV   [BP+crc],BX      }
  135.              $1F                     {           POP   DS               }
  136.            );
  137.     outcrc:=crc
  138.   end;
  139.  
  140.   procedure computecksum (var data; blocksize:integer; var outcksum:byte);
  141.   var t:array [1..1024] of byte absolute data;
  142.       cnt,q:integer;
  143.   begin
  144.     q:=0;
  145.     for cnt:=1 to blocksize do q:=q+t[cnt];
  146.     outcksum:=q and 255
  147.   end;
  148.  
  149.   procedure showerrorstats (curblk,totalerrs,consec:integer);
  150.   var x:integer;
  151.       r:real;
  152.   begin
  153.     x:=wherex;
  154.     write (usr,totalerrs);
  155.     gotoxy (x,wherey+1);
  156.     write (usr,consec,' ');
  157.     gotoxy (x,wherey+1);
  158.     if curblk+totalerrs<>0 then begin
  159.       r:=round(10000.0*totalerrs/(curblk+totalerrs))/100.0;
  160.       write (usr,r:0:2,'%    ')
  161.     end
  162.   end;
  163.  
  164.   overlay function xymodemsend (ymodem:boolean):integer;
  165.   var f:file;
  166.       b:array [1..1026] of byte;
  167.       blocksize:integer;
  168.       fsize,curblk,totalerrs,consec,blocksatatime:integer;
  169.       k:char;
  170.       firstblock:boolean;
  171.       totaltime:sstr;
  172.  
  173.     function getctrlchar:char;   { Gets ACK/NAK/CAN }
  174.     var k,k2:char;
  175.         cnt:integer;
  176.     begin
  177.       getctrlchar:=can;
  178.       repeat
  179.         cnt:=0;
  180.         repeat
  181.           k:=waitchar (10);
  182.           cnt:=cnt+1;
  183.           if keyhit then begin
  184.             k2:=bioskey;
  185.             if k2=^X then exit;
  186.             timedout:=true
  187.           end
  188.         until (not timedout) or (cnt=60);
  189.         if timedout or hungupon then exit;
  190.         if (k in [ack,nak,crcstart,can]) then begin
  191.           getctrlchar:=k;
  192.           if k=can then sendchar (can);
  193.           exit
  194.         end
  195.       until hungupon;
  196.       timedout:=true
  197.     end;
  198.  
  199.     procedure sendendoffile;
  200.     var k:char;
  201.         tries:integer;
  202.     begin
  203.       tries:=0;
  204.       repeat
  205.         tries:=tries+1;
  206.         sendchar(eot);
  207.         k:=waitchar (20);
  208.       until (k=ack) or (k=can) or (tries=3);
  209.       sendchar(eot)
  210.     end;
  211.  
  212.     procedure getblockfromfile;
  213.     begin
  214.       fillchar (b,sizeof(b),26);
  215.       blockread (f,b,blocksatatime);
  216.       blocksize:=blocksatatime shl 7
  217.     end;
  218.  
  219.     procedure buildfirstblock;
  220.     var cnt,p:integer;
  221.     begin
  222.       blocksize:=128;
  223.       fillchar(b,128,0);
  224.       p:=length(fn);
  225.       repeat
  226.         p:=p-1
  227.       until (p=0) or (fn[p]='\');
  228.       for cnt:=1 to length(fn)-p do b[cnt]:=ord(fn[cnt+p])
  229.     end;
  230.  
  231.     procedure sendblock (num:integer);
  232.     var cnt,crc,bksize:integer;
  233.         n:byte;
  234.         k:char;
  235.     begin
  236.       clearmodemahead;
  237.       n:=num and 255;
  238.       if blocksize=1024
  239.         then k:=stx
  240.         else k:=soh;
  241.       if crcmode
  242.         then
  243.           begin
  244.             b[blocksize+1]:=0;
  245.             b[blocksize+2]:=0;
  246.             computecrc (b,blocksize+2,crc);
  247.             b[blocksize+1]:=hi(crc);
  248.             b[blocksize+2]:=lo(crc);
  249.             bksize:=blocksize+2;
  250.           end
  251.         else
  252.           begin
  253.             b[blocksize+1]:=0;
  254.             computecksum (b,blocksize,b[blocksize+1]);
  255.             bksize:=blocksize+1
  256.           end;
  257.       sendchar (k);
  258.       sendchar (chr(n));
  259.       sendchar (chr(255-n));
  260.       for cnt:=1 to bksize do sendchar(chr(b[cnt]))
  261.     end;
  262.  
  263.     procedure updatestatus;
  264.     begin
  265.       gotoxy (16,3);
  266.       write (usr,curblk,' of ',fsize);
  267.       gotoxy (16,4);
  268.       write (usr,minstr((fsize-curblk)*blocksatatime),' of ',totaltime,' ');
  269.       gotoxy (16,5);
  270.       showerrorstats (curblk,totalerrs,consec)
  271.     end;
  272.  
  273.     procedure initxfer;
  274.     begin
  275.       starttimer (numminsxfer);
  276.       if ymodem then blocksatatime:=8 else blocksatatime:=1;
  277.       fsize:=(filesize(f)+blocksatatime-1) div blocksatatime;
  278.       totaltime:=minstr(fsize*blocksatatime);
  279.       totalerrs:=0;
  280.       consec:=0;
  281.       firstblock:=true;
  282.       if ymodem
  283.         then
  284.           begin
  285.             curblk:=0;
  286.             buildfirstblock
  287.           end
  288.         else
  289.           begin
  290.             curblk:=1;
  291.             getblockfromfile
  292.           end;
  293.       splitscreen (8);
  294.       top;
  295.       write (usr,'Waiting for NAK')
  296.     end;
  297.  
  298.     procedure setupscreen;
  299.     begin
  300.       gotoxy (1,1);
  301.       if ymodem then write (usr,'Y') else write (usr,'X');
  302.       write (usr,'MODEM');
  303.       if crcmode then write (usr,'-CRC');
  304.       writeln (usr,' send in progress.  Press Ctrl-X to abort.');
  305.       clreol;
  306.       gotoxy (1,3);
  307.       writeln (usr,'Current block:');
  308.       writeln (usr,'Time left:');
  309.       writeln (usr,'Total errors:');
  310.       writeln (usr,'  Consecutive:');
  311.       write (usr,'Error rate:')
  312.     end;
  313.  
  314.   label abort,done;
  315.   begin
  316.     xymodemsend:=2;
  317.     assign (f,fn);
  318.     reset (f);
  319.     iocode:=ioresult;
  320.     if iocode<>0 then exit;
  321.     initxfer;
  322.     repeat
  323.       k:=getctrlchar;
  324.       if k=can then begin
  325.         if (fsize-curblk<2) and (curblk>2) then xymodemsend:=1; { Cheater! }
  326.         goto abort
  327.       end;
  328.       if firstblock then begin
  329.         if (k=nak) or (k=crcstart) then firstblock:=false;
  330.         crcmode:=k=crcstart;
  331.         setupscreen;
  332.         k:=#0
  333.       end;
  334.       if k=ack then begin
  335.         curblk:=curblk+1;
  336.         if eof(f) then goto done;
  337.         getblockfromfile
  338.       end;
  339.       if k<>nak then consec:=0 else begin
  340.         totalerrs:=totalerrs+1;
  341.         consec:=consec+1
  342.       end;
  343.       sendblock(curblk);
  344.       updatestatus
  345.     until 0=1;
  346.     done:
  347.     sendendoffile;
  348.     xymodemsend:=0;
  349.     abort:
  350.     close (f);
  351.     unsplit;
  352.     stoptimer (numminsxfer)
  353.   end;
  354.  
  355.   overlay function xymodemreceive(ymodem:boolean):integer;
  356.   var f:file;
  357.       block:array [1..1026] of byte;
  358.       blkl,blkh,xblkl,nblkl,nblk1:byte;
  359.       curblk:integer;
  360.       ctrl,k,k2:char;
  361.       timeul,consec,totalerrs,blocksize:integer;
  362.       canceled,timeout:boolean;
  363.  
  364.     procedure cancel;
  365.     begin
  366.       wait (10);
  367.       clearmodemahead;
  368.       sendchar (can);
  369.       wait (10);
  370.       clearmodemahead;
  371.       sendchar (can);
  372.       canceled:=true
  373.     end;
  374.  
  375.     function writeblock:boolean;
  376.     var wb:boolean;
  377.     begin
  378.       blockwrite (f,block,blocksize div 128);
  379.       wb:=ioresult=0;
  380.       writeblock:=wb;
  381.       if not wb then begin
  382.         gotoxy (1,1);
  383.         write (usr,'I/O ERROR ',iocode,' WRITING BLOCK');
  384.         clreol;
  385.         sendchar (can);
  386.         wait (10);
  387.         sendchar (can);
  388.         clearmodemahead
  389.       end
  390.     end;
  391.  
  392.     procedure updatestatus;
  393.     begin
  394.       curblk:=blkl+(blkh shl 8);
  395.       gotoxy (16,3);
  396.       write (usr,curblk);
  397.       gotoxy (16,4);
  398.       showerrorstats (curblk,totalerrs,consec)
  399.     end;
  400.  
  401.     function sendctrl:char;
  402.     var cnt,consec:integer;
  403.         k:char;
  404.     begin
  405.       cnt:=0;
  406.       consec:=0;
  407.       timeout:=false;
  408.       updatestatus;
  409.       sendctrl:=can;
  410.       repeat
  411.         if keyhit then begin
  412.           k:=bioskey;
  413.           if k=^X then begin
  414.             timeout:=true;
  415.             cancel;
  416.             exit
  417.           end
  418.         end;
  419.         sendctrl:=waitchar (50);
  420.         if not timedout then exit;
  421.         sendchar (ctrl);
  422.         cnt:=0;
  423.         consec:=consec+1
  424.       until (consec=10) or hungupon;
  425.       timeout:=true
  426.     end;
  427.  
  428.     function getachar:char;
  429.     var cnt:integer;
  430.         k:char;
  431.     begin
  432.       getachar:=#0;
  433.       timeout:=timeout or hungupon;
  434.       if timeout then exit;
  435.       timeout:=false;
  436.       if keyhit then begin
  437.         k:=bioskey;
  438.         if k=^X then begin
  439.           getachar:=#0;
  440.           timeout:=true;
  441.           cancel;
  442.           exit
  443.         end
  444.       end;
  445.       getachar:=waitchar (10);
  446.       timeout:=timeout or timedout
  447.     end;
  448.  
  449.     procedure xfererror (txt:lstr);
  450.     begin
  451.       gotoxy (16,7);
  452.       write (usr,txt,' in block ',curblk);
  453.       clreol
  454.     end;
  455.  
  456.     procedure initxfer;
  457.     var k:char;
  458.     begin
  459.       timeul:=timer;
  460.       timeout:=false;
  461.       consec:=0;
  462.       blkl:=1;
  463.       blkh:=0;
  464.       xblkl:=1;
  465.       curblk:=1;
  466.       totalerrs:=0;
  467.       if crcmode
  468.         then ctrl:=crcstart
  469.         else ctrl:=nak;
  470.       canceled:=false;
  471.       starttimer (numminsxfer);
  472.       splitscreen (8);
  473.       top;
  474.       gotoxy (1,1);
  475.       if ymodem then write (usr,'Y') else write (usr,'X');
  476.       write (usr,'MODEM');
  477.       if crcmode then write (usr,'-CRC');
  478.       write (usr,' receive in progress.  Press Ctrl-X to abort.'^M^J^J,
  479.              'Current block:'^M^J,
  480.              'Total errors:'^M^J,
  481.              '  Consecutive:'^M^J,
  482.              'Error rate:'^M^J,
  483.              'Error type:');
  484.       while numchars>0 do k:=getchar
  485.     end;
  486.  
  487.     procedure endoffile;
  488.     begin
  489.       xymodemreceive:=0;
  490.       sendchar (ack);
  491.       wait (10);
  492.       sendchar (ack);
  493.       clearmodemahead
  494.     end;
  495.  
  496.     function block0:boolean;
  497.     var b0:boolean;
  498.         cnt:integer;
  499.     begin
  500.       b0:=(nblkl=0) and (nblk1=255) and (blkh=0) and (blkl<>255);
  501.       if b0 then begin
  502.         xfererror ('(Receiving block 0...)');
  503.         for cnt:=1 to blocksize do block[cnt]:=ord(getachar);
  504.         ctrl:=ack;
  505.         sendchar (ack)
  506.       end;
  507.       block0:=b0
  508.     end;
  509.  
  510.     function blocknumerror:boolean;
  511.     var bne:boolean;
  512.     begin
  513.       bne:=(nblkl<>(255-nblk1)) or ((nblkl<>xblkl) and (nblkl<>blkl));
  514.       if bne then xfererror ('Block # '+strr(nblkl)+' not '+strr(255-nblk1)+
  515.                              ' and '+strr(xblkl)+' or '+strr(blkl));
  516.       blocknumerror:=bne
  517.     end;
  518.  
  519.     function resentnoreason:boolean;
  520.     var rnr:boolean;
  521.         cnt:integer;
  522.     begin
  523.       rnr:=(nblkl<>xblkl) and (nblkl=blkl);
  524.       if rnr then begin
  525.         xfererror ('Block resent for no reason');
  526.         for cnt:=1 to blocksize do block[cnt]:=ord(getachar);
  527.         ctrl:=ack;
  528.         sendchar (ack)
  529.       end;
  530.       resentnoreason:=rnr
  531.     end;
  532.  
  533.     procedure getblockfrommodem;
  534.     var cnt:integer;
  535.     begin
  536.       for cnt:=1 to blocksize do begin
  537.         block[cnt]:=ord(getachar);
  538.         if timeout then exit
  539.       end
  540.     end;
  541.  
  542.     function badblock:boolean;
  543.     var crc:integer;
  544.         cksum:byte;
  545.     begin
  546.       badblock:=false;
  547.       if crcmode
  548.         then
  549.           begin
  550.             computecrc(block,blocksize,crc);
  551.             if crc<>0 then begin
  552.               xfererror ('CRC error');
  553.               badblock:=true
  554.             end
  555.           end
  556.         else
  557.           begin
  558.             computecksum(block,blocksize,cksum);
  559.             if cksum<>block[129] then begin
  560.               xfererror ('Checksum error');
  561.               badblock:=true
  562.             end
  563.           end
  564.     end;
  565.  
  566.   label nakit,abort,done;
  567.   begin
  568.     xymodemreceive:=2;
  569.     assign (f,fn);
  570.     rewrite (f);
  571.     iocode:=ioresult;
  572.     if iocode<>0 then begin
  573.       fileerror ('XYMODEMRECEIVE',fn);
  574.       exit
  575.     end;
  576.     initxfer;
  577.     repeat
  578.       k:=sendctrl;
  579.       ctrl:=nak;
  580.       if timeout or (k=can) then goto abort;
  581.       if k=eot then begin
  582.         endoffile;
  583.         goto done
  584.       end;
  585.       case k of
  586.         soh:blocksize:=128;
  587.         stx:blocksize:=1024
  588.         else begin
  589.           xfererror ('SOH error: '+strr(ord(k)));
  590.           goto nakit
  591.         end
  592.       end;
  593.       if crcmode
  594.         then blocksize:=blocksize+2
  595.         else blocksize:=blocksize+1;
  596.       nblkl:=ord(getachar);
  597.       nblk1:=ord(getachar);
  598.       if timeout then goto nakit;
  599.       if block0 then goto nakit;
  600.       if blocknumerror then goto nakit;
  601.       if resentnoreason then goto nakit;
  602.       if (nblkl=0) and (blkl=255) then blkh:=blkh+1;
  603.       blkl:=nblkl;
  604.       getblockfrommodem;
  605.       if timeout then goto nakit;
  606.       if badblock then goto nakit;
  607.       ctrl:=ack;
  608.       xblkl:=blkl+1;
  609.       sendchar (ack);
  610.       updatestatus;
  611.       if not writeblock then goto abort;
  612.       consec:=0;
  613.       nakit:
  614.       if hungupon then goto abort;
  615.       if timeout then xfererror ('Time out (short block)');
  616.       if ctrl<>ack then begin
  617.         totalerrs:=totalerrs+1;
  618.         consec:=consec+1;
  619.         repeat
  620.           k:=waitchar (10)
  621.         until timedout;
  622.         if consec>=15 then begin
  623.           sendchar (can);
  624.           goto abort
  625.         end;
  626.         sendchar (ctrl)
  627.       end
  628.     until 0=1;
  629.     abort:
  630.     cancel;
  631.     done:
  632.     close (f); consec:=ioresult;
  633.     if canceled then begin
  634.       erase (f); consec:=ioresult
  635.     end;
  636.     timeul:=timer-timeul;
  637.     if timeul<0 then timeul:=timeul+1440;
  638.     settimeleft (timeleft+timeul*2);
  639.     unsplit;
  640.     stoptimer (numminsxfer)
  641.   end;
  642.  
  643. begin
  644.   if send
  645.     then protocolxfer:=xymodemsend(ymodem)
  646.     else protocolxfer:=xymodemreceive(ymodem)
  647. end;
  648.  
  649.  
  650.  
  651.  
  652. (************
  653.  
  654.  
  655.  
  656.  
  657.  
  658.  
  659. procedure termmode;
  660. var k:char;
  661. begin
  662.   clrscr;
  663.   writeln ('Termmode- ^D when done, or ^A to abort.');
  664.   setparam (1,1200,false);
  665.   repeat
  666.     if keyhit then begin
  667.       k:=bioskey;
  668.       if k=^A then halt else if k=^D then exit else sendchar (k)
  669.     end;
  670.     while numchars>0 do write (getchar)
  671.   until 0=1
  672. end;
  673. var k:char;
  674.     fn:lstr;
  675.     b:integer;
  676.     snd,crcm,ymd:boolean;
  677. begin
  678.   termmode;
  679.   write ('Filename: ');
  680.   readln (fn);
  681.   if length(fn)=0 then halt;
  682.   write ('S=Send: ');    k:=bioskey;  snd:=upcase(k)='S'; if k=^C then halt;
  683.   write ('C=Crc: ');     k:=bioskey; crcm:=upcase(k)='C'; if k=^C then halt;
  684.   write ('Y=Ymodem: ');  k:=bioskey;  ymd:=upcase(k)='Y'; if k=^C then halt;
  685.   writeln;
  686.   writeln;
  687.   clrscr;
  688.   b:=protocolxfer (snd,crcm,ymd,fn);
  689.   gotoxy (1,24);
  690.   writeln ('Returned: ',b)
  691. end.
  692.  
  693.  
  694. ************)
  695.  
  696.