Skip to content

Commit

Permalink
Merge pull request avrdudes#1577 from stefanrueger/config_value
Browse files Browse the repository at this point in the history
Provide and use libavrude functions to access part config values
  • Loading branch information
stefanrueger authored Nov 26, 2023
2 parents 606658a + f4de378 commit e0aee95
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 50 deletions.
1 change: 0 additions & 1 deletion src/avrcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

#include "avrdude.h"
#include "libavrdude.h"
#include "avrintel.h"

/*
* Provides an API for cached bytewise access
Expand Down
167 changes: 167 additions & 0 deletions src/avrpart.c
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,173 @@ AVRMEM_ALIAS *avr_find_memalias(const AVRPART *p, const AVRMEM *m_orig) {
return NULL;
}

// Return index in uP_table for part or -1
int avr_locate_upidx(const AVRPART *p) {
int idx = -1;

if(!p)
return -1;
if(p->mcuid >= 0)
idx = upidxmcuid(p->mcuid);
if(idx < 0 && p->desc && *p->desc)
idx = upidxname(p->desc);

if(idx < 0)
pmsg_error("uP_table neither knows mcuid %d nor part %s\n",
p->mcuid, p->desc && *p->desc? p->desc: "???");

return idx;
}

// Return pointer to config table for the part and set number of config bitfields
const Configitem_t *avr_locate_configitems(const AVRPART *p, int *nc) {
int idx = avr_locate_upidx(p);
if(idx < 0)
return NULL;

*nc = uP_table[idx].nconfigs;
return uP_table[idx].cfgtable;
}


/*
* Return pointer to a configuration bitfield that uniquely matches the
* argument name. Return NULL if none matches or more than one do.
*
* The caller provides a matching function which can be str_eq, str_starts,
* str_matched_by etc. If name is the full name of a configuration bitfield
* then a pointer to that is returned irrespective of the matching function.
*/
const Configitem_t *avr_locate_config(const Configitem_t *cfg, int nc, const char *name,
int (*match)(const char *, const char*)) {

if(!cfg || nc < 1 || !name || !match)
return NULL;

const Configitem_t *ret = NULL;
int nmatches = 0;

for(int i = 0; i < nc; i++) {
if(match(cfg[i].name, name)) {
if(match == str_eq || str_eq(cfg[i].name, name)) // Full name specified: return straight away
return cfg+i;
nmatches++, ret = cfg+i;
}
}

return nmatches == 1? ret: NULL;
}

/*
* Return a NULL terminated malloc'd list of pointers to config bitfields
*
* The caller provides a matching function which can be str_eq, str_starts,
* str_matched_by etc. If name is a full, existing config name then the
* returned list is confined to this specific entry irrespective of the
* matching function.
*/
const Configitem_t **avr_locate_configlist(const Configitem_t *cfg, int nc, const char *name,
int (*match)(const char *, const char*)) {

const Configitem_t **ret = cfg_malloc(__func__, sizeof cfg*(nc>0? nc+1: 1)), **r = ret;

if(cfg && name && match) {
for(int i = 0; i < nc; i++)
if(match(cfg[i].name, name)) {
if(match == str_eq || str_eq(cfg[i].name, name)) { // Full name specified: return straight away
ret[0] = cfg+i;
ret[1] = NULL;
return ret;
}
*r++ = cfg+i;
}
}
*r = NULL;

return ret;
}

// Return memory associated with config item and fill in pointer to Configitem_t record
static AVRMEM *avr_locate_config_mem_c_value(const PROGRAMMER *pgm, const AVRPART *p,
const char *cname, const Configitem_t **cp, int *valp) {

int nc = 0;
const Configitem_t *cfg = avr_locate_configitems(p, &nc);

if(!cfg || nc < 1) {
pmsg_error("avrintel.c does not hold configuration information for %s\n", p->desc);
return NULL;
}

const Configitem_t *c = avr_locate_config(cfg, nc, cname, str_contains);
if(!c) {
pmsg_error("%s does not have a unique config item matched by %s\n", p->desc, cname);
return NULL;
}

AVRMEM *mem = str_starts(c->memstr, "lock")? avr_locate_lock(p): avr_locate_fuse_by_offset(p, c->memoffset);
if(!mem)
mem = avr_locate_mem(p, c->memstr);
if(!mem) {
pmsg_error("%s does not have the memory %s needed for config item %s\n", p->desc, c->memstr, cname);
return NULL;
}

if(mem->size < 1 || mem->size > 4) {
pmsg_error("cannot handle size %d of %s's memory %s for config item %s\n", mem->size, p->desc, c->memstr, cname);
return NULL;
}

int fusel = 0;
for(int i = 0; i < mem->size; i++)
if(led_read_byte(pgm, p, mem, i, (unsigned char *) &fusel + i) < 0) {
pmsg_error("cannot read from %s's %s memory\n", p->desc, mem->desc);
return NULL;
}

*cp = c;
*valp = fusel;
return mem;
}

// Initialise *valuep with configuration value of named configuration bitfield
int avr_get_config_value(const PROGRAMMER *pgm, const AVRPART *p, const char *cname, int *valuep) {
const Configitem_t *c;
int fusel;

if(!avr_locate_config_mem_c_value(pgm, p, cname, &c, &fusel))
return -1;

*valuep = (fusel & c->mask) >> c->lsh;
return 0;
}

// Set configuration value of named configuration bitfield to value
int avr_set_config_value(const PROGRAMMER *pgm, const AVRPART *p, const char *cname, int value) {
AVRMEM *mem;
const Configitem_t *c;
int fusel;

if(!(mem=avr_locate_config_mem_c_value(pgm, p, cname, &c, &fusel)))
return -1;

if((value << c->lsh) & ~c->mask)
pmsg_warning("value 0x%02x has bits set outside bitfield mask 0x%02x\n", value, c->mask >> c->lsh);

int newval = (fusel & ~c->mask) | ((value << c->lsh) & c->mask);

if(newval != fusel) {
for(int i = 0; i < mem->size; i++)
if(led_write_byte(pgm, p, mem, i, ((unsigned char *) &newval)[i]) < 0) {
pmsg_error("cannot write to %s's %s memory\n", p->desc, mem->desc);
return -1;
}
}

return 0;
}


static char *print_num(const char *fmt, int n) {
return str_sprintf(n<10? "%d": fmt, n);
}
Expand Down
1 change: 0 additions & 1 deletion src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include "avrdude.h"
#include "libavrdude.h"
#include "config.h"
#include "avrintel.h"

#include "config_gram.h"

Expand Down
20 changes: 3 additions & 17 deletions src/jtagmkI.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,6 @@ struct pdata

#define PDATA(pgm) ((struct pdata *)(pgm->cookie))

/*
* The OCDEN fuse is bit 7 of the high fuse (hfuse). In order to
* perform memory operations on MTYPE_SPM and MTYPE_EEPROM, OCDEN
* needs to be programmed.
*
* OCDEN should probably rather be defined via the configuration, but
* if this ever changes to a different fuse byte for one MCU, quite
* some code here needs to be generalized anyway.
*/
#define OCDEN (1 << 7)

/*
* Table of baud rates supported by the mkI ICE, accompanied by their
* internal parameter value.
Expand Down Expand Up @@ -550,12 +539,9 @@ static int jtagmkI_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
if (jtagmkI_reset(pgm) < 0)
return -1;

AVRMEM *hf = avr_locate_hfuse(p);
if (!hf || jtagmkI_read_byte(pgm, p, hf, 1, &b) < 0)
return -1;
if ((b & OCDEN) != 0)
pmsg_warning("OCDEN fuse not programmed, "
"single-byte EEPROM updates not possible\n");
int ocden = 0;
if(avr_get_config_value(pgm, p, "ocden", &ocden) == 0 && ocden) // ocden == 1 means disabled
pmsg_warning("OCDEN fuse not programmed, single-byte EEPROM updates not possible\n");

return 0;
}
Expand Down
20 changes: 3 additions & 17 deletions src/jtagmkII.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,6 @@ struct pdata

#define PDATA(pgm) ((struct pdata *)(pgm->cookie))

/*
* The OCDEN fuse is bit 7 of the high fuse (hfuse). In order to
* perform memory operations on MTYPE_SPM and MTYPE_EEPROM, OCDEN
* needs to be programmed.
*
* OCDEN should probably rather be defined via the configuration, but
* if this ever changes to a different fuse byte for one MCU, quite
* some code here needs to be generalized anyway.
*/
#define OCDEN (1 << 7)

#define RC(x) { x, #x },
static struct {
unsigned int code;
Expand Down Expand Up @@ -1325,12 +1314,9 @@ static int jtagmkII_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
}

if ((pgm->flag & PGM_FL_IS_JTAG) && !(p->prog_modes & (PM_PDI | PM_UPDI))) {
AVRMEM *hf = avr_locate_hfuse(p);
if (!hf || jtagmkII_read_byte(pgm, p, hf, 1, &b) < 0)
return -1;
if ((b & OCDEN) != 0)
pmsg_warning("OCDEN fuse not programmed, "
"single-byte EEPROM updates not possible\n");
int ocden = 0;
if(avr_get_config_value(pgm, p, "ocden", &ocden) == 0 && ocden) // ocden == 1 means disabled
pmsg_warning("OCDEN fuse not programmed, single-byte EEPROM updates not possible\n");
}

if (pgm->read_chip_rev && p->prog_modes & (PM_PDI | PM_UPDI)) {
Expand Down
10 changes: 10 additions & 0 deletions src/libavrdude.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include "avrintel.h"

typedef uint32_t pinmask_t;
/*
Expand Down Expand Up @@ -1419,6 +1420,15 @@ typedef struct {
extern "C" {
#endif

int avr_locate_upidx(const AVRPART *p);
const Configitem_t *avr_locate_configitems(const AVRPART *p, int *nc);
const Configitem_t *avr_locate_config(const Configitem_t *cfg, int nc, const char *name,
int (*match)(const char *, const char*));
const Configitem_t **avr_locate_configlist(const Configitem_t *cfg, int nc, const char *name,
int (*match)(const char *, const char*));
int avr_get_config_value(const PROGRAMMER *pgm, const AVRPART *p, const char *cname, int *valuep);
int avr_set_config_value(const PROGRAMMER *pgm, const AVRPART *p, const char *cname, int value);

int setport_from_serialadapter(char **portp, const SERIALADAPTER *ser, const char *sernum);
int setport_from_vid_pid(char **portp, int vid, int pid, const char *sernum);
int list_available_serialports(LISTID programmers);
Expand Down
31 changes: 17 additions & 14 deletions src/term.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
#include <errno.h>

#include "libavrdude.h"
#include "avrintel.h"

#if defined(HAVE_LIBREADLINE)
#include <readline/readline.h>
Expand Down Expand Up @@ -2000,29 +1999,33 @@ static char *tokenize(char *s, int *argcp, char ***argvp) {


static int do_cmd(const PROGRAMMER *pgm, const AVRPART *p, int argc, char *argv[]) {
int i;
int hold, matches;
size_t len;

len = strlen(argv[0]);
matches = 0;
for (i=0; i<NCMDS; i++) {
if(!*(void (**)(void)) ((char *) pgm + cmd[i].fnoff))
continue;
if(len && strncasecmp(argv[0], cmd[i].name, len)==0) { // Partial initial match
hold = i;
matches++;
if(cmd[i].name[len] == 0) { // Exact match
matches = 1;
break;
for(int i = 0; i < NCMDS; i++)
if(*(void (**)(void)) ((char *) pgm + cmd[i].fnoff))
if(len && strncasecmp(argv[0], cmd[i].name, len)==0) { // Partial initial match
hold = i;
matches++;
if(cmd[i].name[len] == 0) { // Exact match
matches = 1;
break;
}
}
}
}

if(matches == 1)
return cmd[hold].func(pgm, p, argc, argv);

pmsg_error("(cmd) command %s is %s\n", argv[0], matches > 1? "ambiguous": "invalid");
pmsg_error("(cmd) command %s is %s", argv[0], matches > 1? "ambiguous": "invalid");
if(matches > 1)
for(int ch = ':', i = 0; i < NCMDS; i++)
if(*(void (**)(void)) ((char *) pgm + cmd[i].fnoff))
if(len && strncasecmp(argv[0], cmd[i].name, len)==0)
msg_error("%c %s", ch, cmd[i].name), ch = ',';
msg_error("\n");

return -1;
}

Expand Down

0 comments on commit e0aee95

Please sign in to comment.