home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / ZSYS / ZNODE-12 / I / LMODEM.C < prev    next >
Text File  |  2000-06-30  |  19KB  |  661 lines

  1. /*
  2.  
  3.    LMODEM.C -- Little MODEM program 
  4.                                       
  5.    Byte, Nov. 1983, pages 410-28                       
  6.                                                                              
  7.    This program implements the Ward Christensen assembly-language           
  8.    program in C.  It is derived from the cmodem13.c program                 
  9.    by Jack M. Wierda and Roderick W. Hart.  The modes available have         
  10.    been greatly reduced.  The program provides terminal emulation           
  11.    and text capture as well as file send and receive capabilities.          
  12.                                                                              
  13.    Hardware-dependent functions have been isolated from the                 
  14.    majority of the program.                                                 
  15.                                                                              
  16.    Written by David D. Clark                                                
  17.    9-Jan-83                                                                 
  18.   
  19.    Adapted to the KayPro II and Software Toolworks' (C/80 V. 3.0) 
  20.    C compiler by Lee R. Bradley
  21.  
  22.    To compile and assemble with AS.COM, use the following:
  23.                                                     
  24.    A>C -C2500 -D800 B:LMODEM.ASM=LMODEM.C
  25.    A>AS B:LMODEM.COM=B:LMODEM.ASM                     
  26.  
  27.    Incorporated dynamic allocation of buffer space.  Used ideas in Clark's 
  28.    version 2. 
  29.  
  30.    To compile, assemble and link with M80 and L80, use the following commands 
  31.  
  32.    A>C -C2500 -D800 -M1 B:LMODEM.MAC=LMODEM.C
  33.    A>M80 B:LMODEM.REL=B:LMODEM.MAC             
  34.    A>L80 B:LMODEM,STDLIB,CLIBRARY,B:LMODEM/N/E
  35.  
  36. */
  37.  
  38. #include "printf.h"
  39. #include "printf.c"
  40. #include "scanf.h"
  41. #include "scanf.c"
  42.  
  43. #define    DOTS            50        /* sector counting dots per line */
  44. #define    SPS             12000     /* loops per second  */
  45. #define    SECSIZ          0x80
  46. #define    DATAMASK        0x7f
  47. #define    BUFSECS         128       /* number of file sectors to buffer */
  48. #define    BLKSIZ          16384     /* size of blocks written (1 extent) */
  49. #define    ERRORMAX        10        /* maximum errors before abort */
  50. #define    RETRYMAX        5         /* maximum retrys before abort */
  51. #define    DIRCTIO         6         /* cpm bdos direct-console io command */
  52. #define    INPUT           0xff      /* direct-console io input */
  53. #define    FALSE           0
  54. #define    TRUE            1         /* lrb */
  55. #define    NULL            0         /* lrb */
  56.  
  57. /***************************************************************************/
  58. /*                                                                         */
  59. /*   Special characters used in the file transfer-protocol.                */
  60. /*                                                                         */
  61. /***************************************************************************/
  62.  
  63. #define      TIMEOUT  -1   /* timeout character  */
  64. #define      SOH      1    /* start of sector character */
  65. #define      EOT      4    /* end of transmission character  */
  66. #define      ACK      6    /* acknowledge sector transmission */
  67. #define      NAK      21   /* error in transmission detected */
  68.  
  69. /****************************************************************************/
  70. /*                                                                          */
  71. /*   Miscellaneous ASCII characters                                         */
  72. /*                                                                          */
  73. /****************************************************************************/
  74.  
  75. #define    TAB             9
  76. #define    LF             10
  77. #define    CR             13
  78. #define    CTRLZ          26  /* end of text-file character */
  79.  
  80. /****************************************************************************/
  81. /*                                                                          */
  82. /*    These #defines determine which keys will be interpreted as            */
  83. /*    command characters.                                                   */
  84. /*                                                                          */
  85. /****************************************************************************/
  86.  
  87. #define      CTRLB   2
  88. #define      CTRLE   5
  89. #define      CTRLK   11
  90. #define      CTRLL   12
  91. #define      CTRLQ   17
  92. #define      CTRLR   18
  93. #define      CTRLS   19
  94. #define      CTRLT   20
  95. #define      CTRLV   22
  96.  
  97. #define      SETBAUD   CTRLB   /* set baudrate */
  98. #define      CAPTURE   CTRLT   /* toggle text capture */
  99. #define      HELP      CTRLE   /* get instructions */
  100. #define      KEEP      CTRLK   /* keep text buffer  */
  101. #define      LITERAL   CTRLL   /* send literal character */
  102. #define      QUIT      CTRLQ   /* quit */
  103. #define      RECEIVE   CTRLR   /* receive file by sectors  */
  104. #define      SEND      CTRLS   /* send file by sectors */
  105. #define      VIEW      CTRLV   /* view data transfered  */
  106.  
  107. char ViewMode, BFlag, KbData, ModData;
  108. char AsciiFlg, ShowTrans, ShowRec, View;
  109. char *Bufr;
  110. char FileName[14];
  111. int Fd;
  112. unsigned BufSiz,BufPtr;
  113.  
  114. char *baudrate;
  115. extern char Cmode;
  116.  
  117. main(argc, argv)
  118. int argc;
  119. char **argv;
  120. {
  121.  
  122.    Cmode = 0;
  123.    AsciiFlg = ShowRecv = ShowTrans = BFlag = View = FALSE;
  124.    BufPtr = 0;
  125.    BufSiz=0x7f80;                     /*  make sure this isn't too big !! */
  126.    ViewMode = KbData = NULL;
  127.    if ((Bufr = alloc(BufSiz)) == 0) {
  128.       printf("Can't allocate the buffer\n");
  129.       exit();
  130.       }
  131.  
  132.    instruct();
  133.    initializemodem();
  134.  
  135.    while (ctsready() && (KbData != QUIT)) {
  136.       if (KbData = bdos(DIRCTIO, INPUT)) /* get any char at kbd */
  137.          switch (KbData) {
  138.  
  139.          case SETBAUD:
  140.             printf("\nEnter 1 for 300, 2 for 1200 or 3 for 2400 baud.\n");
  141.             switch (getchar())
  142.                { case '1': baud(5); baudrate = "300"; break; 
  143.                  case '2': baud(7); baudrate = "1200"; break; 
  144.                  case '3': baud(10); baudrate = "2400"; 
  145.                }
  146.             printf("\nBaud rate set at %s bps.\n", baudrate);
  147.             break;
  148.  
  149.          case HELP:
  150.             instruct();
  151.             break;
  152.  
  153.          case CAPTURE:
  154.             BFlag = ~BFlag;
  155.             if (BFlag)
  156.                printf("Capture initiated");
  157.             else
  158.                printf("Capture terminated");
  159.             printf(", %u", BufSiz - BufPtr);
  160.             printf(" bytes free\n");
  161.             break;
  162.  
  163.          case KEEP:
  164.             if (!BufPtr)
  165.                printf("Nothing to save\n");
  166.             else {
  167.                printf("Save as what file? ");
  168.                scanf("%s", FileName);
  169.                Bufr[BufPtr] = CTRLZ;
  170.                Fd = fopen(FileName,"w");
  171.                if (Fd == NULL)
  172.                  printf("Cannot create %s\n",
  173.                      FileName);
  174.                else {
  175.                   write(Fd, Bufr,
  176.                      (BufPtr/SECSIZ+1)*SECSIZ);
  177.                   fclose(Fd);
  178.                   BFlag = FALSE;
  179.                   BufPtr = 0;
  180.                }
  181.             }
  182.             break;
  183.  
  184.          case RECEIVE:
  185.             printf("Receive what file? ");
  186.             scanf("%s", FileName);
  187.             readfile(FileName);
  188.             break;
  189.  
  190.          case SEND:
  191.             printf("Send what file? ");
  192.             scanf("%s", FileName);
  193.             sendfile(FileName);
  194.             break;
  195.  
  196.          case QUIT:
  197.             hangup();
  198.             break;
  199.  
  200.          case VIEW:
  201.             View = ~View;
  202.             if (View) {
  203.                printf("View as Ascii or Hex? ");
  204.                ViewMode = toupper(getchar());
  205.                printf("\nDisplay will be in ");
  206.                if (ViewMode == 'A')
  207.                     printf("Ascii\n");
  208.                else
  209.                   printf("Hex\n");
  210.             }
  211.             else
  212.                printf("Viewing disabled\n");
  213.             break;
  214.  
  215.          case LITERAL:
  216.             while ( !(KbData = bdos(DIRCTIO, INPUT)) );
  217.                   mcharout(KbData);
  218.                   break;
  219.  
  220.          default:
  221.             mcharout(KbData);
  222.             break;
  223.          }
  224.  
  225.       if (minprdy()) {
  226.          ModData = mcharinp();
  227.          if (BFlag && (BufPtr < BufSiz))
  228.             Bufr[BufPtr++] = ModData;
  229.          else if   (BFlag)
  230.             printf("Capture Bufr overflow\n");
  231.          putchar(ModData);
  232.       }
  233.    }
  234. }   
  235.  
  236. instruct()
  237. {
  238.    printf("\n\nLMODEM.C, 5/21/86");
  239.    printf("\nDavid D. Clark, Byte, Nov. '83, pages 410-428");
  240.    printf("\n");
  241.    printf("\nAdapted to C/80 \n");
  242.    printf("Lee R. Bradley, Mouse House Software\n");
  243.    printf("\n");
  244.    printf("LMODEM.C is a small remote communication program.\n");
  245.    printf("When started it acts simply as a dumb terminal. \n");
  246.    printf("The following commands are available:\n\n");
  247.  
  248.    printf("Press RETURN to continue\n");
  249.    getchar();
  250.  
  251.    show_char(SETBAUD);
  252.    printf("\t- Set baudrate.  \n");
  253.  
  254.    show_char(CAPTURE);
  255.    printf("\t- Toggles text capture.  Initially inactive.  When\n");
  256.    printf("\t  acting as a terminal, all text received will be\n");
  257.    printf("\t  saved in a buffer.  The buffer may be saved on disk\n");
  258.    printf("\t  with the 'keep' command below.\n");
  259.  
  260.    show_char(HELP);
  261.    printf("\t- Help on the commands.  In case you forget what\n");
  262.    printf("\t  you are reading right now, type ctrl-E and you will\n");
  263.    printf("\t  be told what commands do what.\n");
  264.  
  265.    show_char(KEEP);
  266.    printf("\t- Keep.  Lets you save captured text in a diskfile. \n");
  267.    printf("\t  You will be asked to name the file in which the text\n");
  268.    printf("\t  will be saved.  The text buffer will be cleared if the\n");
  269.    printf("\t  text is saved successfully.\n");
  270.  
  271.    show_char(RECEIVE);
  272.    printf("\t- Receive file in Ward Christensen protocol.  You will\n");
  273.    printf("\t  be asked for the name of the file to write into.\n");
  274.  
  275.    show_char(SEND);
  276.    printf("\t- Send file in Ward Christensen protocol.\n");
  277.  
  278.    show_char(VIEW);
  279.    printf("\t- Toggle data viewing.  Initially inactive.  Data \n");
  280.    printf("\t  transmitted will be displayed in Ascii or Hex.\n");
  281.  
  282.    show_char(LITERAL);
  283.    printf("\t- Send literal character.  A character typed after this\n");
  284.    printf("\t  character will be sent as is.  In this way, characters\n");
  285.    printf("\t  that represent commands may be sent without being\n");
  286.    printf("\t  interpreted as a command.\n");
  287.  
  288.    show_char(QUIT);
  289.    printf("\t- Quit.  Exit program.\n\n");
  290.  
  291.    return;
  292.  
  293. }
  294. show_char(c)
  295. char c;
  296. {
  297.    if ((c>= 0) && (c<= 31))
  298.       printf("ctrl-%c", c + '@');
  299.    else if (c == ' ')
  300.       printf("<spc>");
  301.    else if ((c >='@') && (c <= '~'))
  302.       putchar(c);
  303.    else if (c == 127)
  304.       printf("<del>");
  305.    else
  306.       printf("%xH", c);
  307.    return;
  308. }
  309.  
  310. readfile(file)
  311. char *file;
  312. {
  313.    int firstchar, sectnum, sectcurr, sectcomp, errors;
  314.    int checksum;
  315.    int errorflag;
  316.    unsigned j, bufptr;
  317.  
  318.    if (View) {
  319.       ShowRecv = TRUE;
  320.       ShowTrans = FALSE;
  321.    }
  322.  
  323.    Fd = fopen(file,"w");
  324.    if (Fd == 0) {
  325.       printf("Cannot create %s\n", file);
  326.       return;
  327.    }
  328.    else
  329.       printf("Receiving %s\n\n", file);
  330.    sectnum = errors = bufptr = 0;
  331.    initializemodem();
  332.    sendchar(NAK);
  333.    do {
  334.       errorflag = FALSE;
  335.       do {                /* get synchronization character */
  336.          firstchar = readchar(5);
  337.       } while (    firstchar != SOH
  338.                 && firstchar != EOT
  339.                 && firstchar != TIMEOUT);
  340.       if (firstchar == TIMEOUT) {
  341.          errorflag = TRUE;
  342.          printf("Timeout error\n");
  343.       }
  344.       if (firstchar == SOH) {        /* main if */
  345.          sectcurr = readchar(1);
  346.          sectcomp = readchar(1);
  347.          if ((sectcurr + sectcomp) == -1) {
  348.             if ((sectcurr & 0xff) == (sectnum + 1 & 0xff)) { /* lrb */
  349.                checksum = 0;
  350.                if (ViewMode == 'A')
  351.                   AsciiFlg = TRUE;
  352.                for (j = bufptr; j < (bufptr + SECSIZ); j++) {
  353.                     Bufr[j] = readchar(1);
  354.                     checksum = (checksum + Bufr[j]) & 0xff;
  355.                }
  356.                AsciiFlg = FALSE;
  357.                if ((checksum & 0xff) == (readchar(1) & 0xff)) {    /* lrb */
  358.                   errors = 0;
  359.                   sectnum++;
  360.                   bufptr += SECSIZ;
  361.                   if ((sectnum % BUFSECS) == 0) {
  362.                      bufptr = 0;
  363.                      if (write(Fd, Bufr, BLKSIZ) == NULL) {
  364.                         printf("Error writing file\n");
  365.                         fclose(Fd);
  366.                         return;
  367.                      }
  368.                      do ; 
  369.                      while (readchar(1) != TIMEOUT);
  370.                   }
  371.                   if (!ShowRecv)
  372.                      if (((sectnum - 1 ) % DOTS) ==0)
  373.                         printf("\n<%4d>.", sectnum);
  374.                      else
  375.                         printf(".");
  376.                   sendchar(ACK);
  377.                }
  378.                else {
  379.                   printf("\nChecksum error, expected ");
  380.                   printf("<%0x>\n", checksum);
  381.                   errorflag = TRUE;
  382.                }    /*  This is a comment  */
  383.            }   
  384.            else 
  385.               if ((sectcurr & 0xff) == (sectnum & 0xff)) {  /* lrb */ 
  386.                  printf("\nReceived duplicate sector %d\n", sectnum);
  387.                  /* wait for silence on the line */
  388.                  do ;  /* nothing */
  389.                  while (readchar(1) != TIMEOUT);
  390.                  sendchar(ACK);
  391.               }
  392.               else {
  393.                  printf("\nSynchronization error\n");
  394.                  errorflag = TRUE;
  395.               }
  396.           }
  397.           else {
  398.              printf("\nSector number error\n");
  399.              errorflag = TRUE;
  400.           }
  401.       }  /* end of main if.   This right brace was missing from Byte */ 
  402.  
  403.       if (errorflag == TRUE) {
  404.          errors++;
  405.          printf("Error %d\n", errors);
  406.          while (readchar(1) != TIMEOUT);
  407.          sendchar(NAK);
  408.       }
  409.  
  410.    }  while (firstchar != EOT && errors != ERRORMAX);
  411.     
  412.    if ((firstchar == EOT) && (errors < ERRORMAX)) {
  413.       sendchar(ACK);
  414.       write(Fd, Bufr, bufptr);
  415.       fclose(Fd);
  416.       printf("\n\nTransfer complete\n");
  417.    }
  418.    else
  419.       printf("\n\nAborting\n");
  420. }
  421.  
  422.  
  423. readchar (seconds)
  424. unsigned seconds;
  425. {
  426.    char data;
  427.    seconds = seconds*SPS;
  428.    while (!minprdy() && seconds)  /* wait until input ready */
  429.       --seconds;
  430.    if (!seconds)
  431.       return(TIMEOUT);            /* nothing arrived in time */
  432.    data = mcharinp();             /* get it */
  433.    if (ShowRecv) {                /* show if needed */
  434.       if (AsciiFlg)
  435.          if (((data >= ' ') && (data <= DATAMASK))
  436.              || data == LF || data == CR || data == TAB)
  437.             putchar(data);
  438.          else
  439.             printf("[%0x]", data);
  440.       else
  441.          printf("[%0x]", data);
  442.    }
  443.    return data;
  444. }
  445.  
  446. sendfile(file)
  447. char *file;
  448. {
  449.    int sectnum, sectors, attempts;
  450.    int checksum;
  451.    unsigned j, bufptr;
  452.  
  453.    if (View) {
  454.       ShowRecv = FALSE;
  455.       ShowTrans = TRUE;
  456.    }
  457.    Fd = fopen(file, "r");
  458.    if (Fd == NULL) {
  459.       printf("Cannot open %s\n", file);
  460.       return;
  461.    }
  462.    else
  463.       printf("Sending %s\n\n", file);
  464.    initializemodem();
  465.    attempts = 0;
  466.    sectnum = 1;
  467.  
  468.    while ((sectors = read(Fd, Bufr, BufSiz)) && (attempts != RETRYMAX)) {
  469.       if (sectors == NULL) {
  470.          printf("\nError reading file\n");
  471.          fclose(Fd);
  472.          return;
  473.       }
  474.       else {
  475.          sectors = sectors / SECSIZ + 1;
  476.          bufptr = 0;
  477.          do {
  478.             attempts = 0;
  479.             do {
  480.                if (!ShowTrans)
  481.                   if (((sectnum - 1) % DOTS) == 0)
  482.                      printf("\n<%4d>.", sectnum);
  483.                   else
  484.                      printf(".");
  485.                sendchar(SOH);
  486.                sendchar(sectnum);
  487.                sendchar(~sectnum);
  488.                checksum = 0;
  489.                if (ViewMode = 'A')
  490.                   AsciiFlg = TRUE;
  491.                for (j= bufptr; j < (bufptr + SECSIZ); j++) {
  492.                   sendchar(Bufr[j]);
  493.                   checksum = (checksum + Bufr[j]) & 0xff;
  494.                }
  495.                AsciiFlg = FALSE;
  496.                sendchar(checksum);
  497.                purgeline();
  498.                attempts++;
  499.             } while ((readchar(10) != ACK) && 
  500.                       (attempts != RETRYMAX));
  501.             bufptr += SECSIZ;
  502.             sectnum++;
  503.             sectors--;
  504.          } while (sectors && (attempts != RETRYMAX));
  505.       }
  506.    }
  507.  
  508.    if (attempts == RETRYMAX)
  509.       printf("\nNo acknowledgement of sector, aborting\n");
  510.    else {
  511.       attempts = 0;
  512.       do {
  513.          sendchar(EOT);
  514.          purgeline();
  515.          attempts++;
  516.       } while ((readchar(10) != ACK) && (attempts != RETRYMAX));
  517.       if (attempts == RETRYMAX) {
  518.          printf("\nNo acknowledgement of end of file");
  519.          printf(", aborting\n");
  520.       }
  521.       else 
  522.          printf("\nTransfer complete\n");
  523.    }
  524.    fclose(Fd);
  525.    return;
  526. }
  527.  
  528. sendchar(data)
  529. char data;
  530. {
  531.    while (!moutrdy());           /* wait until output ready */
  532.    
  533.    mcharout(data);               /* send it */
  534.  
  535.    if (ShowTrans) {              /* show it, if needed */
  536.       if (AsciiFlg)
  537.          if (((data >= ' ') && (data <= DATAMASK))
  538.              || data == LF || data == CR || data == TAB)
  539.             putchar(data);
  540.          else
  541.             printf("[%0x]", data);
  542.       else
  543.          printf("[%0x]", data);
  544.    }
  545.    return;
  546. }
  547.  
  548. /* Hardware dependent code */
  549.  
  550. #define     BAUDRATE    0
  551. #define     DATAPORT    4
  552. #define     STATUSPORT  6
  553. #define     DAV   1
  554. #define     TBE   4
  555.  
  556. initializemodem()
  557. {
  558.    purgeline();               /* minimal code */
  559. }
  560.  
  561. purgeline()
  562. {
  563.    while (minprdy())           /* while there are characters ... */
  564.       mcharinp();                   /* gobble them */
  565. }
  566.  
  567. mcharinp()
  568. {
  569.    char c;
  570.  
  571.    while (!minprdy());   /* do nothing until ready */
  572.    c = rx();             /* get data  */
  573.    return c;
  574. }
  575.  
  576. mcharout(c)
  577. char c;
  578. {
  579.    while (!moutrdy());    /* do nothing until ready */
  580.    tx(c);                 /* put data */
  581. }
  582.  
  583. int rx()
  584. {
  585. #asm
  586.    IN  DATAPORT           ; get data from port
  587.    MVI  H,0
  588.    MOV  L,A   
  589. #endasm
  590. }
  591.    
  592. minprdy()
  593. {                         /* returns 0 or 1 if (un)ready */
  594. #asm
  595.    IN  STATUSPORT
  596.    ANI  DAV
  597.    MVI  H,0
  598.    MOV  L,A    
  599.    RZ
  600.    MVI  L,1 
  601. #endasm
  602. }
  603.  
  604. moutrdy()
  605. {                         /* returns 0 of 1 if (un)ready */
  606. #asm
  607.    IN  STATUSPORT
  608.    ANI  TBE
  609.    MVI  H,0
  610.    MOV  L,A
  611.    RZ
  612.    MVI  L,1
  613. #endasm
  614. }
  615.  
  616. int tx(c)
  617. char c;
  618. {
  619. #asm
  620.    POP  H
  621.    POP  D
  622.    PUSH  D
  623.    PUSH  H
  624.    MOV   A,E
  625.    OUT   DATAPORT
  626. #endasm
  627. }
  628.  
  629. int baud(c)
  630. char c;
  631. {
  632. #asm
  633.    POP  H
  634.    POP  D
  635.    PUSH  D
  636.    PUSH  H
  637.    MOV   A,E
  638.    OUT   BAUDRATE
  639. #endasm
  640. }
  641. ctsready()
  642. {
  643.    return TRUE;
  644. }
  645.  
  646. hangup()
  647. {
  648.    return TRUE;           /* nothing to do */
  649. }
  650.  
  651. #include "stdlib.c"
  652. 
  653. }
  654. ctsready()
  655. {
  656.    return TRUE;
  657. }
  658.  
  659. hangup()
  660. {
  661.    return TRUE;           /* noth