From 5bf7290268eee59f5d18def44193159cf88113d2 Mon Sep 17 00:00:00 2001
From: troth <troth@81a1dc3b-b13d-400b-aceb-764788c761c2>
Date: Tue, 29 Jul 2003 22:08:21 +0000
Subject: [PATCH] * avr.c: * avr.h: * avr910.c: * main.c: * stk500.c: New
 progress reporting implementation.

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@337 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog |  21 +++++++---
 avr.c     |  30 +++-----------
 avr.h     |   2 +
 avr910.c  |   6 +++
 main.c    | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 stk500.c  |  16 +-------
 6 files changed, 148 insertions(+), 46 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index ca90aadd..636a5e96 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,11 +1,20 @@
+2003-07-29  Theodore A. Roth  <troth@openavr.org>
+
+	* avr.c:
+	* avr.h:
+	* avr910.c:
+	* main.c:
+	* stk500.c:
+	New progress reporting implementation.
+
 2003-07-24  Joerg Wunsch  <j@uriah.heep.sax.de>
 
-	* avrdude.1
-	* doc/avrdude.texi
-	* pgm.c
-	* pgm.h
-	* stk500.c
-	* stk500_private.h
+	* avrdude.1:
+	* doc/avrdude.texi:
+	* pgm.c:
+	* pgm.h:
+	* stk500.c:
+	* stk500_private.h:
 	* term.c: Add support for displaying and setting the various
 	operational parameters of the STK500 (Vtarget, Varef, clock).
 
diff --git a/avr.c b/avr.c
index 0ee7285d..7da25bec 100644
--- a/avr.c
+++ b/avr.c
@@ -394,7 +394,6 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
   unsigned char  * buf;
   AVRMEM * mem;
   int rc;
-  int printed;
 
   mem = avr_locate_mem(p, memtype);
   if (mem == NULL) {
@@ -443,8 +442,6 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
     }
   }
 
-  printed = 0;
-
   for (i=0; i<size; i++) {
     rc = avr_read_byte(pgm, p, mem, i, &rbyte);
     if (rc != 0) {
@@ -456,16 +453,7 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
       return -2;
     }
     buf[i] = rbyte;
-    if (verbose) {
-      if ((i % 16 == 0)||(i == (size-1))) {
-        printed = 1;
-        fprintf(stderr, "\r        \r%6lu", i);
-      }
-    }
-  }
-
-  if (printed) {
-    fprintf(stderr, "\n");
+    report_progress(i, size, NULL);
   }
 
   if (strcasecmp(mem->desc, "flash") == 0)
@@ -738,7 +726,6 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
   unsigned char    data;
   int              werror;
   AVRMEM         * m;
-  int              printed;
 
   m = avr_locate_mem(p, memtype);
   if (m == NULL) {
@@ -749,7 +736,6 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
 
   pgm->err_led(pgm, OFF);
 
-  printed = 0;
   werror  = 0;
 
   wsize = m->size;
@@ -782,12 +768,8 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
 
   for (i=0; i<wsize; i++) {
     data = m->buf[i];
-    if (verbose) {
-      if ((i % 16 == 0)||(i == (wsize-1))) {
-        fprintf(stderr, "\r      \r%6lu", i);
-        printed = 1;
-      }
-    }
+    report_progress(i, wsize, NULL);
+
     rc = avr_write_byte(pgm, p, m, i, data);
     if (rc) {
       fprintf(stderr, " ***failed;  ");
@@ -825,10 +807,6 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
       pgm->err_led(pgm, ON);
     }
   }
-
-  if (printed)
-    fprintf(stderr, "\n");
-
   return i;
 }
 
@@ -841,6 +819,7 @@ int avr_signature(PROGRAMMER * pgm, AVRPART * p)
 {
   int rc;
 
+  report_progress (0,1,"Reading");
   rc = avr_read(pgm, p, "signature", 0, 0);
   if (rc < 0) {
     fprintf(stderr, 
@@ -848,6 +827,7 @@ int avr_signature(PROGRAMMER * pgm, AVRPART * p)
             progname, p->desc, rc);
     return -1;
   }
+  report_progress (1,1,NULL);
 
   return 0;
 }
diff --git a/avr.h b/avr.h
index c1c00ae3..c93efe97 100644
--- a/avr.h
+++ b/avr.h
@@ -86,4 +86,6 @@ int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles);;
 
 int avr_mem_hiaddr(AVRMEM * mem);
 
+extern void report_progress (int completed, int total, char *hdr);
+
 #endif
diff --git a/avr910.c b/avr910.c
index 2d48ac4e..ba4e73ba 100644
--- a/avr910.c
+++ b/avr910.c
@@ -535,6 +535,8 @@ static int avr910_paged_write_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
       page_addr = addr;
       page_bytes = page_size;
     }
+
+    report_progress (addr, max_addr, NULL);
   }
 
   /* If we didn't send the page wr cmd after the last byte written in the
@@ -571,6 +573,8 @@ static int avr910_paged_write_eeprom(PROGRAMMER * pgm, AVRPART * p,
     if (has_auto_incr_addr != 'Y') {
       avr910_set_addr(pgm, addr);
     }
+
+    report_progress (addr, max_addr, NULL);
   }
 
   return addr;
@@ -635,6 +639,8 @@ static int avr910_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
     if (has_auto_incr_addr != 'Y') {
       avr910_set_addr(pgm, addr);
     }
+
+    report_progress (addr, max_addr, NULL);
   }
 
   return addr * rd_size;
diff --git a/main.c b/main.c
index c1d50fc5..acb75fd1 100644
--- a/main.c
+++ b/main.c
@@ -92,6 +92,7 @@ void usage(void)
     "  -t                         Enter terminal mode.\n"
     "  -E <exitspec>[,<exitspec>] List programmer exit specifications.\n"
     "  -v                         Verbose output. -v -v for more.\n"
+    "  -q                         Quell progress output.\n"
     "  -?                         Display this usage.\n"
     "\navrdude project: <URL:http://savannah.nongnu.org/projects/avrdude>\n"
     ,progname);
@@ -253,7 +254,104 @@ void list_programmers(FILE * f, char * prefix, LISTID programmers)
   return;
 }
 
+typedef void (*FP_UpdateProgress)(int percent, 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;
+  int percent = (completed * 100) / total;
+
+  if (update_progress == NULL)
+    return;
+
+  if (hdr) {
+    last = 0;
+    update_progress (percent, hdr);
+  }
+
+  if (percent > 100)
+    percent = 100;
+
+  if (percent > last) {
+    last = percent;
+    update_progress (percent, hdr);
+  }
+
+  if (percent == 100)
+    last = 0;                   /* Get ready for next time. */
+}
+
+static void update_progress_tty (int percent, char *hdr)
+{
+  static char hashes[51];
+  static char *header;
+  static 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%%", header, hashes, percent);
+  }
+
+  if (percent == 100) {
+    last = 1;
+    fprintf (stderr, "\n\n");
+  }
+}
+
+static void update_progress_no_tty (int percent, char *hdr)
+{
+  static int last = 0;
+  int cnt = (percent>>1)*2;
+
+  if (hdr) {
+    fprintf (stderr, "\n%s | ", hdr);
+    last = 0;
+  }
+  else {
+    while (cnt > last) {
+      fprintf (stderr, "#");
+      cnt -=  2;
+    }
+  }
+
+  if ((percent == 100) && (last != 0)) {
+    fprintf (stderr, " | 100%\n\n");
+    last = 0;
+  }
+  else
+    last = (percent>>1)*2;    /* Make last a multiple of 2. */
+}
 
 /*
  * main routine
@@ -297,6 +395,7 @@ int main(int argc, char * argv [])
   int     set_cycles;  /* value to set the erase-rewrite cycles to */
   char  * e;           /* for strtol() error checking */
   char  * homedir;
+  int     quell_progress;
 
   progname = rindex(argv[0],'/');
   if (progname)
@@ -323,6 +422,7 @@ int main(int argc, char * argv [])
   filefmt       = FMT_AUTO;
   nowrite       = 0;
   verify        = 1;        /* on by default */
+  quell_progress = 0;
   ppisetbits    = 0;
   ppiclrbits    = 0;
   exitspecs     = NULL;
@@ -375,7 +475,7 @@ int main(int argc, char * argv [])
   /*
    * process command line arguments
    */
-  while ((ch = getopt(argc,argv,"?c:C:eE:f:Fi:I:m:no:p:P:tvVyY:")) != -1) {
+  while ((ch = getopt(argc,argv,"?c:C:eE:f:Fi:I:m:no:p:P:qtvVyY:")) != -1) {
 
     switch (ch) {
       case 'c': /* programmer id */
@@ -424,6 +524,10 @@ int main(int argc, char * argv [])
         partdesc = optarg;
         break;
 
+      case 'q' : /* Quell progress output */
+        quell_progress = 1;
+        break;
+
       case 'e': /* perform a chip erase */
         erase = 1;
         break;
@@ -524,6 +628,13 @@ int main(int argc, char * argv [])
 
   }
 
+  if (quell_progress == 0) {
+    if (isatty (STDERR_FILENO))
+      update_progress = update_progress_tty;
+    else
+      update_progress = update_progress_no_tty;
+  }
+
   if (verbose) {
     /*
      * Print out an identifying string so folks can tell what version
@@ -877,6 +988,7 @@ int main(int argc, char * argv [])
      */
     fprintf(stderr, "%s: reading %s memory:\n", 
             progname, memtype);
+    report_progress(0,1,"Reading");
     rc = avr_read(pgm, p, memtype, 0, 1);
     if (rc < 0) {
       fprintf(stderr, "%s: failed to read all of %s memory, rc=%d\n", 
@@ -884,6 +996,7 @@ int main(int argc, char * argv [])
       exitrc = 1;
       goto main_exit;
     }
+    report_progress(1,1,NULL);
     size = rc;
 
     fprintf(stderr, "%s: writing output file \"%s\"\n",
@@ -918,7 +1031,9 @@ int main(int argc, char * argv [])
             progname, memtype, size);
 
     if (!nowrite) {
+      report_progress(0,1,"Writing");
       rc = avr_write(pgm, p, memtype, size, 1);
+      report_progress(1,1,NULL);
     }
     else {
       /* 
@@ -953,6 +1068,7 @@ int main(int argc, char * argv [])
             progname, memtype, inputf);
     fprintf(stderr, "%s: reading on-chip %s data:\n", 
             progname, memtype);
+    report_progress (0,1,"Reading");
     rc = avr_read(pgm, v, memtype, vsize, 1);
     if (rc < 0) {
       fprintf(stderr, "%s: failed to read all of %s memory, rc=%d\n", 
@@ -961,6 +1077,7 @@ int main(int argc, char * argv [])
       exitrc = 1;
       goto main_exit;
     }
+    report_progress (1,1,NULL);
 
     fprintf(stderr, "%s: verifying ...\n", progname);
     rc = avr_verify(p, v, memtype, vsize);
diff --git a/stk500.c b/stk500.c
index 6b746dc9..cc4fe332 100644
--- a/stk500.c
+++ b/stk500.c
@@ -741,9 +741,7 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
 #endif     
 
   for (addr = 0; addr < n; addr += page_size) {
-    if (verbose) {
-      fprintf(stderr, "\r      \r%6u", addr);
-    }
+    report_progress (addr, n_bytes, NULL);
     tries = 0;
   retry:
     tries++;
@@ -787,10 +785,6 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
       return -5;
     }
   }
-  if (verbose) {
-    fprintf(stderr, "\r      \r%6u", addr-1);
-    fprintf(stderr, "\n");
-  }
 
   return n;
 }
@@ -835,9 +829,7 @@ static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
   }
 
   for (addr = 0; addr < n; addr += page_size) {
-    if (verbose) {
-      fprintf(stderr, "\r      \r%6u", addr);
-    }
+    report_progress (addr, n_bytes, NULL);
     tries = 0;
   retry:
     tries++;
@@ -878,10 +870,6 @@ static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
       return -5;
     }
   }
-  if (verbose) {
-    fprintf(stderr, "\r      \r%6u", addr-1);
-    fprintf(stderr, "\n");
-  }
 
   return n;
 }