diff --git a/main.c b/main.c index bed09db..782c4ac 100644 --- a/main.c +++ b/main.c @@ -118,32 +118,144 @@ static void store_io(void *user_data, uint16_t pc, printf(" => 0x%04x\n", data); } +struct cmdline_args { + const char *driver_name; + const char *serial_device; + const char *fet_force_id; + int want_jtag; + int no_rc; + int vcc_mv; + stab_t stab; +}; + +struct driver { + const char *name; + const char *help; + device_t (*func)(const struct cmdline_args *args); +}; + +static device_t driver_open_fet(const struct cmdline_args *args, + int flags, transport_t trans) +{ + device_t dev; + + if (!args->want_jtag) + flags |= FET_PROTO_SPYBIWIRE; + + dev = fet_open(trans, flags, args->vcc_mv, args->fet_force_id); + if (!dev) { + trans->destroy(trans); + return NULL; + } + + return dev; +} + +static device_t driver_open_rf2500(const struct cmdline_args *args) +{ + transport_t trans; + + if (args->serial_device) { + fprintf(stderr, "This driver does not support tty devices.\n"); + return NULL; + } + + trans = rf2500_open(); + if (!trans) + return NULL; + + return driver_open_fet(args, FET_PROTO_RF2500, trans); +} + +static device_t driver_open_olimex(const struct cmdline_args *args) +{ + transport_t trans; + + if (args->serial_device) + trans = uif_open(args->serial_device, 1); + else + trans = olimex_open(); + + if (!trans) + return NULL; + + return driver_open_fet(args, FET_PROTO_OLIMEX, trans); +} + +static device_t driver_open_sim(const struct cmdline_args *args) +{ + return sim_open(fetch_io, store_io, args->stab); +} + +static device_t driver_open_uif(const struct cmdline_args *args) +{ + transport_t trans; + + if (!args->serial_device) { + fprintf(stderr, "This driver does not support USB access. " + "Specify a tty device using -d.\n"); + return NULL; + } + + trans = uif_open(args->serial_device, 0); + if (!trans) + return NULL; + + return driver_open_fet(args, 0, trans); +} + +static device_t driver_open_uif_bsl(const struct cmdline_args *args) +{ + if (!args->serial_device) { + fprintf(stderr, "This driver does not support USB access. " + "Specify a tty device using -d.\n"); + return NULL; + } + + return bsl_open(args->serial_device); +} + +static const struct driver driver_table[] = { + { + .name = "rf2500", + .help = "eZ430-RF2500 devices. Only USB connection is " + "supported.", + driver_open_rf2500 + }, + { .name = "olimex", + .help = "Olimex MSP-JTAG-TINY.", + .func = driver_open_olimex + }, + { + .name = "sim", + .help = "Simulation mode.", + .func = driver_open_sim + }, + { + .name = "uif", + .help = "TI FET430UIF and compatible devices (e.g. eZ430).", + .func = driver_open_uif + }, + { + .name = "uif-bsl", + .help = "TI FET430UIF bootloader.", + .func = driver_open_uif_bsl + } +}; + static void usage(const char *progname) { + int i; + fprintf(stderr, -"Usage: %s [options] -R [-v voltage] [command ...]\n" -" %s [options] -u [-j] [-v voltage] [command ...]\n" -" %s [options] -O [-j] [-v voltage] [command ...]\n" -" %s [options] -l [-j] [-v voltage] [command ...]\n" -" %s [options] -B [command ...]\n" -" %s [options] -s [command ...]\n" +"Usage: %s [options] [command ...]\n" "\n" -" -R\n" -" Open the first available RF2500 device on the USB bus.\n" -" -u device\n" -" Open the given tty device (FET430UIF compatible devices).\n" -" -O device\n" -" Open the given tty device (Olimex MSP430-JTAG-TINY).\n" -" -l\n" -" Open the first available Olimex MSP430-JTAG-TINY using libusb.\n" +" -d device\n" +" Connect via the given tty device, rather than USB.\n" " -j\n" " Use JTAG, rather than Spy-Bi-Wire (UIF devices only).\n" " -v voltage\n" " Set the supply voltage, in millivolts.\n" -" -B device\n" -" Debug the FET itself through the bootloader.\n" -" -s\n" -" Start in simulation mode.\n" " -n\n" " Do not read ~/.mspdebug on startup.\n" " --help\n" @@ -153,11 +265,19 @@ static void usage(const char *progname) " --fet-force-id string\n" " Override the device ID returned by the FET.\n" "\n" -"By default, the first RF2500 device on the USB bus is opened.\n" +"Most drivers connect by default via USB, unless told otherwise via the\n" +"-d option.\n" "\n" "If commands are given, they will be executed. Otherwise, an interactive\n" -"command reader is started.\n", - progname, progname, progname, progname, progname, progname); +"command reader is started.\n\n", + progname); + + printf("Available drivers are:\n"); + for (i = 0; i < ARRAY_LEN(driver_table); i++) { + const struct driver *drv = &driver_table[i]; + + printf(" %s\n %s\n", drv->name, drv->help); + } } static void process_rc_file(cproc_t cp) @@ -173,22 +293,6 @@ static void process_rc_file(cproc_t cp) cproc_process_file(cp, text); } -#define MODE_RF2500 0x01 -#define MODE_UIF 0x02 -#define MODE_UIF_BSL 0x04 -#define MODE_SIM 0x08 -#define MODE_OLIMEX 0x10 -#define MODE_OLIMEX_USB 0x20 - -struct cmdline_args { - const char *devpath; - const char *fet_force_id; - int mode; - int want_jtag; - int no_rc; - int vcc_mv; -}; - static int add_fet_device(void *user_data, const struct fet_db_record *r) { struct vector *v = (struct vector *)user_data; @@ -234,12 +338,11 @@ static int parse_cmdline_args(int argc, char **argv, {NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "lu:jv:B:O:sR?n", + while ((opt = getopt_long(argc, argv, "d:jv:n", longopts, NULL)) >= 0) switch (opt) { - case 'O': - args->devpath = optarg; - args->mode |= MODE_OLIMEX; + case 'd': + args->serial_device = optarg; break; case 'L': @@ -253,19 +356,6 @@ static int parse_cmdline_args(int argc, char **argv, usage(argv[0]); exit(0); - case 'R': - args->mode |= MODE_RF2500; - break; - - case 'u': - args->devpath = optarg; - args->mode |= MODE_UIF; - break; - - case 'l': - args->mode |= MODE_OLIMEX_USB; - break; - case 'v': args->vcc_mv = atoi(optarg); break; @@ -274,103 +364,50 @@ static int parse_cmdline_args(int argc, char **argv, args->want_jtag = 1; break; - case 'B': - args->devpath = optarg; - args->mode |= MODE_UIF_BSL; - break; - - case 's': - args->mode |= MODE_SIM; - break; - case 'n': args->no_rc = 1; break; case '?': - return -1; - - default: - fprintf(stderr, "Invalid argument: %c\n" - "Try --help for help.\n", opt); + fprintf(stderr, "Try --help for usage information.\n"); return -1; } - /* Check for incompatible arguments */ - if (args->mode & (args->mode - 1)) { - fprintf(stderr, "Multiple incompatible options specified.\n" - "Try --help for help.\n"); + if (optind >= argc) { + fprintf(stderr, "You need to specify a driver. Try --help for " + "a list.\n"); return -1; } - if (!args->mode) { - fprintf(stderr, "You need to specify an operating mode.\n" - "Try --help for help.\n"); - return -1; - } + args->driver_name = argv[optind]; + optind++; return 0; } -device_t setup_device(const struct cmdline_args *args, - stab_t stab) -{ - device_t msp430_dev = NULL; - transport_t trans = NULL; - - /* Open a device */ - if (args->mode == MODE_SIM) { - msp430_dev = sim_open(fetch_io, store_io, stab); - } else if (args->mode == MODE_UIF_BSL) { - msp430_dev = bsl_open(args->devpath); - } else { - int flags = 0; - - /* Open the appropriate transport */ - if (args->mode == MODE_OLIMEX) { - trans = uif_open(args->devpath, 1); - flags |= FET_PROTO_OLIMEX; - } else if (args->mode == MODE_UIF) { - trans = uif_open(args->devpath, 0); - } else if (args->mode == MODE_OLIMEX_USB) { - trans = olimex_open(); - flags |= FET_PROTO_OLIMEX; - } else { - trans = rf2500_open(); - flags |= FET_PROTO_RF2500; - } - - if (!trans) - return NULL; - - /* Then initialize the device */ - if (!args->want_jtag) - flags |= FET_PROTO_SPYBIWIRE; - - msp430_dev = fet_open(trans, flags, args->vcc_mv, - args->fet_force_id); - } - - if (!msp430_dev) { - if (trans) - trans->destroy(trans); - return NULL; - } - - return msp430_dev; -} - -cproc_t setup_cproc(const struct cmdline_args *args) +cproc_t setup_cproc(struct cmdline_args *args) { + int i; device_t msp430_dev; stab_t stab; cproc_t cp; + i = 0; + while (i < ARRAY_LEN(driver_table) && + strcasecmp(driver_table[i].name, args->driver_name)) + i++; + if (i >= ARRAY_LEN(driver_table)) { + fprintf(stderr, "Unknown driver: %s. Try --help for a list.\n", + args->driver_name); + return NULL; + } + stab = stab_new(); if (!stab) return NULL; + args->stab = stab; - msp430_dev = setup_device(args, stab); + msp430_dev = driver_table[i].func(args); if (!msp430_dev) { stab_destroy(stab); return NULL; diff --git a/mspdebug.man b/mspdebug.man index b591bfe..d400073 100644 --- a/mspdebug.man +++ b/mspdebug.man @@ -2,21 +2,12 @@ .SH NAME MSPDebug - debugging tool for MSP430 MCUs .SH SYNOPSIS -\fBmspdebug\fR [options] \-R [\-v \fIvoltage\fR] [\fIcommand\fR ...] -.br -\fBmspdebug\fR [options] \-u \fIdevice\fR [\-j] [\-v \fIvoltage\fR] [\fIcommand\fR ...] -.br -\fBmspdebug\fR [options] \-O \fIdevice\fR [\-j] [\-v \fIvoltage\fR] [\fIcommand\fR ...] -.br -\fBmspdebug\fR [options] \-l [\-j] [\-v \fIvoltage\fR] [\fIcommand\fR ...] -.br -\fBmspdebug\fR [options] \-B \fIdevice\fR [\fIcommand\fR ...] -.br -\fBmspdebug\fR [options] \-s [\fIcommand\fR ...] +\fBmspdebug\fR [options] \fIdriver\fR [\fIcommand\fR ...] .SH DESCRIPTION MSPDebug is a command-line tool designed for debugging and programming -the MSP430 family of MCUs. It supports the eZ430-F2013, eZ430-RF2500 -and FET430UIF programming tools. +the MSP430 family of MCUs. It supports the eZ430-F2013, eZ430-RF2500, +FET430UIF and Olimex MSP-JTAG-TINY programming tools, as well as a +simulation mode. When started with appropriate options, MSPDebug will attempt to connect to the debugging tool specified and identify the device under @@ -39,42 +30,36 @@ commands are specified on the end of the command-line, then they are executed after connecting to the device, and the interactive prompt is not started. See the section labelled \fBCOMMANDS\fR for more information. -.IP "\-R" -Connect to an eZ430-RF2500 device. The USB bus will be searched for -the first available device. You must have write permission for usbfs -in order for this to work. You can achieve this by running as root -(not recommended), or by remounting usbfs using the -devuid/devgid/devmode options. .IP "\-v \fIvoltage\fR" Set the programming voltage. The voltage should be specified as an integer in millivolts. It defaults to 3000 (3.0 V). -.IP "\-u \fIdevice\fR" -Connect to an eZ430-F2013 or a FET430UIF device. The device argument -should be the filename of the appropriate tty device. The TI serial -converter chips on these devices are supported by newer versions of the -Linux kernel, and should appear as /dev/tty\fIXX\fR when attached. -.IP "\-O \fIdevice\fR" -Connect to an Olimex MSP430-JTAG-TINY device. The device argument -should be the filename of the appropriate tty device. -.IP "\-l" -Connect to an Olimex MSP430-JTAG-TINY device using libusb. The first -available device on the USB bus is claimed. .IP "\-j" Use JTAG instead of Spy-Bi-Wire to communicate with the MSP430. This option only works on FET430UIF devices. -.IP "\-B \fIdevice\fR" -Connect to the bootloader on a FET430UIF device. These devices contain -MSP430F419 chips. By sending a special command sequence, you can obtain -access to the bootloader and inspect memory on the MSP430F419 in the -programming device itself. - -Currently, only memory inspection is supported. CPU control via the -bootloader is not possible. Memory erase and write is possible, but is -currently not implemented, for lack of ability to test it. If implemented, -this would allow firmware updates to FET430UIF devices. - -The argument should be the filename of the appropriate tty device. -.IP "\-s" +.IP "\-d \fIdevice\fR" +Specify that the driver should connect via a tty device rather than USB. +The supported connection methods vary depending on the driver. See the +section \fBDRIVERS\fR below for details. +.IP "\-n" +Do not process the startup file (~/.mspdebug). +.IP "\-\-help" +Display a brief help message and exit. +.IP "\-\-fet\-list" +Display a list of devices supported by the FET driver (the driver used +for \fB\-R\fR and \fB\-u\fR operating modes). +.IP "\-\-fet\-force\-id \fIstring\fR" +When using a FET device, force the connected chip to be recognised by +MSPDebug as one of the given type during initialization. This overrides +the device ID returned by the FET. +.SH DRIVERS +A driver name must be specified on the command line for MSPDebug to +connect to. Valid driver names are listed here. +.IP "\fBrf2500\fR" +Connect to an eZ430-RF2500 device. Only USB connection is supported. +.IP "\fBolimex\fR" +Connect to an Olimex MSP-JTAG-TINY device. Both USB and tty access are +supported. +.IP "\fBsim\fR" Do not connect to any hardware device, but instead start in simulation mode. A 64k buffer is allocated to simulate the device memory. The CPU core alone is emulated (no peripheral emulation). @@ -94,17 +79,25 @@ execution. This mode is intended for testing of changes to MSPDebug, and for aiding the disassembly of MSP430 binaries (as all binary and symbol table formats are still usable in this mode). -.IP "\-n" -Do not process the startup file (~/.mspdebug). -.IP "\-\-help" -Display a brief help message and exit. -.IP "\-\-fet\-list" -Display a list of devices supported by the FET driver (the driver used -for \fB\-R\fR and \fB\-u\fR operating modes). -.IP "\-\-fet\-force\-id \fIstring\fR" -When using a FET device, force the connected chip to be recognised by -MSPDebug as one of the given type during initialization. This overrides -the device ID returned by the FET. +.IP "\fBuif\fR" +Connect to an eZ430-F2013 or a FET430UIF device. The device argument +should be the filename of the appropriate tty device. The TI serial +converter chips on these devices are supported by newer versions of the +Linux kernel, and should appear as /dev/tty\fIXX\fR when attached. + +USB connection is not supported for this driver. +.IP "\fBuif-bsl\fR" +Connect to the bootloader on a FET430UIF device. These devices contain +MSP430F419 chips. By sending a special command sequence, you can obtain +access to the bootloader and inspect memory on the MSP430F419 in the +programming device itself. + +Currently, only memory inspection is supported. CPU control via the +bootloader is not possible. Memory erase and write is possible, but is +currently not implemented, for lack of ability to test it. If implemented, +this would allow firmware updates to FET430UIF devices. + +USB connection is not supported for this driver. .SH COMMANDS MSPDebug can accept commands either through an interactive prompt, or non-interactively when specified on the command line. The supported