home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 170_01 / zapload.c < prev    next >
Text File  |  1979-12-31  |  13KB  |  479 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3.  
  4.     /********************************************************
  5.     *                            *
  6.     *    ZAPLOAD -- Binary to Intel hex Conversion    *
  7.     *            Utility                *
  8.     *                            *
  9.     *        T. Jennings 26 Sept. 82            *
  10.     *                            *
  11.     *                            *
  12.     ********************************************************/
  13.  
  14. /*    A nearly universal utility for converting binary to Intel hex
  15.     outputting to one or more devices. See ZAPLOAD.DOC for details.
  16.  
  17.     A terminating record is sent following the last data record,
  18.     to indicate end of load and to pass the start address. 
  19.  
  20.     OPERATION: 
  21.  
  22.     ZAPLOAD <file> <options>
  23.  
  24.         where <file> is any legal filespec, and
  25.         <options> are one or more of the following options:
  26.  
  27.         -B <number> Generate records of <number> bytes per record.
  28.             This must be less than 1025.
  29.         -L <number> Set starting address(default 0000)
  30.         -W <number> Delay between character transmission, where
  31.             <number> is a variable. No fixed time scale.
  32.         -M <number> delay at end of line.
  33.         -R <number> Set the run address to <number>. Default 0000 hex.
  34.         -S <number> Skip <number> bytes at the beginning of the file,
  35.  
  36.         -A    transmit the file to the AUX device.
  37.         -F    Send the data to disk file <file>
  38.  
  39.         -Z    Generate 1's complement check sums.
  40.         -E    Do even bytes only,
  41.         -O    Do odd bytes only,
  42.         -X     Enable console output
  43.         -N    No EOF record generated.
  44.  
  45.     Each record is echoed on the console for verification. */
  46.  
  47. int    inbuf,outbuf,punch;
  48. char    infile[18];
  49. char    outfile[18];
  50. char    record[1024];        /* this is very big!!! */
  51.  
  52. int    sum_type;        /* 0 means 1's compl., 1 means 2's */
  53. int    disk_file;        /* true means send to the disk file */
  54. int     send_tuart;        /* true to send to TUART port C */
  55. int    send_pch;        /* true if sending to the punch, */
  56. int    dsk_err;        /* disk file error */
  57. unsigned load_address;        /* load address */
  58. unsigned start_address;        /* Starting address, */
  59. int    byte_count;        /* number of bytes to send, */
  60. int    delay;            /* software delay counter, */
  61. int    eol_delay;
  62. int    console;        /* true if echoing to the console */
  63. int    alt_byte;        /* true if doing alternate bytes, */
  64. int    lsb;            /* 1 if doing odd bytes, */
  65. int    doeof;            /* true if making an EOF record. */
  66. int    skip;            /* bytes to skip at start of file */
  67. int    byte_addr;        /* byte address in file, */
  68. unsigned datasum;        /* eyeball check checksum */
  69. int    eof;            /* true at end of file */
  70.  
  71. #define    CR    0x0d
  72. #define    LF    0x0a
  73. #define    ERROR    -1
  74. #define    TRUE    -1
  75. #define    FALSE    0
  76. #define    OK    0
  77. #define    NONE    0
  78. #define    MAX_BYTES 64    /* max # data bytes in a record */
  79. #define MIN_BYTES 8    /* minimum bytes, */
  80.  
  81. formfeed()
  82. {}
  83.  
  84. /* Start by verifying the command line; must have at least one
  85. argument, the file. Get any options, and if the guy screws up,
  86. announce the proper way to invoke the program. */
  87.  
  88. main(argc,argv)
  89. int    argc;
  90. char    **argv;
  91. {
  92.  
  93. char    *s;
  94. int    is_ok;
  95. char    arg;
  96.  
  97.     is_ok=FALSE;            /* set as bad cmd. line, */
  98.     send_tuart =FALSE;        /* send to LST: port, */
  99.     send_pch =FALSE;        /* send it to the punch, */
  100.     disk_file =FALSE;        /* no disk file, */
  101.     dsk_err =FALSE;            /* no error yet, */
  102.     doeof =TRUE;            /* Make EOF records, */
  103.     alt_byte =FALSE;        /* no alternate bytes, */
  104.     console =FALSE;            /* default to no echo */
  105.     eof =FALSE;            /* not end of file yet */
  106.     skip =0;            /* dont skip any bytes, */
  107.     sum_type =1;            /* two's complement checksum, */
  108.     load_address =0;        /* load address of 0000 */
  109.     start_address =0;        /* default start address */
  110.     byte_count =32;            /* default byte count */
  111.     delay=0;            /* no delay */
  112.     eol_delay=0;
  113.     byte_addr =0;            /* byte within the file, */
  114.  
  115.     printf("\nBinary to Intel Hex Conversion Utility");
  116.     printf("\n  Version 2.1a 26 Sept. 1982 by T. Jennings\n");
  117.  
  118.     if(argc >1) {    
  119.         is_ok= TRUE;
  120.         strcpy(infile,argv[1]);    /* save the filename, */
  121.         argc -=2;            /* two taken, */
  122.         argv +=2;            /* move both, */
  123.  
  124.         while(argc >0)            /* now do all the options */
  125.         {    arg= toupper(**argv);
  126.             switch(arg)
  127.             {
  128.  
  129. /* Skip leading dashes on the arguments */
  130.             case '-':
  131.                 ++*argv;    /* skip leading dashes */
  132.                 continue;
  133.                 break;
  134.  
  135. /* Change the default load address */
  136.             case 'L':
  137.                 if((--argc >0) && 
  138.                 (make_hex(*++argv,&load_address)!=NONE))
  139.                 {    printf("Load address: %x\n",load_address);
  140.                 }
  141.                 else
  142.                 {    printf("Bad hex number\n");
  143.                     is_ok =FALSE;
  144.                 }
  145.                 break;
  146.  
  147. /* Change the default run address */
  148.             case 'R':
  149.                 if((--argc >0) && 
  150.                 (make_hex(*++argv,&start_address)!=NONE))
  151.                 {    printf("Start address: %x\n",start_address);
  152.                 }
  153.                 else
  154.                 {    printf("Bad hex number\n");
  155.                     is_ok =FALSE;
  156.                 }
  157.                 break;
  158.  
  159. /* Change the default bytes per record */
  160.             case 'B':
  161.                 if((--argc >0) && 
  162.                 (make_dec(*++argv,&byte_count)!=NONE))
  163.                 {    printf("%d Byte records\n",byte_count);
  164.                     if(byte_count > 1024)
  165.                     {    is_ok=FALSE;
  166.                         printf("Byte count must be <1025\n");
  167.                     }
  168.                 }
  169.                 else
  170.                 {    printf("Bad decimal number\n");
  171.                     is_ok =FALSE;
  172.                 }
  173.                 break;
  174.  
  175.  
  176. /* Enable sending INTEL hex to the punch */
  177.             case 'A':
  178.                 send_pch =TRUE;
  179.                 printf("Output to AUX\n");
  180.                 punch= open("AUX",0x8001);
  181.                 break;
  182.  
  183. /* Set number of bytes to skip at the start of the file. */
  184.             case 'S':
  185.                 if((--argc >0) &&(make_dec(*++argv,&skip)!=NONE))
  186.                 {    printf("Skip %d bytes\n",skip);
  187.                 }
  188.                 else
  189.                 {    printf("Bad decimal number\n");
  190.                     is_ok =FALSE;
  191.                 }
  192.                 break;
  193.                 
  194. /* Open an output file */
  195.             case 'F':
  196.                 if(--argc)
  197.                 {    strcpy(outfile,*++argv);/* save the filename,*/
  198.                     printf("Sending output to %s\n",outfile);
  199.                     disk_file=TRUE;
  200.                 }
  201.                 else
  202.                 {    printf("Missing a filename\n");
  203.                 }
  204.                 break;
  205.  
  206. /* change the checksum type */
  207.             case 'Z':
  208.                 sum_type =0;
  209.                 printf("1's complement checksum\n");
  210.                 break;
  211.  
  212. /* Set a software delay between chars */
  213.             case 'W':
  214.                 if((--argc >0) && 
  215.                 (make_dec(*++argv,&delay)!=NONE))
  216.                 {    printf("Delay %d between characters\n",delay);
  217.                 }
  218.                 else
  219.                 {    printf("Bad decimal number\n");
  220.                     is_ok=FALSE;
  221.                 }
  222.                 break;
  223.  
  224. /* Set a software delay at the end of the line*/
  225.             case 'M':
  226.                 if((--argc >0) && 
  227.                 (make_dec(*++argv,&eol_delay)!=NONE))
  228.                 {    printf("Delay %d at end of record\n",eol_delay);
  229.                 }
  230.                 else
  231.                 {    printf("Bad decimal number\n");
  232.                     is_ok=FALSE;
  233.                 }
  234.                 break;
  235.  
  236. /* Do only the even bytes */
  237.             case 'E':
  238.                 lsb =0;    /* LSB address mask, */
  239.                 alt_byte =TRUE;
  240.                 printf("Doing only even bytes\n");
  241.                 break;
  242. /* Do the odd bytes */
  243.             case 'O':
  244.                 lsb =1;
  245.                 alt_byte =TRUE;
  246.                 printf("Doing only odd bytes\n");
  247.                 break;
  248. /* Dont generate an EOF record */
  249.             case 'N':
  250.                 doeof =FALSE;
  251.                 printf("Don't generate an EOF record\n");
  252.                 break;
  253.             case 'X':
  254.                 console =TRUE;
  255.                 printf("Output to the console\n");
  256.                 break;
  257. /* Gets here only on bad arguments */
  258.             default:
  259.                 printf("Bad option: %s\n",*argv);
  260.                 is_ok=FALSE;    /* none of the above!!! */
  261.                 break;
  262.             }
  263.  
  264.         --argc; ++argv;
  265.         }
  266.     }
  267. /* Now see what we got. Exit now on bad options, and try to open any files.
  268. Make sure theres at least one destination.  */
  269.  
  270.     if (is_ok) {
  271.         if ((inbuf= open(infile,0x8000)) ==ERROR) {
  272.             printf("\nCan't find %s",infile);
  273.             exit();
  274.         }
  275.         if (disk_file) {
  276.             if ((outbuf =creat(outfile,0x8001)) ==ERROR) {
  277.                 printf("\nCan't create %s",outfile);
  278.                 exit();
  279.             }
  280.         }
  281.         send_file();
  282.         if(disk_file) {
  283.             close(outbuf);
  284.         }
  285.         exit();
  286.     }
  287.     else {
  288.         printf("Try:  ZAPLOAD <file> <options>, where <options> is");
  289.         printf         (" one or more of the following:");
  290.         printf("\n\t L <xxxx> set load address,(default 0000)");
  291.         printf("\n\t R <xxxx> set start address,(default 0000)");
  292.         printf("\n\t B <dddd> record byte count, default 32,");
  293.         printf("\n\t S <dddd> skip <dddd> bytes before processing,");
  294.         printf("\n\t W <dddd> delay between characters,(0-65535)");
  295.         printf("\n\t M <dddd> delay at end of line(0-65535),");
  296.         printf("\n\t F <file> send hex to <file>,");
  297.         printf("\n\t A Send to the AUX device,");
  298.         printf("\n\t Z Make 1's complement checksums,");
  299.         printf("\n\t X Output to the console,");
  300.         printf("\n\t E Do only even addressed bytes,");
  301.         printf("\n\t O Do only odd addressed bytes,");
  302.         exit();
  303.     }
  304. }
  305.  
  306. /* Now the file(s) are open, and the options are set. Send the file, converting
  307. it to INTEL hex records. */
  308.  
  309. int    send_file()
  310. {
  311. int    total,this_record;
  312. char    dummy;
  313.  
  314.     while(skip--) {        /* skip any bytes in the file, */
  315.         eof =read(inbuf,&dummy,1);    /* as specified, */
  316.         eof =((eof == ERROR) || (eof == NULL));
  317.     }        
  318.     byte_addr =0;            /* start keeping track, */
  319.     datasum= 0;            /* zero the checksum, */
  320.     total =0;
  321.     while(!eof) {
  322.         this_record =make_record(byte_count); /* make data records, */
  323.         total +=this_record;    /* count bytes, */
  324.     }
  325.     printf("End of file\n");
  326.     if(this_record > 0) {        /* if last record non-empty, */
  327.         make_record(0);        /* then make an EOF record, */
  328.     }                /* else we already did, */
  329.     printf("Total byte count =%dd, data checksum =%xh\n",total,datasum);
  330.     sendc(0x1a);            /* send a control-Z, */
  331.     return;                /* then leave */
  332. }
  333. /* read bytes from the disk file, and make INTEL hex records. */
  334.  
  335. int    make_record(count)
  336. int    count;
  337. {
  338. int    i,j,b;
  339. int    checksum;
  340. int    check;
  341. char    c;
  342.  
  343. /* Write out an INTEL hex record. Pad it to the full length if the file
  344. empties out. If we are passed a count of 0, do only a EOF record. */
  345.  
  346.     checksum =0;                /* zero the checksum, */
  347.     for(i=0; i <count;  ) {
  348.         j= read(inbuf,&c,1);        /* read byte to C */
  349.         if((j ==ERROR) || (j == NONE)) {
  350.             eof =TRUE;
  351.             break;
  352.         }
  353.         check =byte_addr &1;        /* if alternate bytes, */
  354.         if(!alt_byte ||(alt_byte && (check ==lsb) )) { 
  355.             record[i] =c;        /* save each byte, */
  356.             checksum +=c;        /* sum up the data bytes, */
  357.             datasum +=c;        /* add data to the sum also. */
  358.             ++i;            /* Count another done, */
  359.         }
  360.         ++byte_addr;
  361.     }
  362.  
  363. /* Now we have an array of data bytes. If its not empty, send it out as a data
  364. record, else send as a terminating record. */
  365.  
  366.     if(i) {                    /* If data record ... */
  367.         sendc(':');                /* record start character, */
  368.         sendb(i);                /* send the byte count, */
  369.         checksum +=i;                /* update the checksum, */
  370.         sendw(load_address);
  371.         checksum +=((load_address>>8) &0xff);/* add the address to the */
  372.         checksum +=( load_address &0xff);    /* checksum, */
  373.         load_address += i;            /* update the address, */
  374.         sendb(0);                /* set record type =data, */
  375.         for(j=0,b=i; b>0; b--)            /*send all the data bytes, */
  376.             sendb(record[j++])
  377.         ;
  378.     }
  379.     else if(doeof) {                /*... its end of file */
  380.         sendc(':');                /* record start character, */
  381.         sendb(i);                /* send the byte count, */
  382.         checksum +=i;                /* update the checksum, */
  383.         sendw(start_address);
  384.         checksum +=((start_address>>8) &0xff);/* add the address to the */
  385.         checksum +=( start_address &0xff);    /* checksum, */
  386.         sendb(1);                /* record type =end, */
  387.     }
  388.  
  389. /* now make the correct checksum */
  390.  
  391.     if(i || doeof) {
  392.         checksum =( ~checksum);        /* ones complement, */
  393.         checksum += sum_type;            /* correct it, */
  394.         sendb(checksum);            /* send it, */
  395.         sendc(CR);                /* for a pretty screen, */
  396.         sendc(LF);
  397.     }
  398.     return(i);                    /* return number written, */
  399. }
  400.  
  401. /* Data transmission routines */
  402.  
  403. /* This is the lowest level character I/O routine. It send the character to the
  404. CRT, any open disk file, and the LST: device. If enabled, it does a variable
  405. length software delay for the zap-80. */
  406.  
  407. int     sendc(arg)
  408. int    arg;
  409. {
  410. char    character;
  411. int    i,j;
  412.  
  413.     character= arg;                /* type conversion */
  414.     if(console)
  415.         putchar(character);
  416.     if(disk_file) {
  417.         write(outbuf,&character,1);
  418.     }
  419.     if(arg==CR)
  420.     {    if(eol_delay)
  421.         {
  422.             for(i=eol_delay; i>0; i--)
  423.             {    for(j=0; j<100; j++);
  424.             }
  425.         }
  426.     }
  427.     else
  428.     {    if(delay)
  429.         {
  430.             for(i=delay; i>0; i--)
  431.             {    for(j=0; j<100; j++);
  432.             }
  433.         }
  434.     }
  435.     if(send_pch)
  436.         write(punch,&character,1);
  437.     return;
  438. }
  439.  
  440. int    sendb(byte)
  441. int    byte;
  442. {
  443. char    h;
  444.     byte =(byte &0xff);
  445.     h=(byte >>4) &0x0f;
  446.     sendc(((h>9) ? h+'A'-10 : h+'0'));
  447.     h=(byte & 0x0f);
  448.     sendc(((h>9) ? h+'A'-10 : h+'0'));
  449.     return;
  450. }
  451. int    sendw(word)
  452. int    word;
  453. {
  454.     sendb((word >>8) &0xff);
  455.     sendb(word &0xff);
  456.     return;
  457. }
  458.  
  459. /* Make a string into a hex number. Return non-zero if OK. The actual
  460.  return value is set via a calling pointer. */
  461.  
  462. int    make_hex(string,hex_number)
  463. char    *string;
  464. int    *hex_number;
  465. {
  466.     return(sscanf(string,"%x",hex_number));
  467. }
  468.  
  469. /* Make a string into a decimal number. Return non-zero if OK. The actual
  470.  return value is set via a calling pointer. */
  471.  
  472. int    make_dec(string,decimal_numbr)
  473. char    *string;
  474. int    *decimal_numbr;
  475. {
  476.     return(sscanf(string,"%d",decimal_numbr));
  477. }
  478.  
  479.