Merge pull request #1053 from stefanrueger/main

Enable stdin verification and display correct number of bytes written/verified
This commit is contained in:
Stefan Rueger 2022-08-04 17:58:15 +01:00 committed by GitHub
commit 5f01d900f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 322 additions and 149 deletions

View File

@ -1222,6 +1222,54 @@ int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles)
return 0; return 0;
} }
// Typical order in which memories show in avrdude.conf, runtime adds unknown ones (if any)
const char *avr_mem_order[100] = {
"eeprom", "flash", "application", "apptable",
"boot", "lfuse", "hfuse", "efuse",
"fuse", "fuse0", "wdtcfg", "fuse1",
"bodcfg", "fuse2", "osccfg", "fuse3",
"fuse4", "tcd0cfg", "fuse5", "syscfg0",
"fuse6", "syscfg1", "fuse7", "append",
"codesize", "fuse8", "fuse9", "bootend",
"bootsize", "fuses", "lock", "lockbits",
"tempsense", "signature", "prodsig", "sernum",
"calibration", "osccal16", "osccal20", "osc16err",
"osc20err", "usersig", "userrow", "data",
};
void avr_add_mem_order(const char *str) {
for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++) {
if(avr_mem_order[i] && !strcmp(avr_mem_order[i], str))
return;
if(!avr_mem_order[i]) {
avr_mem_order[i] = strdup(str);
return;
}
}
avrdude_message(MSG_INFO,
"%s: avr_mem_order[] under-dimensioned in avr.c; increase and recompile\n",
progname);
exit(1);
}
int avr_mem_is_known(const char *str) {
if(str && *str)
for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++)
if(avr_mem_order[i] && !strcmp(avr_mem_order[i], str))
return 1;
return 0;
}
int avr_mem_might_be_known(const char *str) {
if(str && *str)
for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++)
if(avr_mem_order[i] && !strncmp(avr_mem_order[i], str, strlen(str)))
return 1;
return 0;
}
int avr_chip_erase(PROGRAMMER * pgm, AVRPART * p) int avr_chip_erase(PROGRAMMER * pgm, AVRPART * p)
{ {
int rc; int rc;

View File

@ -1320,6 +1320,7 @@ part_parm :
mem->desc[AVR_MEMDESCLEN-1] = 0; mem->desc[AVR_MEMDESCLEN-1] = 0;
ladd(current_part->mem, mem); ladd(current_part->mem, mem);
} }
avr_add_mem_order($2->value.string);
current_mem = mem; current_mem = mem;
free_token($2); free_token($2);
} }

View File

@ -280,35 +280,6 @@ static void dev_stack_out(bool tsv, AVRPART *p, const char *name, unsigned char
} }
// order in which memories are processed, runtime adds unknown ones (but there shouldn't be any)
static const char *mem_order[100] = {
"eeprom", "flash", "application", "apptable",
"boot", "lfuse", "hfuse", "efuse",
"fuse", "fuse0", "wdtcfg", "fuse1",
"bodcfg", "fuse2", "osccfg", "fuse3",
"fuse4", "tcd0cfg", "fuse5", "syscfg0",
"fuse6", "syscfg1", "fuse7", "append",
"codesize", "fuse8", "fuse9", "bootend",
"bootsize", "fuses", "lock", "lockbits",
"tempsense", "signature", "prodsig", "sernum",
"calibration", "osccal16", "osccal20", "osc16err",
"osc20err", "usersig", "userrow", "data",
};
static void add_mem_order(const char *str) {
for(size_t i=0; i < sizeof mem_order/sizeof *mem_order; i++) {
if(mem_order[i] && !strcmp(mem_order[i], str))
return;
if(!mem_order[i]) {
mem_order[i] = strdup(str);
return;
}
}
dev_info("%s: mem_order[] under-dimensioned in developer_opts.c; increase and recompile\n", progname);
exit(1);
}
static int intcmp(int a, int b) { static int intcmp(int a, int b) {
return a-b; return a-b;
} }
@ -410,8 +381,8 @@ static int avrpart_deep_copy(AVRPARTdeep *d, AVRPART *p) {
// fill in all memories we got in defined order // fill in all memories we got in defined order
di = 0; di = 0;
for(size_t mi=0; mi < sizeof mem_order/sizeof *mem_order && mem_order[mi]; mi++) { for(size_t mi=0; mi < sizeof avr_mem_order/sizeof *avr_mem_order && avr_mem_order[mi]; mi++) {
m = p->mem? avr_locate_mem(p, mem_order[mi]): NULL; m = p->mem? avr_locate_mem(p, avr_mem_order[mi]): NULL;
if(m) { if(m) {
if(di >= sizeof d->mems/sizeof *d->mems) { if(di >= sizeof d->mems/sizeof *d->mems) {
avrdude_message(MSG_INFO, "%s: ran out of mems[] space, increase size in AVRMEMdeep of developer_opts.c and recompile\n", progname); avrdude_message(MSG_INFO, "%s: ran out of mems[] space, increase size in AVRMEMdeep of developer_opts.c and recompile\n", progname);
@ -566,11 +537,11 @@ static void dev_part_strct(AVRPART *p, bool tsv, AVRPART *base) {
if(!base || opcodecmp(p->op[i], base->op[i], i)) if(!base || opcodecmp(p->op[i], base->op[i], i))
dev_part_strct_entry(tsv, ".ptop", p->desc, "part", opcodename(i), opcode2str(p->op[i], i, !tsv)); dev_part_strct_entry(tsv, ".ptop", p->desc, "part", opcodename(i), opcode2str(p->op[i], i, !tsv));
for(size_t mi=0; mi < sizeof mem_order/sizeof *mem_order && mem_order[mi]; mi++) { for(size_t mi=0; mi < sizeof avr_mem_order/sizeof *avr_mem_order && avr_mem_order[mi]; mi++) {
AVRMEM *m, *bm; AVRMEM *m, *bm;
m = p->mem? avr_locate_mem(p, mem_order[mi]): NULL; m = p->mem? avr_locate_mem(p, avr_mem_order[mi]): NULL;
bm = base && base->mem? avr_locate_mem(base, mem_order[mi]): NULL; bm = base && base->mem? avr_locate_mem(base, avr_mem_order[mi]): NULL;
if(!m && bm && !tsv) if(!m && bm && !tsv)
dev_info("\n memory \"%s\" = NULL;\n", bm->desc); dev_info("\n memory \"%s\" = NULL;\n", bm->desc);
@ -694,12 +665,12 @@ void dev_output_part_defs(char *partdesc) {
AVRPART *p = ldata(ln1); AVRPART *p = ldata(ln1);
if(p->mem) if(p->mem)
for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm)) for(LNODEID lnm=lfirst(p->mem); lnm; lnm=lnext(lnm))
add_mem_order(((AVRMEM *) ldata(lnm))->desc); avr_add_mem_order(((AVRMEM *) ldata(lnm))->desc);
// same for aliased memories (though probably not needed) // same for aliased memories (though probably not needed)
if(p->mem_alias) if(p->mem_alias)
for(LNODEID lnm=lfirst(p->mem_alias); lnm; lnm=lnext(lnm)) for(LNODEID lnm=lfirst(p->mem_alias); lnm; lnm=lnext(lnm))
add_mem_order(((AVRMEM_ALIAS *) ldata(lnm))->desc); avr_add_mem_order(((AVRMEM_ALIAS *) ldata(lnm))->desc);
} }
nprinted = dev_nprinted; nprinted = dev_nprinted;

View File

@ -783,6 +783,7 @@ void sort_programmers(LISTID programmers);
typedef void (*FP_UpdateProgress)(int percent, double etime, char *hdr); typedef void (*FP_UpdateProgress)(int percent, double etime, char *hdr);
extern struct avrpart parts[]; extern struct avrpart parts[];
extern const char *avr_mem_order[100];
extern FP_UpdateProgress update_progress; extern FP_UpdateProgress update_progress;
@ -818,6 +819,11 @@ int avr_get_cycle_count(PROGRAMMER * pgm, AVRPART * p, int * cycles);
int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles); int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles);
void avr_add_mem_order(const char *str);
int avr_mem_is_known(const char *str);
int avr_mem_might_be_known(const char *str);
#define disable_trailing_ff_removal() avr_mem_hiaddr(NULL) #define disable_trailing_ff_removal() avr_mem_hiaddr(NULL)
int avr_mem_hiaddr(AVRMEM * mem); int avr_mem_hiaddr(AVRMEM * mem);
@ -888,6 +894,7 @@ enum updateflags {
UF_NONE = 0, UF_NONE = 0,
UF_NOWRITE = 1, UF_NOWRITE = 1,
UF_AUTO_ERASE = 2, UF_AUTO_ERASE = 2,
UF_VERIFY = 4,
}; };
@ -898,6 +905,17 @@ typedef struct update_t {
int format; int format;
} UPDATE; } UPDATE;
typedef struct { // File reads for flash can exclude trailing 0xff, which are cut off
int nbytes, // Number of bytes set including 0xff but excluding cut off, trailing 0xff
nsections, // Number of consecutive sections in source excluding cut off, trailing 0xff
npages, // Number of memory pages needed excluding pages solely with trailing 0xff
nfill, // Number of fill bytes to make up full pages that are needed
ntrailing, // Number of trailing 0xff in source
firstaddr, // First address set in [0, mem->size-1]
lastaddr; // Highest address set by input file
} Filestats;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -910,6 +928,14 @@ extern void free_update(UPDATE * upd);
extern int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, extern int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd,
enum updateflags flags); enum updateflags flags);
extern int memstats(struct avrpart *p, char *memtype, int size, Filestats *fsp);
// Convenience functions for printing
const char *plural(int x);
const char *inname(const char *fn);
const char *outname(const char *fn);
const char *interval(int a, int b);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -237,7 +237,7 @@ static void cleanup_main(void)
static void replace_backslashes(char *s) static void replace_backslashes(char *s)
{ {
// Replace all backslashes with forward slashes // Replace all backslashes with forward slashes
for (int i = 0; i < strlen(s); i++) { for (size_t i = 0; i < strlen(s); i++) {
if (s[i] == '\\') { if (s[i] == '\\') {
s[i] = '/'; s[i] = '/';
} }
@ -267,7 +267,6 @@ int main(int argc, char * argv [])
int calibrate; /* 1=calibrate RC oscillator, 0=don't */ int calibrate; /* 1=calibrate RC oscillator, 0=don't */
char * port; /* device port (/dev/xxx) */ char * port; /* device port (/dev/xxx) */
int terminal; /* 1=enter terminal mode, 0=don't */ int terminal; /* 1=enter terminal mode, 0=don't */
int verify; /* perform a verify operation */
char * exitspecs; /* exit specs string from command line */ char * exitspecs; /* exit specs string from command line */
char * programmer; /* programmer id */ char * programmer; /* programmer id */
char * partdesc; /* part id */ char * partdesc; /* part id */
@ -284,7 +283,7 @@ int main(int argc, char * argv [])
int init_ok; /* Device initialization worked well */ int init_ok; /* Device initialization worked well */
int is_open; /* Device open succeeded */ int is_open; /* Device open succeeded */
char * logfile; /* Use logfile rather than stderr for diagnostics */ char * logfile; /* Use logfile rather than stderr for diagnostics */
enum updateflags uflags = UF_AUTO_ERASE; /* Flags for do_op() */ enum updateflags uflags = UF_AUTO_ERASE | UF_VERIFY; /* Flags for do_op() */
#if !defined(WIN32) #if !defined(WIN32)
char * homedir; char * homedir;
@ -349,7 +348,6 @@ int main(int argc, char * argv [])
p = NULL; p = NULL;
ovsigck = 0; ovsigck = 0;
terminal = 0; terminal = 0;
verify = 1; /* on by default */
quell_progress = 0; quell_progress = 0;
exitspecs = NULL; exitspecs = NULL;
pgm = NULL; pgm = NULL;
@ -525,12 +523,6 @@ int main(int argc, char * argv [])
exit(1); exit(1);
} }
ladd(updates, upd); ladd(updates, upd);
if (verify && upd->op == DEVICE_WRITE) {
upd = dup_update(upd);
upd->op = DEVICE_VERIFY;
ladd(updates, upd);
}
break; break;
case 'v': case 'v':
@ -538,7 +530,7 @@ int main(int argc, char * argv [])
break; break;
case 'V': case 'V':
verify = 0; uflags &= ~UF_VERIFY;
break; break;
case 'x': case 'x':
@ -759,6 +751,7 @@ int main(int argc, char * argv [])
bitclock = default_bitclock; bitclock = default_bitclock;
} }
avrdude_message(MSG_NOTICE, "\n"); avrdude_message(MSG_NOTICE, "\n");
// developer option -p <wildcard>/[*codws] prints various aspects of part descriptions and exits // developer option -p <wildcard>/[*codws] prints various aspects of part descriptions and exits
@ -926,6 +919,12 @@ int main(int argc, char * argv [])
exit(1); exit(1);
} }
} }
if (!avr_mem_might_be_known(upd->memtype)) {
avrdude_message(MSG_INFO, "%s: unknown memory type %s\n", progname, upd->memtype);
exit(1);
}
// TODO: check whether filename other than "-" is readable/writable
} }
/* /*
@ -1251,7 +1250,7 @@ int main(int argc, char * argv [])
for (ln=lfirst(updates); ln; ln=lnext(ln)) { for (ln=lfirst(updates); ln; ln=lnext(ln)) {
upd = ldata(ln); upd = ldata(ln);
rc = do_op(pgm, p, upd, uflags); rc = do_op(pgm, p, upd, uflags);
if (rc) { if (rc && rc != LIBAVRDUDE_SOFTFAIL) {
exitrc = 1; exitrc = 1;
break; break;
} }

View File

@ -45,7 +45,7 @@ UPDATE * parse_op(char * s)
i = 0; i = 0;
p = s; p = s;
while ((i < (sizeof(buf)-1) && *p && (*p != ':'))) while (i < (int) sizeof(buf)-1 && *p && *p != ':')
buf[i++] = *p++; buf[i++] = *p++;
buf[i] = 0; buf[i] = 0;
@ -214,18 +214,124 @@ void free_update(UPDATE * u)
} }
// Memory statistics considering holes after a file read returned size bytes
int memstats(struct avrpart *p, char *memtype, int size, Filestats *fsp) {
Filestats ret = { 0 };
AVRMEM *mem = avr_locate_mem(p, memtype);
if(!mem) {
avrdude_message(MSG_INFO, "%s: %s %s undefined\n",
progname, p->desc, memtype);
return LIBAVRDUDE_GENERAL_FAILURE;
}
if(!mem->buf || !mem->tags) {
avrdude_message(MSG_INFO, "%s: %s %s is not set\n",
progname, p->desc, memtype);
return LIBAVRDUDE_GENERAL_FAILURE;
}
int pgsize = mem->page_size;
if(pgsize < 1)
pgsize = 1;
if(size < 0 || size > mem->size) {
avrdude_message(MSG_INFO, "%s: memstats() size %d at odds with %s %s size %d\n",
progname, size, p->desc, memtype, mem->size);
return LIBAVRDUDE_GENERAL_FAILURE;
}
ret.lastaddr = -1;
int firstset = 0, insection = 0;
// Scan all memory
for(int addr = 0; addr < mem->size; ) {
int pageset = 0;
// Go page by page
for(int pgi = 0; pgi < pgsize; pgi++, addr++) {
if(mem->tags[addr] & TAG_ALLOCATED) {
if(!firstset) {
firstset = 1;
ret.firstaddr = addr;
}
ret.lastaddr = addr;
// size can be smaller than tags suggest owing to flash trailing-0xff
if(addr < size) {
ret.nbytes++;
if(!pageset) {
pageset = 1;
ret.nfill += pgi;
ret.npages++;
}
if(!insection) {
insection = 1;
ret.nsections++;
}
} else { // Now beyond size returned by input file read
ret.ntrailing++;
if(pageset)
ret.nfill++;
}
} else { // In a hole or beyond input file
insection = 0;
if(pageset)
ret.nfill++;
}
}
}
if(fsp)
*fsp = ret;
return LIBAVRDUDE_SUCCESS;
}
// Convenience functions for printing
const char *plural(int x) {
return x==1? "": "s";
}
const char *inname(const char *fn) {
return !fn? "???": strcmp(fn, "-")? fn: "<stdin>";
}
const char *outname(const char *fn) {
return !fn? "???": strcmp(fn, "-")? fn: "<stdout>";
}
// Return sth like "[0, 0x1ff]"
const char *interval(int a, int b) {
// Cyclic buffer for 20+ temporary interval strings each max 41 bytes at 64-bit int
static char space[20*41 + 80], *sp;
if(!sp || sp-space > (int) sizeof space - 80)
sp = space;
char *ret = sp;
sprintf(sp, a<16? "[%d": "[0x%x", a);
sp += strlen(sp);
sprintf(sp, b<16? ", %d]": ", 0x%x]", b);
// Advance beyond return string in temporary ring buffer
sp += strlen(sp)+1;
return ret;
}
int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags flags) int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags flags)
{ {
struct avrpart * v; struct avrpart * v;
AVRMEM * mem; AVRMEM * mem;
int size, vsize; int size;
int rc; int rc;
Filestats fs;
mem = avr_locate_mem(p, upd->memtype); mem = avr_locate_mem(p, upd->memtype);
if (mem == NULL) { if (mem == NULL) {
avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n", avrdude_message(MSG_INFO, "%s: skipping -U %s:... as memory not defined for part %s\n",
upd->memtype, p->desc); progname, upd->memtype, p->desc);
return -1; return LIBAVRDUDE_SOFTFAIL;
} }
AVRMEM_ALIAS * alias_mem = avr_find_memalias(p, mem); AVRMEM_ALIAS * alias_mem = avr_find_memalias(p, mem);
@ -235,167 +341,189 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
strcat(alias_mem_desc, alias_mem->desc); strcat(alias_mem_desc, alias_mem->desc);
} }
if (upd->op == DEVICE_READ) { switch (upd->op) {
/* case DEVICE_READ:
* read out the specified device memory and write it to a file // Read out the specified device memory and write it to a file
*/
if (upd->format == FMT_IMM) { if (upd->format == FMT_IMM) {
avrdude_message(MSG_INFO, avrdude_message(MSG_INFO,
"%s: Invalid file format 'immediate' for output\n", "%s: Invalid file format 'immediate' for output\n", progname);
progname, upd->filename); return LIBAVRDUDE_GENERAL_FAILURE;
return -1;
} }
if (quell_progress < 2) { if (quell_progress < 2)
avrdude_message(MSG_INFO, "%s: reading %s%s memory:\n", avrdude_message(MSG_INFO, "%s: reading %s%s memory ...\n",
progname, mem->desc, alias_mem_desc); progname, mem->desc, alias_mem_desc);
}
report_progress(0, 1, "Reading"); report_progress(0, 1, "Reading");
rc = avr_read(pgm, p, upd->memtype, 0); rc = avr_read(pgm, p, upd->memtype, 0);
report_progress(1, 1, NULL);
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: failed to read all of %s%s memory, rc=%d\n", avrdude_message(MSG_INFO, "%s: failed to read all of %s%s memory, rc=%d\n",
progname, mem->desc, alias_mem_desc, rc); progname, mem->desc, alias_mem_desc, rc);
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
} }
report_progress(1,1,NULL);
size = rc; size = rc;
if (quell_progress < 2) { if (quell_progress < 2) {
if (rc == 0) if (rc == 0)
avrdude_message(MSG_INFO, "%s: Flash is empty, resulting file has no contents.\n", avrdude_message(MSG_INFO, "%s: flash is empty, resulting file has no contents\n",
progname); progname);
avrdude_message(MSG_INFO, "%s: writing output file \"%s\"\n", avrdude_message(MSG_INFO, "%s: writing output file %s\n",
progname, progname, outname(upd->filename));
strcmp(upd->filename, "-")==0 ? "<stdout>" : upd->filename);
} }
rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size); rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size);
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: write to file '%s' failed\n", avrdude_message(MSG_INFO, "%s: write to file %s failed\n",
progname, upd->filename); progname, outname(upd->filename));
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
}
}
else if (upd->op == DEVICE_WRITE) {
/*
* write the selected device memory using data from a file; first
* read the data from the specified file
*/
if (quell_progress < 2) {
avrdude_message(MSG_INFO, "%s: reading input file \"%s\"\n",
progname,
strcmp(upd->filename, "-")==0 ? "<stdin>" : upd->filename);
} }
break;
case DEVICE_WRITE:
// Write the selected device memory using data from a file
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1); rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
if (quell_progress < 2)
avrdude_message(MSG_INFO, "%s: reading input file %s for %s%s\n",
progname, inname(upd->filename), mem->desc, alias_mem_desc);
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n", avrdude_message(MSG_INFO, "%s: read from file %s failed\n",
progname, upd->filename); progname, inname(upd->filename));
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
} }
size = rc; size = rc;
/* if(memstats(p, upd->memtype, size, &fs) < 0)
* write the buffer contents to the selected memory type return LIBAVRDUDE_GENERAL_FAILURE;
*/
if(quell_progress < 2) { if(quell_progress < 2) {
avrdude_message(MSG_INFO, "%s: writing %s%s (%d bytes):\n", int level = fs.nsections > 1 || fs.firstaddr > 0 || fs.ntrailing? MSG_INFO: MSG_NOTICE;
progname, mem->desc, alias_mem_desc, size);
avrdude_message(level, "%*s with %d byte%s in %d section%s within %s\n",
(int) strlen(progname)+1, "",
fs.nbytes, plural(fs.nbytes),
fs.nsections, plural(fs.nsections),
interval(fs.firstaddr, fs.lastaddr));
if(mem->page_size > 1) {
avrdude_message(level, "%*s using %d page%s and %d pad byte%s",
(int) strlen(progname)+1, "",
fs.npages, plural(fs.npages),
fs.nfill, plural(fs.nfill));
if(fs.ntrailing)
avrdude_message(level, ", cutting off %d trailing 0xff byte%s",
fs.ntrailing, plural(fs.ntrailing));
avrdude_message(level, "\n");
} }
}
// Write the buffer contents to the selected memory type
if (quell_progress < 2)
avrdude_message(MSG_INFO, "%s: writing %d byte%s %s%s ...\n",
progname, fs.nbytes, plural(fs.nbytes), mem->desc, alias_mem_desc);
if (!(flags & UF_NOWRITE)) { if (!(flags & UF_NOWRITE)) {
report_progress(0, 1, "Writing"); report_progress(0, 1, "Writing");
rc = avr_write(pgm, p, upd->memtype, size, (flags & UF_AUTO_ERASE) != 0); rc = avr_write(pgm, p, upd->memtype, size, (flags & UF_AUTO_ERASE) != 0);
report_progress(1, 1, NULL); report_progress(1, 1, NULL);
} } else {
else { // Test mode: write to stdout in intel hex rather than to the chip
/*
* test mode, don't actually write to the chip, output the buffer
* to stdout in intel hex instead
*/
rc = fileio(FIO_WRITE, "-", FMT_IHEX, p, upd->memtype, size); rc = fileio(FIO_WRITE, "-", FMT_IHEX, p, upd->memtype, size);
} }
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: failed to write %s%s memory, rc=%d\n", avrdude_message(MSG_INFO, "%s: failed to write %s%s memory, rc=%d\n",
progname, mem->desc, alias_mem_desc, rc); progname, mem->desc, alias_mem_desc, rc);
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
} }
vsize = rc; if (quell_progress < 2)
avrdude_message(MSG_INFO, "%s: %d byte%s of %s%s written\n",
progname, fs.nbytes, plural(fs.nbytes), mem->desc, alias_mem_desc);
if (quell_progress < 2) { // Fall through for (default) auto verify, ie, unless -V was specified
avrdude_message(MSG_INFO, "%s: %d bytes of %s%s written\n", progname, if (!(flags & UF_VERIFY))
vsize, mem->desc, alias_mem_desc); break;
}
} case DEVICE_VERIFY:
else if (upd->op == DEVICE_VERIFY) { // Verify that the in memory file is the same as what is on the chip
/*
* verify that the in memory file (p->mem[AVR_M_FLASH|AVR_M_EEPROM])
* is the same as what is on the chip
*/
pgm->vfy_led(pgm, ON); pgm->vfy_led(pgm, ON);
if (quell_progress < 2) { int userverify = upd->op == DEVICE_VERIFY; // Explicit -U :v by user
avrdude_message(MSG_INFO, "%s: verifying %s%s memory against %s:\n",
progname, mem->desc, alias_mem_desc, upd->filename);
avrdude_message(MSG_NOTICE2, "%s: load data %s%s data from input file %s:\n", if (quell_progress < 2) {
progname, mem->desc, alias_mem_desc, upd->filename); avrdude_message(MSG_INFO, "%s: verifying %s%s memory against %s\n",
progname, mem->desc, alias_mem_desc, inname(upd->filename));
if (userverify)
avrdude_message(MSG_NOTICE, "%s: load %s%s data from input file %s\n",
progname, mem->desc, alias_mem_desc, inname(upd->filename));
} }
// No need to read file when fallen through from DEVICE_WRITE
if (userverify) {
rc = fileio(FIO_READ_FOR_VERIFY, upd->filename, upd->format, p, upd->memtype, -1); rc = fileio(FIO_READ_FOR_VERIFY, upd->filename, upd->format, p, upd->memtype, -1);
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n", avrdude_message(MSG_INFO, "%s: read from file %s failed\n",
progname, upd->filename); progname, inname(upd->filename));
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
} }
v = avr_dup_part(p);
size = rc; size = rc;
if(memstats(p, upd->memtype, size, &fs) < 0)
return LIBAVRDUDE_GENERAL_FAILURE;
} else {
// Correct size of last read to include potentially cut off, trailing 0xff (flash)
size = fs.lastaddr+1;
}
v = avr_dup_part(p);
if (quell_progress < 2) { if (quell_progress < 2) {
avrdude_message(MSG_NOTICE2, "%s: input file %s contains %d bytes\n", if (userverify)
progname, upd->filename, size); avrdude_message(MSG_NOTICE, "%s: input file %s contains %d byte%s\n",
avrdude_message(MSG_NOTICE2, "%s: reading on-chip %s%s data:\n", progname, inname(upd->filename), fs.nbytes, plural(fs.nbytes));
avrdude_message(MSG_NOTICE2, "%s: reading on-chip %s%s data ...\n",
progname, mem->desc, alias_mem_desc); progname, mem->desc, alias_mem_desc);
} }
report_progress (0,1,"Reading"); report_progress (0,1,"Reading");
rc = avr_read(pgm, p, upd->memtype, v); rc = avr_read(pgm, p, upd->memtype, v);
report_progress (1,1,NULL);
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: failed to read all of %s%s memory, rc=%d\n", avrdude_message(MSG_INFO, "%s: failed to read all of %s%s memory, rc=%d\n",
progname, mem->desc, alias_mem_desc, rc); progname, mem->desc, alias_mem_desc, rc);
pgm->err_led(pgm, ON); pgm->err_led(pgm, ON);
avr_free_part(v); avr_free_part(v);
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
} }
report_progress (1,1,NULL);
if (quell_progress < 2)
if (quell_progress < 2) {
avrdude_message(MSG_NOTICE2, "%s: verifying ...\n", progname); avrdude_message(MSG_NOTICE2, "%s: verifying ...\n", progname);
}
rc = avr_verify(p, v, upd->memtype, size); rc = avr_verify(p, v, upd->memtype, size);
if (rc < 0) { if (rc < 0) {
avrdude_message(MSG_INFO, "%s: verification error; content mismatch\n", avrdude_message(MSG_INFO, "%s: verification error; content mismatch\n",
progname); progname);
pgm->err_led(pgm, ON); pgm->err_led(pgm, ON);
avr_free_part(v); avr_free_part(v);
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
} }
if (quell_progress < 2) { if (quell_progress < 2) {
avrdude_message(MSG_INFO, "%s: %d bytes of %s%s verified\n", int verified = fs.nbytes+fs.ntrailing;
progname, rc, mem->desc, alias_mem_desc); avrdude_message(MSG_INFO, "%s: %d byte%s of %s%s verified\n",
progname, verified, plural(verified), mem->desc, alias_mem_desc);
} }
pgm->vfy_led(pgm, OFF); pgm->vfy_led(pgm, OFF);
avr_free_part(v); avr_free_part(v);
} break;
else {
default:
avrdude_message(MSG_INFO, "%s: invalid update operation (%d) requested\n", avrdude_message(MSG_INFO, "%s: invalid update operation (%d) requested\n",
progname, upd->op); progname, upd->op);
return -1; return LIBAVRDUDE_GENERAL_FAILURE;
} }
return 0; return LIBAVRDUDE_SUCCESS;
} }