Logo Search packages:      
Sourcecode: odyssey version File versions

main.cxx

/* Copyright (C) 2002-2004  Mark Andrew Aikens <marka@desert.cx>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: main.cxx,v 1.30 2004/08/22 16:44:48 marka Exp $
 */
using namespace std;

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <ctype.h>
#include <getopt.h>
#include <exception>
#include <iterator>
#include <vector>
#include <string>
#include "config.h"
#include "ConfigFile.h"
#include "DataBuffer.h"
#include "HexFile.h"
#include "IO.h"
#include "Device.h"


/* Global variables */
00040 ConfigFile *config;



static char *argv0;
static Device *device;
static IO *io;
static bool quiet;

static void do_listdevices(void);
static int do_init(int argc, char *argv[]);
static int do_write(int argc, char *argv[]);
static int do_read(int argc, char *argv[]);
static int do_verify(int argc, char *argv[]);
static int do_erase(int argc, char *argv[]);
static int do_blankcheck(int argc, char *argv[]);
static int do_test(int argc, char *argv[]);


static const struct cmd {
      char *name;
      int  (*func)(int argc, char *argv[]);
      bool requires_chiptype;
      char *desc;
} commands[] = {
      {"init", do_init, false, "Prepares the programmer board for use"},
      {"write", do_write, true, "Writes data to PIC"},
      {"read", do_read, true, "Reads the contents of a PIC"},
      {"verify", do_verify, true, "Verifies the contents of a PIC"},
      {"erase", do_erase, true, "Erases an electrically erasable PIC"},
      {"blankcheck", do_blankcheck, true, "Checks if a PIC is erased"},
      {"test", do_test, false, "Enters programmer board test mode"},
};
static const int num_commands = (sizeof(commands) / sizeof(struct cmd));


static int usage(void) {
      int i;

      fprintf(stderr,
            "Usage:\n" \
            "  odyssey [options] init\n"
            "  odyssey [options] test\n"
            "  odyssey [options] chiptype command [command options]\n"
            "\n" \
            "Options:\n" \
            "  -V            Print the version of Odyssey and exit\n" \
            "  -q            Quiet mode. Don't display the progress counters.\n" \
            "  -f filename   Use an alternate configuration file in ~/.odyssey/\n" \
            "  -v s.var=val  Override a configuration file variable\n" \
            "  -l            List supported values for chiptype and exit\n" \
            "\n" \
            "Commands:\n");

      for(i=0; i<num_commands; i++)
            fprintf(stderr, "  %-14s %s\n", commands[i].name, commands[i].desc);
      fprintf(stderr, "\n");

      return 1;
}


static void sighandler(int sig) {
      fprintf(stderr, "Caught signal %d.\n", sig);
      if(io != NULL)
            delete io;
      exit(1);
}


static bool progress(void *data, long addr, int percent) {
      static int last_percent = 101;
      static int output_is_tty = -1;

      if(!quiet && (percent != last_percent)) {
            last_percent = percent;
            if(output_is_tty < 0)
                  output_is_tty = isatty(1);
            if(output_is_tty) {
                  printf("\033[1GAddress: 0x%06lx, % 3d%% done", addr, percent);
                  fflush(stdout);
            } else {
                  printf("Address: 0x%06lx, % 3d%% done\n", addr, percent);
            }
      }
      return true;
}


int main(int argc, char *argv[]) {
      char ioname[30];
      int retval, i;
      long ioport;
      char *user_configfile="config";
      vector<string> var_override;

      quiet = false;
      while((i = getopt(argc, argv, "qVv:f:l+")) > 0) {
            switch(i) {
            case 'q':
                  quiet = true;
                  break;
            case 'V':
                  printf("Odyssey version %s\n", VERSION);
                  return 0;
            case 'v':
                  var_override.push_back(string(optarg));
                  break;
            case 'f':
                  user_configfile = optarg;
                  break;
            case 'l':
                  do_listdevices();
                  return 0;
            case '?':
            case ':':
            default:;
                  return usage();
            }
      }

      if(optind == argc) {
            fprintf(stderr, "%s: Not enough arguments.\n", argv[0]);
            return usage();
      }

      /* Read in the configuration file */
      try {
            config = new ConfigFile(user_configfile, PACKAGE,
              SYSCONFDIR "/" PACKAGE ".conf");
      } catch(std::exception& e) {
            fprintf(stderr, "Error: %s\n", e.what());
            return 1;
      }

      /* Process config variables set on the command line */
      vector<string>::iterator it = var_override.begin();
      for(; it != var_override.end(); it++) {
            int j = it->find('=');
            /* Check for the form a.b=c */
            if((j < 0) || ((i = (int)it->rfind('.', j)) < 0)) {
                  fprintf(stderr, "Invalid syntax for specifying a configuration variable\n");
                  return 1;
            }
            string section(*it, 0, i);
            string key(*it, i+1, j-i-1);
            string value(*it, j+1);
            config->set_string(section, key, value.c_str());
      }
      var_override.clear();

      /* Default IO driver parameters */
      if(! config->get_string("io", "driver", ioname, sizeof(ioname))) {
            strcpy(ioname, "DirectPP");
      }
      if(! config->get_integer("io", "port", &ioport)) {
            ioport = 0;
      }

      /* Initialize the hardware */
      try {
            io = IO::acquire(ioname, ioport);
      } catch(std::exception& e) {
            fprintf(stderr, "\n%s: I/O init: %s\n", argv[0], e.what());
            retval = 1;
            goto exit1;
      }


      /* commands that don't need a chiptype */
      for(i=0; i<num_commands; i++) {
            if(!strcmp(argv[optind], commands[i].name)) {
                  retval = 1;
                  if(commands[i].requires_chiptype) {
                        fprintf(stderr,
                          "\n%s: Missing chiptype for command %s\n",
                          argv[0], argv[optind]);
                  } else {
                        retval = commands[i].func(argc-optind, &argv[optind]);
                  }
                  goto exit2;
            }
      }

      /* Load the device configuration */
      device = Device::load(argv[optind]);
      if(device == NULL) {
            fprintf(stderr, "\n%s: Couldn't load configuration for '%s' device.\n",
              argv[0], argv[optind]);
            retval = 1;
            goto exit2;
      }
      optind++;

      if(optind == argc) {
            fprintf(stderr, "%s: Need to specify a command.\n", argv[0]);
            retval = usage();
            goto exit3;
      }

      /* Catch some signals to properly shut down the hardware */
      signal(SIGHUP, sighandler);
      signal(SIGINT, sighandler);
      signal(SIGQUIT, sighandler);
      signal(SIGPIPE, sighandler);
      signal(SIGTERM, sighandler);

      device->set_iodevice(io);
      device->set_progress_cb(progress);

      retval = 1;
      argv0 = argv[0];
      for(i=0; i<num_commands; i++) {
            if(!strcmp(argv[optind], commands[i].name)) {
                  retval = commands[i].func(argc-optind, &argv[optind]);
                  break;
            }
      }

      if(i == num_commands) {
            fprintf(stderr, "%s: Invalid command '%s'.\n", argv[0], argv[optind]);
            retval = usage();
      }

      device->set_iodevice(NULL);

exit3:;
      delete device;

exit2:;
      delete io;
      io = NULL;

exit1:;
      delete config;
      return retval;
}


static void do_listdevices(void) {
      vector<string>::iterator it;
      vector<string> *devlist;
      string line;

      devlist = Device::list();
      printf("Supported values for chiptype. A * indicates that it has not yet been tested.\n");
      for(it=devlist->begin(); it != devlist->end();) {
            if(line.empty()) {
                  line.append("  ");
                  line.append(*it);
                  it++;
            } else if(line.size() + it->size() > 74) {
                  printf("%s\n", line.c_str());
                  line.erase();
            } else {
                  line.append(", ");
                  line.append(*it);
                  it++;
            }
      }
      if(! line.empty())
            printf("%s\n", line.c_str());

      delete devlist;
}

static int do_init(int argc, char *argv[]) {
      /* Hardware already configured in IO's subclasses' constructor */
      return 0;
}

static int do_write(int argc, char *argv[]) {
      if(argc < 2) {
            fprintf(stderr, "\n%s: %s requires a filename.\n", argv0, argv[0]);
            fprintf(stderr,
                  "Usage:\n  %s [options] chiptype %s filename.hex\n\n",
                    argv0, argv[0]);
            return 1;
      }

      DataBuffer buf(device->get_wordsize());

      try {
            /* Read the hex file into the data buffer */
            HexFile *hf = HexFile::load(argv[1]);

            hf->read(buf);
            delete hf;
      } catch(std::exception& e) {
            fprintf(stderr, "%s: %s\n", argv[1], e.what());
            return 1;
      }

      try {
            device->program(buf);
            printf("\n");
      } catch(std::exception& e) {
            printf("\n");
            fprintf(stderr, "%s: %s: %s\n", argv0, device->get_name().c_str(), e.what());
            return 1;
      }

      return 0;
}


static int do_read(int argc, char *argv[]) {
      if(argc < 2) {
            fprintf(stderr, "\n%s: %s requires a filename.\n", argv0, argv[0]);
            fprintf(stderr,
                  "Usage:\n  %s [options] chiptype %s filename.hex\n\n",
                    argv0, argv[0]);
            return 1;
      }

      DataBuffer buf(device->get_wordsize());
      HexFile *hf;

      try {
            /* Read data from the device into the buffer */
            device->read(buf);
            printf("\n");
      } catch(std::exception& e) {
            printf("\n");
            fprintf(stderr, "%s: %s: %s\n", argv0, device->get_name().c_str(), e.what());
            return 1;
      }

      try {
            /* Open the hex file */
            hf = new HexFile_ihx8(argv[1]);
      } catch(std::exception& e) {
            fprintf(stderr, "%s: %s\n", argv[1], e.what());
            return 1;
      }

      try {
            /* Get the device memory map so we know what parts of the buffer
             * are valid and save those parts to the hex file. */
            IntPairVector mmap = device->get_mmap();
            IntPairVector::iterator n = mmap.begin();
            for(; n != mmap.end(); n++)
                  hf->write(buf, n->first, n->second);
      } catch(std::exception& e) {
            delete hf;
            fprintf(stderr, "%s: %s\n", argv[0], e.what());
            return 1;
      }
      delete hf;

      return 0;
}


static int do_verify(int argc, char *argv[]) {
      if(argc < 2) {
            fprintf(stderr, "\n%s: %s requires a filename.\n", argv0, argv[0]);
            fprintf(stderr,
                  "Usage:\n  %s [options] chiptype %s filename.hex\n\n",
                    argv0, argv[0]);
            return 1;
      }

      DataBuffer buf(device->get_wordsize());

      try {
            /* Read data from the file into the buffer */
            HexFile *hf = HexFile::load(argv[1]);
            hf->read(buf);
            delete hf;
      } catch(std::exception& e) {
            fprintf(stderr, "%s: %s\n", argv[1], e.what());
            return 1;
      }

      try {
            /* Verify the contents of the device */
            device->read(buf, true);
            printf("\n");
      } catch(std::exception& e) {
            printf("\n");
            fprintf(stderr, "%s\n", e.what());
            return 1;
      }

      printf("Verification succeeded.\n");
      return 0;
}


static int do_erase(int argc, char *argv[]) {
      try {
            device->erase();
      } catch(std::exception& e) {
            fprintf(stderr, "\n%s: %s: %s\n", argv0, device->get_name().c_str(), e.what());
            return 1;
      }
      return 0;
}


static int do_blankcheck(int argc, char *argv[]) {
      DataBuffer buf(device->get_wordsize());

      printf("Verifying a device is blank.\n");
      try {
            /* Verify the contents of the device */
            device->read(buf, true);
            printf("\n");
      } catch(std::exception& e) {
            printf("\n");
            fprintf(stderr, "%s\nDevice is not blank.\n", e.what());
            return 1;
      }
      printf("Device is blank.\n");
      return 0;
}


static int do_test(int argc, char *argv[]) {
      bool get_out;
      char buffer[100];
      enum { undefined, set_signal, unset_signal } action;
      int i;

      printf("\nProgrammer board test mode. Make sure you didn't " \
        "leave a PIC in the programmer.");

      get_out = false;
      while(! get_out) {
            printf("\n\n");
            printf("Current Status:\n");
            try {
                  printf("Pwr     = %1d    Vpp    = %1d    Clk = %1d\n",
                    (int)io->get_pwr(), (int)io->get_vpp(), (int)io->get_clk());
                  printf("DataOut = %1d    DataIn = %1d\n\n",
                    (int)io->get_data(), (int)io->read_data());
            } catch(std::exception& e) {
                  printf("\nError determining status:\n  %s\n\n", e.what());
            }
            printf("Signal Abbreviations: (P)wr     (V)pp     (C)lk     (D)ata\n");
            printf("Commands:             (Q) Quit  (H) Help  (+) Set   (-) Unset\n");
            printf(" %% ");
            fflush(stdout);

            if(fgets(buffer, sizeof(buffer), stdin) == NULL)
                  break;

            action = undefined;
            for(i = 0; buffer[i] != 0; i++) {
                  switch(buffer[i]) {
                  case '\n':
                  case '\r':
                        break;
                  case 'q':
                  case 'Q':
                        get_out = true;
                        printf("\n");
                        goto next_line;
                  case 'h':
                  case 'H':
                  case '?':
                        printf("\nFor example : \"+PV-D\" sets the Pwr and Vpp " \
                          "signals, unsets DataOut and\nleaves Clk unchanged\n");
                        goto next_line;
                  case '+':
                        action = set_signal;
                        break;
                  case '-':
                        action = unset_signal;
                        break;
                  case 'p':
                  case 'P':
                  case 'v':
                  case 'V':
                  case 'c':
                  case 'C':
                  case 'd':
                  case 'D':
                        if(action == undefined) {
                              printf("Undefined action (set/unset) for %c\n",
                                toupper(buffer[i]));
                              break;
                        }
                        try {
                              switch(toupper(buffer[i])) {
                              case 'P':
                                    io->set_pwr(action == set_signal);
                                    break;
                              case 'V':
                                    io->set_vpp (action == set_signal);
                                    break;
                              case 'C':
                                    io->set_clk (action == set_signal);
                                    break;
                              case 'D':
                                    io->set_data(action == set_signal);
                                    break;
                              }
                        } catch(std::exception& e) {
                              printf("\nError processing command:\n  %s\n\n", e.what());
                        }
                        break;
                  default:
                        printf("Unknown signal '%c'\n", toupper(buffer[i]));
                        goto next_line;
                  }
            }
next_line:;
      }

      io->set_pwr(false);
      io->set_vpp(false);
      io->set_clk(false);
      io->set_data(false);

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index