Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

firmdl.c

Go to the documentation of this file.
00001 /*
00002  *  firmdl3.c
00003  *
00004  *  A firmware downloader for the RCX.  Version 3.0.  Supports single and
00005  *  quad speed downloading.
00006  *
00007  *  The contents of this file are subject to the Mozilla Public License
00008  *  Version 1.0 (the "License"); you may not use this file except in
00009  *  compliance with the License. You may obtain a copy of the License at
00010  *  http://www.mozilla.org/MPL/
00011  *
00012  *  Software distributed under the License is distributed on an "AS IS"
00013  *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
00014  *  License for the specific language governing rights and limitations
00015  *  under the License.
00016  *
00017  *  The Original Code is Firmdl code, released October 3, 1998.
00018  *
00019  *  The Initial Developer of the Original Code is Kekoa Proudfoot.
00020  *  Portions created by Kekoa Proudfoot are Copyright (C) 1998, 1999
00021  *  Kekoa Proudfoot. All Rights Reserved.
00022  *
00023  *  Contributor(s): Kekoa Proudfoot <kekoa@graphics.stanford.edu>
00024  *                  Laurent Demailly
00025  *                  Allen Martin
00026  *                  Markus Noga
00027  *                  Gavin Smyth
00028  *                  Luis Villa
00029  */
00030 
00031 /*
00032  *  usage: firmdl [options] srecfile  (e.g. firmdl Firm0309.lgo)
00033  *
00034  *  If necessary, set DEFAULTTTY, below, to the serial device you want to use.
00035  *  Set the RCXTTY environment variable to override DEFAULTTTY.
00036  *  Use the command-line option --tty=TTY to override RCXTTY and DEFAULTTTY.
00037  *
00038  *  Acknowledgements:
00039  *
00040  *     Laurent Demailly, Allen Martin, Markus Noga, Gavin Smyth, and Luis
00041  *     Villa all contributed something to some version of this program.
00042  *
00043  *  Version history:
00044  *
00045  *     1.x: single speed downloading plus many small revisions
00046  *     2.0: double speed downloading, improved comm code, never released
00047  *     3.0: quad speed downloads, misc other features, version numbering
00048  *     3.1: fixed checksum algorithm, increased max file size
00049  *  Kekoa Proudfoot
00050  *  kekoa@graphics.stanford.edu
00051  *  10/3/98, 10/3/99
00052  */
00053 
00054 /*  2002.04.01
00055  *
00056  *  Modifications to the original loader.c file in LegOS 0.2.4 include:
00057  *
00058  *  Hary D. Mahesan's update to support USB IR firmware downloading 
00059  *  using RCX 2.0's USB tower under WIN32 on Cygwin.
00060  *      <hdmahesa@engmail.uwaterloo.ca>
00061  *      <hmahesan@hotmail.com>
00062  *
00063  *  CVS inclusion, revision and modification by Paolo Masetti.
00064  *      <paolo.masetti@itlug.org>
00065  *
00066  */
00067 
00068 #include <sys/types.h>
00069 #include <sys/stat.h>
00070 #include <fcntl.h>
00071 #include <stdlib.h>
00072 #include <unistd.h>
00073 #include <termios.h>
00074 #include <stdio.h>
00075 #include <string.h>
00076 #include <sys/time.h>
00077 #include <ctype.h>
00078 #include <string.h>
00079 #include <assert.h>
00080 
00081 #if defined(_WIN32)
00082   #include <windows.h>
00083 #endif
00084 
00085 #include "rcx_comm.h"
00086 #include "srec.h"
00087 
00088 /* Machine-dependent defines */
00089 
00090 #if defined(LINUX) || defined(linux)
00091 #define DEFAULTTTY   "/dev/ttyS0" /* Linux - COM1 */
00092 #elif defined (_WIN32)
00093 #define DEFAULTTTY   "com1"       /* Cygwin - COM1 */
00094 #elif defined (sun)
00095 #define DEFAULTTTY   "/dev/ttya"  /* Solaris - first serial port - untested */
00096 #else
00097 #define DEFAULTTTY   "/dev/ttyd2" /* IRIX - second serial port */
00098 #endif
00099 
00100 /* Global variables */
00101 
00102 char *progname;
00103 int tty_usb = 0; 
00104 extern int __comm_debug; 
00105 
00106 #include "fastdl.h"
00107 
00108 /* Defines */
00109 
00110 #define BUFFERSIZE      4096
00111 #define RETRIES         10
00112 #define WAKEUP_TIMEOUT  4000
00113 
00114 #define UPLOAD_TIMEOUT  50
00115 
00116 #define IMAGE_START     0x8000
00117 #define IMAGE_MAXLEN    0x7000
00118 #define TRANSFER_SIZE   200
00119 
00120 /* Stripping zeros is not entirely legal if firmware expects trailing zeros */
00121 /* Define FORCE_ZERO_STRIPPING to force zero stripping for all files */
00122 /* Normally you do not want to do this */
00123 /* Possibly useful only if you explicitly zero pad for OCX compatiblity */
00124 /* Since zero stripping is okay for Firm0309.lgo, that is done automatically */
00125 
00126 #if 0
00127 #define FORCE_ZERO_STRIPPING
00128 #endif
00129 
00130 /* Functions */
00131 
00132 int srec_load (char *name, unsigned char *image, int maxlen, unsigned short *start)
00133 {
00134     FILE *file;
00135     char buf[256];
00136     srec_t srec;
00137     int line = 0;
00138     int length = 0;
00139     int strip = 0;
00140 
00141     /* Initialize starting address */
00142     *start = IMAGE_START;
00143 
00144     /* Open file */
00145     if ((file = fopen(name, "r")) == NULL) {
00146                 fprintf(stderr, "%s: ERROR- failed to open %s\n", progname, name);
00147                 exit(1);
00148     }
00149 
00150     /* Clear image to zero */
00151     memset(image, 0, maxlen);
00152 
00153     /* Read image file */
00154     while (fgets(buf, sizeof(buf), file)) {
00155         int error, i;
00156         line++;
00157         /* Skip blank lines */
00158         for (i = 0; buf[i]; i++)
00159             if (!isspace(buf[i]))
00160                 break;
00161         if (!buf[i])
00162             continue;
00163         /* Decode line */
00164         if ((error = srec_decode(&srec, buf)) < 0) {
00165             if (error != SREC_INVALID_CKSUM) {
00166                 fprintf(stderr, "%s: %s on line %d\n",
00167                         name, srec_strerror(error), line);
00168                 exit(1);
00169             }
00170         }
00171         /* Detect Firm0309.lgo header, set strip=1 if found */
00172         if (srec.type == 0) {
00173             if (srec.count == 16)
00174                 if (!strncmp(srec.data, "?LIB_VERSION_L00", 16))
00175                     strip = 1;
00176         }
00177         /* Process s-record data */
00178         else if (srec.type == 1) {
00179             if (srec.addr < IMAGE_START ||
00180                 srec.addr + srec.count > IMAGE_START + maxlen) {
00181                 fprintf(stderr, "%s: address out of bounds on line %d\n",
00182                         name, line);
00183                 exit(1);
00184             }
00185             if (srec.addr + srec.count - IMAGE_START > length)
00186                 length = srec.addr + srec.count - IMAGE_START;
00187             memcpy(&image[srec.addr - IMAGE_START], &srec.data, srec.count);
00188         }
00189         /* Process image starting address */
00190         else if (srec.type == 9) {
00191             if (srec.addr < IMAGE_START ||
00192                 srec.addr > IMAGE_START + maxlen) {
00193                 fprintf(stderr, "%s: address out of bounds on line %d\n",
00194                         name, line);
00195                 exit(1);
00196             }
00197             *start = srec.addr;
00198         }
00199     }
00200 
00201     /* Strip zeros */
00202 #ifdef FORCE_ZERO_STRIPPING
00203     strip = 1;
00204 #endif
00205 
00206     if (strip) {
00207         int pos;
00208         for (pos = IMAGE_MAXLEN - 1; pos >= 0 && image[pos] == 0; pos--);
00209         length = pos + 1;
00210     }
00211 
00212     /* Check length */
00213     if (length == 0) {
00214         fprintf(stderr, "%s: image contains no data\n", name);
00215         exit(1);
00216     }
00217 
00218     return length;
00219 }
00220 
00221 void image_dl(FILEDESCR fd, unsigned char *image, int len, unsigned short start,
00222               int use_comp, char *filename)
00223 {
00224     unsigned short cksum = 0;
00225     unsigned char send[BUFFERSIZE];
00226     unsigned char recv[BUFFERSIZE];
00227     int addr, index, size, i;
00228 
00229     /* Compute image checksum */
00230     int cksumlen = (start + len < 0xcc00) ? len : 0xcc00 - start;
00231     assert(len > 0);
00232     for (i = 0; i < cksumlen; i++)
00233         cksum += image[i];
00234 
00235     /* Delete firmware */
00236     send[0] = 0x65;
00237     send[1] = 1;
00238     send[2] = 3;
00239     send[3] = 5;
00240     send[4] = 7;
00241     send[5] = 11;
00242 
00243     if (rcx_sendrecv(fd, send, 6, recv, 1, 50, RETRIES, use_comp) != 1) {
00244         fprintf(stderr, "%s: delete firmware failed\n", progname);
00245         exit(1);
00246     }
00247 
00248     /* Start firmware download */
00249     send[0] = 0x75;
00250     send[1] = (start >> 0) & 0xff;
00251     send[2] = (start >> 8) & 0xff;
00252     send[3] = (cksum >> 0) & 0xff;
00253     send[4] = (cksum >> 8) & 0xff;
00254     send[5] = 0;
00255 
00256     if (rcx_sendrecv(fd, send, 6, recv, 2, 50, RETRIES, use_comp) != 2) {
00257         fprintf(stderr, "%s: start firmware download failed\n", progname);
00258         exit(1);
00259     }
00260 
00261     /* Transfer data */
00262     fprintf(stderr, "\rTransferring \"%s\" to RCX...\n", filename);
00263     addr = 0;
00264     index = 1;
00265     for (addr = 0, index = 1; addr < len; addr += size, index++) {
00266         fprintf(stderr,"\r%3d%%        \r",(100*addr)/len);
00267         size = len - addr;
00268         send[0] = 0x45;
00269         if (index & 1)
00270             send[0] |= 0x08;
00271         if (size > TRANSFER_SIZE)
00272             size = TRANSFER_SIZE;
00273         else if (0)
00274             /* Set index to zero to make sound after last transfer */
00275             index = 0;
00276         send[1] = (index >> 0) & 0xff;
00277         send[2] = (index >> 8) & 0xff;
00278         send[3] = (size >> 0) & 0xff;
00279         send[4] = (size >> 8) & 0xff;
00280         memcpy(&send[5], &image[addr], size);
00281         for (i = 0, cksum = 0; i < size; i++)
00282             cksum += send[5 + i];
00283         send[size + 5] = cksum & 0xff;
00284 
00285         if (rcx_sendrecv(fd, send, size + 6, recv, 2, UPLOAD_TIMEOUT, RETRIES,
00286                          use_comp) != 2 || recv[1] != 0) {
00287             fprintf(stderr, "%s: transfer data failed\n", progname);
00288             exit(1);
00289         }
00290     }
00291     fputs("100%        \n",stderr);
00292 
00293     /* Unlock firmware */
00294     send[0] = 0xa5;
00295     send[1] = 76;               // 'L'
00296     send[2] = 69;               // 'E'
00297     send[3] = 71;               // 'G'
00298     send[4] = 79;               // 'O'
00299     send[5] = 174;      // '®'
00300 
00301     /* Use longer timeout so ROM has time to checksum firmware */
00302     if (rcx_sendrecv(fd, send, 6, recv, 26, 150, RETRIES, use_comp) != 26) {
00303         fprintf(stderr, "%s: unlock firmware failed\n", progname);
00304         exit(1);
00305     }
00306 }
00307 
00308 int main (int argc, char **argv)
00309 {
00310     unsigned char image[IMAGE_MAXLEN];
00311     unsigned short image_start;
00312     unsigned int image_len;
00313     char *tty = NULL;
00314     int use_fast = 1;
00315     int usage = 0;
00316     FILEDESCR fd;
00317     int status;
00318 
00319     progname = argv[0];
00320 
00321     /* Parse command line */
00322 
00323     argv++; argc--;
00324     while (argc && argv[0][0] == '-') {
00325         if (argv[0][1] == '-') {
00326             if (!strcmp(argv[0], "--")) {
00327                 argv++; argc--;
00328                 break;
00329             }
00330             else if (!strcmp(argv[0], "--debug")) {
00331                 __comm_debug = 1;
00332             }
00333             else if (!strcmp(argv[0], "--fast")) {
00334                 use_fast = 1;
00335             }
00336             else if (!strcmp(argv[0], "--slow")) {
00337                 use_fast = 0;
00338             }
00339             else if (!strncmp(argv[0], "--tty", 5)) {
00340                 if (argv[0][5] == '=') {
00341                     tty = &argv[0][6];
00342                 }
00343                 else if (argc > 1) {
00344                     argv++; argc--;
00345                     tty = argv[0];
00346                 }
00347                 else
00348                     tty = "";
00349                 if (!tty[0]) {
00350                     fprintf(stderr, "%s: invalid tty: %s\n", progname, tty);
00351                     exit(1);
00352                 }
00353             }
00354             else if (!strcmp(argv[0], "--help")) {
00355                 usage = 1;
00356             }
00357             else {
00358                 fprintf(stderr, "%s: unrecognized option %s\n",
00359                         progname, argv[0]);
00360                 exit(1);
00361             }
00362         }
00363         else {
00364             char *p = &argv[0][1];
00365             if (!*p)
00366                 break;
00367             while (*p) {
00368                 switch (*p) {
00369                 case 'f': use_fast = 1; break;
00370                 case 's': use_fast = 0; break;
00371                 case 'h': usage = 1; break;
00372                 default:
00373                     fprintf(stderr, "%s: unrecognized option -- %c\n",
00374                             progname, *p);
00375                     exit(1);
00376                 }
00377                 p++;
00378             }
00379         }
00380         argv++;
00381         argc--;
00382     }
00383 
00384     if (usage || argc != 1) {
00385         char *usage_string =
00386             "      --debug      show debug output, mostly raw bytes\n"
00387             "  -f, --fast       use fast 4x downloading (default)\n"
00388             "  -s, --slow       use slow 1x downloading\n"
00389             "      --tty=TTY    assume tower connected to TTY\n"
00390 #if defined(_WIN32)
00391             "      --tty=usb    assume tower connected to USB\n"
00392 #else
00393             "                   (if device name contains \"usb\", use USB mode)\n"
00394 #endif
00395             "  -h, --help       display this help and exit\n"
00396             ;
00397 
00398         fprintf(stderr, "usage: %s [options] filename\n", progname);
00399         fprintf(stderr, usage_string);
00400         exit(1);
00401     }
00402 
00403     /* Load the s-record file */
00404 
00405     image_len = srec_load(argv[0], image, IMAGE_MAXLEN, &image_start);
00406 
00407     /* Get the tty name */
00408 
00409     if (!tty)
00410         tty = getenv("RCXTTY");
00411     if (!tty)
00412         tty = DEFAULTTTY;
00413 
00414 #if defined(_WIN32)
00415     //Check the command line to see if IR tower is USB.
00416     if(stricmp(tty,"usb")==0)   {
00417         tty_usb = 1;
00418         if(__comm_debug)
00419                 fprintf(stderr, "Hary Mahesan - USB IR Tower Mode.\n");
00420         tty = "\\\\.\\legotower1"; // Set the correct usb tower if you have more than one (unlikely).
00421     }
00422 #elif defined(LINUX) || defined(linux)
00423     /* If the tty string contains "usb", e.g. /dev/usb/lego0, we */
00424     /* assume it is the USB tower.  If you use something else that doesn't */
00425     /* have "usb" in the device name, link it.  /dev/usb/lego0 is the */
00426     /* name of the dirver installed by LegoUSB */
00427     /* (http://legousb.sourceforge.net) */
00428     if (strstr(tty,"usb") !=0) {
00429        tty_usb=1;
00430        if (__comm_debug)
00431          fprintf(stderr, "P.C. Chan & Tyler Akins - USB IR Tower Mode for Linux.\n");
00432     }   
00433 #endif
00434 
00435     if (use_fast && (tty_usb==0)) { //For now, run USB only at 2400bps (slow mode).
00436         /* Try to wake up the tower in fast mode */
00437 
00438         fd = rcx_init(tty, 0);  // Slow startup seems better with low batteries...
00439 
00440         if ((status = rcx_wakeup_tower(fd, WAKEUP_TIMEOUT)) < 0) {
00441             fprintf(stderr, "%s: %s\n", progname, rcx_strerror(status));
00442             exit(1);
00443         }
00444 
00445         // Let's put IR in Fast mode.
00446         rcx_close(fd);
00447         fd = rcx_init(tty, 1);
00448 
00449         /* Check if already alive in fast mode */
00450         if (!rcx_is_alive(fd, 0)) {
00451             /* Not alive in fast mode, download fastdl in slow mode */
00452 
00453             rcx_close(fd);
00454             fd = rcx_init(tty, 0);
00455 
00456             if (!rcx_is_alive(fd, 1)) {
00457                 fprintf(stderr, "%s: no response from rcx\n", progname);
00458                 exit(1);
00459             }
00460 
00461             image_dl(fd, fastdl_image, fastdl_len, fastdl_start, 1, "Fast Download Image");
00462 
00463             /* Go back to fast mode */
00464             rcx_close(fd);
00465             fd = rcx_init(tty, 1);
00466         }
00467 
00468         /* Download image in fast mode */
00469 
00470         image_dl(fd, image, image_len, image_start, 0, argv[0]);
00471         rcx_close(fd);
00472     } else {
00473         /* Try to wake up the tower in slow mode */
00474 
00475         fd = rcx_init(tty, 0);
00476 
00477         // USB tower does not need to be waken up...
00478         if(tty_usb==0) {
00479           if ((status = rcx_wakeup_tower(fd, WAKEUP_TIMEOUT)) < 0) {
00480               fprintf(stderr, "%s: %s\n", progname, rcx_strerror(status));
00481               exit(1);
00482           }
00483 
00484           if (!rcx_is_alive(fd, 1)) {
00485               /* See if alive in fast mode */
00486 
00487               rcx_close(fd);
00488               fd = rcx_init(tty, 1);
00489 
00490               if (rcx_is_alive(fd, 0)) {
00491                   fprintf(stderr, "%s: rcx is in fast mode\n", progname);
00492                   fprintf(stderr, "%s: turn rcx off then back on to "
00493                         "use slow mode\n", progname);
00494                   exit(1);
00495               }
00496 
00497               fprintf(stderr, "%s: no response from rcx\n", progname);
00498               exit(1);
00499           }
00500         }
00501 
00502         /* Download image */
00503         image_dl(fd, image, image_len, image_start, 1, argv[0]);
00504 
00505         rcx_close(fd);
00506     }
00507 
00508     return 0;
00509 }

Generated on Fri Feb 25 08:02:40 2005 for brickos by  doxygen 1.3.9.1