/* -*- c++ -*-

This is Picprog, Microchip PIC programmer software for the serial port device.
Copyright © 1997,2002,2003,2004,2006 Jaakko Hyvätti

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.

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.

The author may be contacted at:

Email: Jaakko.Hyvatti@iki.fi
URL:   http://www.iki.fi/hyvatti/
Phone: +358 40 5011222

Please send any suggestions, bug reports, success stories etc. to the
Email address above.

*/

#include <iostream>

#include <sysexits.h>
#include <unistd.h>
#define HAVE_DECL_GETOPT 1
#include <getopt.h>
#include <string.h>

#include "hexfile.h"
#include "program.h"

using namespace std;

program prog;

char short_opts [] = "d:p:i:o:c:qsh?";

int
main (int argc, char **argv)
{
  int opt_warranty = 0;
  int opt_copying = 0;
  int opt_quiet = 0;
  int opt_usage = 0;

  int opt_format = hexfile::unknown;
  char *opt_port = (char *)"/dev/cuaa0";
  char *opt_input = NULL;
  char *opt_output = NULL;
  char *opt_cc = NULL;
  int opt_skip = 0;
  int opt_erase = 0;
  int opt_burn = 0;
  int opt_calibration = 0;

  // Auto ident (-1) is the default, or if that fails, first device (0)
  int opt_device = -1;

  struct option long_opts[] = {
    {"quiet", no_argument, NULL, 'q'},
    {"warranty", no_argument, &opt_warranty, 1},
    {"copying", no_argument, &opt_copying, 1},
    {"help", no_argument, NULL, 'h'},
    {"device", required_argument, NULL, 'd'},
    {"pic-serial-port", required_argument, NULL, 'p'},
    {"input-hexfile", required_argument, NULL, 'i'},
    {"output-hexfile", required_argument, NULL, 'o'},
    {"ihx32", no_argument, &opt_format, hexfile::ihx32},
    {"ihx16", no_argument, &opt_format, hexfile::ihx16},
    {"ihx8m", no_argument, &opt_format, hexfile::ihx8m},
    {"cc-hexfile", required_argument, NULL, 'c'},
    {"skip-ones", no_argument, &opt_skip, 1},
    {"erase", no_argument, &opt_erase, 1},
    {"burn", no_argument, &opt_burn, 1},
    {"force-calibration", no_argument, &opt_calibration, 1},
    {"slow", no_argument, NULL, 's'},
    {0, 0, 0, 0}
  };

  int optc;

  prog.init (argv);

  while (0 <= (optc = getopt_long (argc, argv, short_opts, long_opts, NULL)))
    switch (optc) {
    case 0:
      break;
    case 'd':
      if (!strcmp (optarg, "auto"))
	opt_device = -1;
      else if (-1 == (opt_device = hexfile::find_device (optarg)))
	opt_usage = 1;
      break;
    case 'p':
      opt_port = optarg;
      break;
    case 'i':
      opt_input = optarg;
      break;
    case 'o':
      opt_output = optarg;
      break;
    case 'c':
      opt_cc = optarg;
      break;
    case 'q':
      opt_quiet = 1;
      break;
    case 's':
	// Add extra delays for capacity added by very long cable
	picport::t_edge = 10; // 10 us
	picport::t_on = 200000;  // 200 ms
	picport::t_off = 700000; // 700 ms - I'm not kidding !
	break;
    default: // -? -h --help unknown flag
      opt_usage = 1;
    }

  if (!opt_quiet || opt_warranty || opt_copying || opt_usage)
    // Locale charset should be respected here.
    cerr << "Picprog version 1.8.1, Copyright © 2006 Jaakko Hyvätti <Jaakko.Hyvatti@iki.fi>\n"
      "Picprog comes with ABSOLUTELY NO WARRANTY; for details\n"
      "type `" << prog.name << " --warranty'.  This is free software,\n"
      "and you are welcome to redistribute it under certain conditions;\n"
      "type `" << prog.name << " --copying' for details.\n\n";

  if (opt_copying)
    prog.copying ();

  if (opt_warranty)
    prog.warranty ();

  if (opt_usage) {
    cerr << "Full documentation is at "
      "<URL:http://www.iki.fi/hyvatti/pic/picprog.html>" << endl
	 << "The author may be contacted at:" << endl << endl

	 << "Email: Jaakko.Hyvatti@iki.fi" << endl
	 << "URL:   http://www.iki.fi/hyvatti/" << endl << endl

	 << "Supported devices:" << endl;
    hexfile::print_devices ();
    cerr << endl;

    prog.usage (long_opts, short_opts);
  }

  if (opt_warranty || opt_copying || opt_usage)
    return EX_OK;

  if (!opt_input && !opt_output && !opt_erase) {
    cerr << "Please specify either input or output hexfile or --erase option."
	 << endl;
    prog.usage (long_opts, short_opts);
  }

  if (opt_cc && !opt_input) {
    cerr << "Carbon copy does not make sense without input file." << endl;
    prog.usage (long_opts, short_opts);
  }

  // if both input and output files are specified, first program the device
  // and then read it.

  if (opt_input || opt_erase) {
    hexfile mem;
    int retval;

    if (EX_OK != (retval = mem.setdevice (opt_port, opt_device)))
      return retval;
    if (opt_input && EX_OK != (retval = mem.load (opt_input)))
      return retval;
    if (opt_burn) {
      if (EX_OK != (retval = mem.program (opt_port, opt_erase, opt_calibration)))
	return retval;
    } else
      cout << "No --burn option specified, device not programmed.\n";

    if (opt_input && opt_cc)
      if (EX_OK != (retval = mem.save (opt_cc,
				       hexfile::formats (opt_format),
				       opt_skip)))
	return retval;
  }

  if (opt_output) {
    hexfile mem;
    int retval;

    if (EX_OK != (retval = mem.setdevice (opt_port, opt_device)))
      return retval;
    if (EX_OK != (retval = mem.read (opt_port)))
      return retval;
    if (EX_OK != (retval = mem.save (opt_output,
				     hexfile::formats (opt_format),
				     opt_skip)))
      return retval;
  }

  return EX_OK;
}


syntax highlighted by Code2HTML, v. 0.9.1