main.c

来自「这是一个非常有价值的参考代码」· C语言 代码 · 共 1,580 行 · 第 1/3 页

C
1,580
字号
/* * avrdude - A Downloader/Uploader for AVR device programmers * Copyright (C) 2000-2005  Brian S. Dean <bsd@bsdhome.com> * * 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.c,v 1.110 2005/09/22 14:14:14 joerg_wunsch Exp $ *//* * Code to program an Atmel AVR device through one of the supported * programmers. * * For parallel port connected programmers, the pin definitions can be * changed via a config file.  See the config file for instructions on * how to add a programmer definition. *   */#include "ac_cfg.h"#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <fcntl.h>#include <limits.h>#include <string.h>#include <time.h>#include <unistd.h>#include <ctype.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/time.h>#include "avr.h"#include "config.h"#include "confwin.h"#include "fileio.h"#include "lists.h"#include "par.h"#include "pindefs.h"#include "term.h"#include "safemode.h"enum {  DEVICE_READ,   DEVICE_WRITE,  DEVICE_VERIFY};typedef struct update_t {  char * memtype;  int    op;  char * filename;  int    format;} UPDATE;/* Get VERSION from ac_cfg.h */char * version      = VERSION;int    verbose;     /* verbose output */int    quell_progress; /* un-verebose output */char * progname;char   progbuf[PATH_MAX]; /* temporary buffer of spaces the same                             length as progname; used for lining up                             multiline messages */PROGRAMMER * pgm = NULL;LISTID updates;/* * global options */int do_cycles;   /* track erase-rewrite cycles *//* * usage message */void usage(void){  fprintf(stderr, "Usage: %s [options]\n" "Options:\n" "  -p <partno>                Required. Specify AVR device.\n" "  -b <baudrate>              Override RS-232 baud rate.\n" "  -B <bitclock>              Specify JTAG bit clock period (us).\n" "  -C <config-file>           Specify location of configuration file.\n" "  -c <programmer>            Specify programmer type.\n" "  -D                         Disable auto erase for flash memory\n" "  -P <port>                  Specify connection port.\n" "  -F                         Override invalid signature check.\n" "  -e                         Perform a chip erase.\n" "  -U <memtype>:r|w|v:<filename>[:format]\n" "                             Memory operation specification.\n" "                             Multiple -U options are allowed, each request\n" "                             is performed in the order specified.\n" "  -n                         Do not write anything to the device.\n" "  -V                         Do not verify.\n" "  -u                         Disable safemode, default when running from a script.\n" "  -s                         Silent safemode operation, will not ask you if\n" "                             fuses should be changed back.\n" "  -t                         Enter terminal mode.\n" "  -E <exitspec>[,<exitspec>] List programmer exit specifications.\n" "  -y                         Count # erase cycles in EEPROM.\n" "  -Y <number>                Initialize erase cycle # in EEPROM.\n" "  -v                         Verbose output. -v -v for more.\n" "  -q                         Quell progress output. -q -q for less.\n" "  -?                         Display this usage.\n" "\navrdude project: <URL:http://savannah.nongnu.org/projects/avrdude>\n"          ,progname);}/* * parse the -E string */int getexitspecs(char *s, int *set, int *clr){  char *cp;  while ((cp = strtok(s, ","))) {    if (strcmp(cp, "reset") == 0) {      *clr |= par_getpinmask(pgm->pinno[PIN_AVR_RESET]);    }    else if (strcmp(cp, "noreset") == 0) {      *set |= par_getpinmask(pgm->pinno[PIN_AVR_RESET]);    }    else if (strcmp(cp, "vcc") == 0) {      if (pgm->pinno[PPI_AVR_VCC])        *set |= pgm->pinno[PPI_AVR_VCC];    }    else if (strcmp(cp, "novcc") == 0) {      if (pgm->pinno[PPI_AVR_VCC])        *clr |= pgm->pinno[PPI_AVR_VCC];    }    else {      return -1;    }    s = 0; /* strtok() should be called with the actual string only once */  }  return 0;}int read_config(char * file){  FILE * f;  f = fopen(file, "r");  if (f == NULL) {    fprintf(stderr, "%s: can't open config file \"%s\": %s\n",            progname, file, strerror(errno));    return -1;  }  lineno = 1;  infile = file;  yyin   = f;  yyparse();  fclose(f);  return 0;}void programmer_display(char * p){  fprintf(stderr, "%sProgrammer Type : %s\n", p, pgm->type);  fprintf(stderr, "%sDescription     : %s\n", p, pgm->desc);  pgm->display(pgm, p);}void verify_pin_assigned(int pin, char * desc){  if (pgm->pinno[pin] == 0) {    fprintf(stderr, "%s: error: no pin has been assigned for %s\n",            progname, desc);    exit(1);  }}PROGRAMMER * locate_programmer(LISTID programmers, char * configid){  LNODEID ln1, ln2;  PROGRAMMER * p = NULL;  char * id;  int found;  found = 0;  for (ln1=lfirst(programmers); ln1 && !found; ln1=lnext(ln1)) {    p = ldata(ln1);    for (ln2=lfirst(p->id); ln2 && !found; ln2=lnext(ln2)) {      id = ldata(ln2);      if (strcasecmp(configid, id) == 0)        found = 1;    }    }  if (found)    return p;  return NULL;}void list_programmers(FILE * f, char * prefix, LISTID programmers){  LNODEID ln1;  PROGRAMMER * p;  for (ln1=lfirst(programmers); ln1; ln1=lnext(ln1)) {    p = ldata(ln1);    fprintf(f, "%s%-8s = %-30s [%s:%d]\n",            prefix, (char *)ldata(lfirst(p->id)), p->desc,            p->config_file, p->lineno);  }  return;}typedef void (*FP_UpdateProgress)(int percent, double etime, char *hdr);static FP_UpdateProgress update_progress;/* * Report the progress of a read or write operation from/to the * device. *  * The first call of report_progress() should look like this (for a write op): *  * report_progress (0, 1, "Writing"); * * Then hdr should be passed NULL on subsequent calls while the * operation is progressing. Once the operation is complete, a final * call should be made as such to ensure proper termination of the * progress report: *  * report_progress (1, 1, NULL); * * It would be nice if we could reduce the usage to one and only one * call for each of start, during and end cases. As things stand now, * that is not possible and makes maintenance a bit more work. */void report_progress (int completed, int total, char *hdr){  static int last = 0;  static double start_time;  int percent = (completed * 100) / total;  struct timeval tv;  double t;  if (update_progress == NULL)    return;  gettimeofday(&tv, NULL);  t = tv.tv_sec + ((double)tv.tv_usec)/1000000;  if (hdr) {    last = 0;    start_time = t;    update_progress (percent, t - start_time, hdr);  }  if (percent > 100)    percent = 100;  if (percent > last) {    last = percent;    update_progress (percent, t - start_time, hdr);  }  if (percent == 100)    last = 0;                   /* Get ready for next time. */}static void update_progress_tty (int percent, double etime, char *hdr){  static char hashes[51];  static char *header;  static int last = 0;  int i;  hashes[50] = 0;  memset (hashes, ' ', 50);  for (i=0; i<percent; i+=2) {    hashes[i/2] = '#';  }  if (hdr) {    fprintf (stderr, "\n");    last = 0;    header = hdr;  }  if (last == 0) {    fprintf(stderr, "\r%s | %s | %d%% %0.2fs",             header, hashes, percent, etime);  }  if (percent == 100) {    last = 1;    fprintf (stderr, "\n\n");  }}static void update_progress_no_tty (int percent, double etime, char *hdr){  static int done = 0;  static int last = 0;  int cnt = (percent>>1)*2;  if (hdr) {    fprintf (stderr, "\n%s | ", hdr);    last = 0;    done = 0;  }  else {    while ((cnt > last) && (done == 0)) {      fprintf (stderr, "#");      cnt -=  2;    }  }  if ((percent == 100) && (done == 0)) {    fprintf (stderr, " | 100%% %0.2fs\n\n", etime);    last = 0;    done = 1;  }  else    last = (percent>>1)*2;    /* Make last a multiple of 2. */}UPDATE * parse_op(char * s){  char buf[1024];  char * p, * cp, c;  UPDATE * upd;  int i;  size_t fnlen;  upd = (UPDATE *)malloc(sizeof(UPDATE));  if (upd == NULL) {    fprintf(stderr, "%s: out of memory\n", progname);    exit(1);  }  i = 0;  p = s;  while ((i < (sizeof(buf)-1) && *p && (*p != ':')))    buf[i++] = *p++;    if (*p != ':') {    fprintf(stderr, "%s: invalid update specification\n", progname);    free(upd);    return NULL;  }  buf[i] = 0;  upd->memtype = (char *)malloc(strlen(buf)+1);  if (upd->memtype == NULL) {    fprintf(stderr, "%s: out of memory\n", progname);    exit(1);  }  strcpy(upd->memtype, buf);  p++;  if (*p == 'r') {    upd->op = DEVICE_READ;  }  else if (*p == 'w') {    upd->op = DEVICE_WRITE;  }  else if (*p == 'v') {    upd->op = DEVICE_VERIFY;  }  else {    fprintf(stderr, "%s: invalid I/O mode '%c' in update specification\n",            progname, *p);    fprintf(stderr,             "  allowed values are:\n"            "    r = read device\n"            "    w = write device\n"            "    v = verify device\n");    free(upd->memtype);    free(upd);    return NULL;  }  p++;  if (*p != ':') {    fprintf(stderr, "%s: invalid update specification\n", progname);    free(upd->memtype);    free(upd);    return NULL;  }  p++;  /*   * Now, parse the filename component.  Instead of looking for the   * leftmost possible colon delimiter, we look for the rightmost one.   * If we found one, we do have a trailing :format specifier, and   * process it.  Otherwise, the remainder of the string is our file   * name component.  That way, the file name itself is allowed to   * contain a colon itself (e. g. C:/some/file.hex), except the   * optional format specifier becomes mandatory then.   */  cp = p;  p = strrchr(cp, ':');  if (p == NULL) {    upd->format = FMT_AUTO;    fnlen = strlen(cp);    upd->filename = (char *)malloc(fnlen + 1);  } else {    fnlen = p - cp;    upd->filename = (char *)malloc(fnlen +1);    c = *++p;    if (c && p[1])      /* More than one char - force failure below. */      c = '?';    switch (c) {      case 'a': upd->format = FMT_AUTO; break;      case 's': upd->format = FMT_SREC; break;      case 'i': upd->format = FMT_IHEX; break;      case 'r': upd->format = FMT_RBIN; break;      case 'm': upd->format = FMT_IMM; break;      default:        fprintf(stderr, "%s: invalid file format '%s' in update specifier\n",                progname, p);        free(upd->memtype);        free(upd);        return NULL;    }  }  if (upd->filename == NULL) {    fprintf(stderr, "%s: out of memory\n", progname);    free(upd->memtype);    free(upd);    return NULL;  }  memcpy(upd->filename, cp, fnlen);  upd->filename[fnlen] = 0;  return upd;}UPDATE * dup_update(UPDATE * upd){  UPDATE * u;  u = (UPDATE *)malloc(sizeof(UPDATE));  if (u == NULL) {    fprintf(stderr, "%s: out of memory\n", progname);    exit(1);  }  memcpy(u, upd, sizeof(UPDATE));  u->memtype = strdup(upd->memtype);  u->filename = strdup(upd->filename);  return u;}UPDATE * new_update(int op, char * memtype, int filefmt, char * filename){  UPDATE * u;  u = (UPDATE *)malloc(sizeof(UPDATE));  if (u == NULL) {    fprintf(stderr, "%s: out of memory\n", progname);    exit(1);  }  u->memtype = strdup(memtype);  u->filename = strdup(filename);  u->op = op;  u->format = filefmt;    return u;}int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, int nowrite,          int verify){  struct avrpart * v;  AVRMEM * mem;  int size, vsize;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?