home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / modems / modem2 / rt11modm.c < prev    next >
C/C++ Source or Header  |  1985-07-20  |  8KB  |  353 lines

  1. #include <stdio.h>
  2.  
  3. /*
  4.  * rtmodem.c -- This program allows the RT-11 user to transfer files to
  5.  * and from a host system (usually CP/M) using Ward Christensen's
  6.  * MODEM/XMODEM protocol.  No terminal emulation is provided (yet).
  7.  * Written in DECUS C by:
  8.  *
  9.  * Robert B. Hoffman, N3CVL    5-Mar-82
  10.  * <Hoffman%Pitt.csnet@CSNet-Relay.ARPA>
  11.  * {allegra, bellcore, cadre, idis, psuvax1}!pitt!hoffman
  12.  *
  13.  * 5-Mar-82    Original Version
  14.  *
  15.  * 18-Mar-83    Changed transmit routine to wait for one of (ACK,NAK,CAN,
  16.  *        or TIMEOUT) before re-sending the sector.  Garbage chars are
  17.  *        now ignored.  Changed receive routine to print a count of
  18.  *        bytes transferred.
  19.  *
  20.  * 26-Aug-83    Changed transmit routine to print a count of bytes
  21.  *        transferred.  Changed receive routine to cancel transfer if
  22.  *        the allocated file size is exceeded. *** Note:  This is
  23.  *        bogus -- putc() isn't returning any error condition. (see below)
  24.  *
  25.  * 9-Dec-83    Changed receive routine to send NAKs only after it times
  26.  *        out waiting for a SOH, rather than NAKing every non-SOH.
  27.  *
  28.  * 13-Feb-84    Changed buffer array from char to ints.  It seems that when
  29.  *        putc was called with a char with the eighth bit set, then
  30.  *        it was returning a negative int, which appeared as an error.
  31.  *        If putc is called with an int, it works just fine, and returns
  32.  *        the expected error condition not found above.  Also changed
  33.  *        command structure to make it quicker.  Now, when a transfer
  34.  *        completes, it returns to command mode rather than exiting.
  35.  *
  36.  * 19-Feb-84    Changed the 'bytes transmitted' message to indicate sectors,
  37.  *        blocks, and bytes.  Added bell chars to termination messages.
  38.  *
  39.  * 15-Aug-84    Fixed a bug that allowed nulls to be transmitted in text mode
  40.  *        and appended an extra sector's worth of nulls in binary mode.
  41.  *        Also changed command scanner to add Ethernet escape option
  42.  *        and to make it easier to add more options.  Added Ethernet
  43.  *        escapes to output driver.
  44.  */
  45.  
  46. struct device {
  47.     int rcsr;
  48.     int rbuf;
  49.     int xcsr;
  50.     int xbuf;
  51. };
  52.  
  53. #define SOH    01
  54. #define EOT    04
  55. #define ACK    06
  56. #define NAK    025
  57. #define CAN    030
  58. #define TIMEOUT    -1
  59. #define TRUE    1
  60. #define FALSE    0
  61. #define EVER    ;;
  62.  
  63. int $$narg = 1;
  64.  
  65. struct device *dladdr = 0176500;
  66.  
  67. int buf[128];
  68. int ether;
  69. FILE *file;
  70.  
  71. main() {
  72.     register int i, c;
  73.     register char *p;
  74.     char blkno, cblkno, *filnam, cmdlin[40];
  75.     int bcnt, cksm, ok, nakcount, sndrcv, txtbin;
  76.     long nbytes;
  77.  
  78.     printf("RTMODEM -- RT-11 file transfer program\n\n");
  79.  
  80. cmd:
  81.     do {
  82.         printf("RTMODEM command=> ");
  83.         gets(cmdlin);
  84.         for (i=0; i<strlen(cmdlin); i++)
  85.             cmdlin[i] = (isupper(cmdlin[i]) ? tolower(cmdlin[i]) : cmdlin[i]);
  86.         filnam = index(cmdlin,' ');
  87.         *filnam++ = 0;    /* this is sneaky -- it null-terminates the */
  88.                 /* command part of the string and makes */
  89.                 /* filnam point to the file name */
  90.  
  91.         ok = TRUE;        /* assume cmd will be OK */
  92.         p = index(cmdlin,'s');    /* sending */
  93.         if (p == NULL) {
  94.             p = index(cmdlin,'r');    /* receiving */
  95.         }
  96.         if (p == NULL) {
  97.             ok = FALSE;    /* one of these MUST be present */
  98.         }
  99.         sndrcv = *p;
  100.  
  101.         p = index(cmdlin,'t');    /* text */
  102.         if (p == NULL) {
  103.             p = index(cmdlin,'b');    /* binary */
  104.         }
  105.         if (p == NULL) {
  106.             ok = FALSE;    /* one of these must also be present */
  107.         }
  108.         txtbin = *p;
  109.  
  110.         if (index(cmdlin,'e') == NULL) {    /* ethernet mode */
  111.             ether = FALSE;
  112.         } else {
  113.             ether = TRUE;
  114.         }
  115.  
  116.         if (!ok) {
  117.             printf("\nCommands are of the form:\n");
  118.             printf("   rt|rb|st|sb [e]   filename\n");
  119.             printf("      rt -- receive text\n");
  120.             printf("      rb -- receive binary\n");
  121.             printf("      st -- send text\n");
  122.             printf("      sb -- send binary\n");
  123.             printf("      e  -- use Ethernet escape\n\n");
  124.         }
  125.     } while (!ok);
  126.  
  127.     freopen("tt:", "wu", stdout);
  128.     if (ether) {
  129.         printf("Using Ethernet character escape.\n");
  130.     }
  131.     if (sndrcv == 's') {
  132.         printf("Sending file %s, %s mode.\n", filnam,
  133.             (txtbin == 't' ? "text" : "binary"));
  134.         if ((file = fopen(filnam,"rn")) == NULL) {
  135.             fprintf(stderr,"Couldn't open input file %s.\n",
  136.                 filnam);
  137.             goto cmd;
  138.         }
  139.         printf("File open, ready to send.\n");
  140.         nbytes = 512L * (long)(file->io_size);
  141.         printf("File is %d sectors (%ld bytes) long.\n",
  142.             (file->io_size) * 4, nbytes);
  143.         nbytes /= 84L;    /* 120 cps * 70% = 84 cps effective */
  144.         printf("Estimated transfer time:  %ld min, %ld sec at 1200 bps.\n",
  145.                 nbytes/60L, nbytes%60L);
  146.  
  147.         while ((c = getmod()) != NAK)
  148.             ;
  149.  
  150.         nbytes = 0L;
  151.         blkno = 0;
  152.         do {
  153.             i = 0;
  154.             do {
  155.                 c = getc(file);
  156.                 if (c == EOF) {
  157.                     if (i == 0)
  158.                         goto sfin;
  159.                     if (txtbin == 't')
  160.                         buf[i++] = 032;
  161.                     else
  162.                         buf[i++] = 0;
  163.                 }
  164.                 else if (txtbin != 't' || c != 0) {
  165.                     buf[i++] = c;
  166.                 }
  167.             } while (i < 128);
  168.             blkno++;
  169.             do {
  170.                 outmod(SOH);
  171.                 outmod(blkno);
  172.                 outmod(~blkno);
  173.                 cksm = 0;
  174.                 for (bcnt = 0; bcnt < 128; bcnt++) {
  175.                     outmod(buf[bcnt]);
  176.                     cksm = (cksm + buf[bcnt]) % 256;
  177.                 }
  178.                 outmod(cksm);
  179.                 do {
  180.                     ok = TRUE;    /* Assume all OK */
  181.                     c = getmod();
  182.                     switch (c) {
  183.                     case ACK:
  184.                     case NAK:
  185.                     case CAN:
  186.                     case TIMEOUT:
  187.                         break;
  188.  
  189.                     default:
  190.                         ok = FALSE;
  191.                         break;
  192.                     }
  193.                 } while (!ok);
  194.             } while (c != ACK && c != CAN);
  195.     
  196.             nbytes += 128L;
  197.             printf("%ld sec, %ld blk, %ld b\r", nbytes/128L,
  198.                 (nbytes+384L)/512L, nbytes);
  199.  
  200.             if (c == CAN) {
  201.                 fclose(file);
  202.                 printf("\n\007\007\007Transfer cancelled by host.\n");
  203.                 goto cmd;
  204.             }
  205.     
  206.         } while (c == ACK && !feof(file));
  207.     
  208. sfin:
  209.         outmod(EOT);
  210.         c = getmod();
  211.         if (c == ACK)
  212.             printf("\n\007\007\007File transmitted\n");
  213.         else
  214.             printf("\n\007\007\007Final ACK was 0%o instead!\n",c);
  215.     
  216.         fclose(file);
  217.         goto cmd;
  218.     }
  219.     else {
  220.         printf("Receiving file %s, %s mode.\n", filnam,
  221.             (txtbin == 't' ? "text" : "binary"));
  222.         if ((file = fopen(filnam,"wn")) == NULL) {
  223.             fprintf(stderr,"Couldn't open output file %s\n",
  224.                 filnam);
  225.             goto cmd;
  226.         }
  227.         printf("File open, ready to receive.\n");
  228.  
  229.         nbytes = 0L;
  230.         outmod(NAK);    /* Send initial NAK */
  231.         nakcount = 0;
  232.         for (EVER) {
  233.             do {
  234.                 c = getmod();
  235.                 switch (c) {
  236.                 case TIMEOUT:
  237.                     outmod(NAK);
  238.                     nakcount++;
  239.                     break;
  240.  
  241.                 case EOT:
  242.                     goto rfin;
  243.  
  244.                 default:
  245.                     break;
  246.                 }
  247.             } while (c != SOH);
  248.  
  249.             blkno = getmod();
  250.             cblkno = getmod();
  251.             cksm = 0;
  252.             for (i=0; i<128; i++) {
  253.                 c = buf[i] = getmod();
  254.                 cksm = (cksm + c) % 256;
  255.             }
  256.             c = getmod();
  257.             ok = (((SOH+blkno+cblkno) % 256) == 0 && cksm == c);
  258.             if (ok) {
  259.                 for (i=0; i<128; i++) {
  260.                     if (buf[i] == '\032' && txtbin == 't')
  261.                         break;
  262.                     c = putc(buf[i],file);
  263.                     if (c == EOF) {
  264.                         outmod(CAN);
  265.                         fclose(file);
  266.                         printf("\n\07Disk full!  Transfer cancelled.\n");
  267.                         goto cmd;
  268.                     }
  269.                 }
  270.                 nbytes += 128L;
  271.                 printf("%ld sec, %ld blk, %ld b\r",
  272.                     nbytes/128L, (nbytes+384L)/512L,
  273.                     nbytes);
  274.                 outmod(ACK);
  275.                 nakcount = 0;
  276.             } else {
  277.                 if (nakcount > 10) {
  278.                     printf("\nR)etry or Q)uit=> ");
  279.                     gets(cmdlin);
  280.                     c = cmdlin[0];
  281.                     if (c == 'q' || c == 'Q') {
  282.                         outmod(CAN);
  283.                         fclose(file);
  284.                         goto cmd;
  285.                     }
  286.                     nakcount = 0;
  287.                 }
  288.                 nakcount++;
  289.                 printf("\nNAK %d\n", nakcount);
  290.                 outmod(NAK);
  291.             }
  292.         }
  293. rfin:
  294.         fclose(file);
  295.         outmod(ACK);
  296.         printf("\n\007\007\007Transfer complete\n");
  297.         goto cmd;
  298.     }
  299. }
  300.  
  301. /*
  302.  * get a character from the modem.   A 10 second timeout is
  303.  * needed to preclude hanging the modem if one side should
  304.  * terminate abnormally.  The constant of 160000 provides this
  305.  * delay for an LSI-11.
  306.  */
  307.  
  308. getmod() {
  309.     register struct device *MODEM;
  310.     long n;
  311.  
  312.     MODEM = dladdr;
  313.     for (n=160000L; ((MODEM->rcsr & 0200) == 0) && (n > 0L); n--)
  314.         ;
  315.     if (n == 0L) {
  316.         printf("\nTimeout!\n");
  317.         return(-1);
  318.     }
  319.     return((MODEM->rbuf) & 0377);
  320. }
  321.  
  322. /*
  323.  * Send a character to the modem.
  324.  */
  325.  
  326. outmod(c)
  327. char c;
  328. {
  329.     if (ether) {
  330.         switch(c) {
  331.         case 020:
  332.         case 021:
  333.         case 023:
  334.             outm(020);
  335.             break;
  336.         default:
  337.             break;
  338.         }
  339.     }
  340.     outm(c);
  341. }
  342.  
  343. outm(c)
  344. char c;
  345. {
  346.     register struct device *MODEM;
  347.  
  348.     MODEM = dladdr;
  349.     while ((MODEM->xcsr & 0200) == 0)
  350.         ;
  351.     MODEM->xbuf = c;
  352. }
  353.