Add simple AVR109/butterfly tool
This commit is contained in:
parent
fcbcbcb9af
commit
9119ee215b
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ twiboot
|
||||
mpmboot
|
||||
funkboot
|
||||
eprom_prog
|
||||
butterfly_prog
|
||||
|
2
Makefile
2
Makefile
@ -1,4 +1,4 @@
|
||||
TARGETS=twiboot mpmboot funkboot eprom_prog
|
||||
TARGETS=twiboot mpmboot funkboot eprom_prog butterfly_prog
|
||||
TARGET_DIR=~/bin
|
||||
BUILD_DIR = build
|
||||
|
||||
|
766
butterfly.c
Normal file
766
butterfly.c
Normal file
@ -0,0 +1,766 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 01/2020 by Olaf Rempel *
|
||||
* razzor@kopf-tisch.de *
|
||||
* *
|
||||
* 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; version 2 of the License, *
|
||||
* *
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "chipinfo_avr.h"
|
||||
#include "multiboot.h"
|
||||
#include "optarg.h"
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#define SERIAL_BAUDRATE B115200
|
||||
#define SERIAL_TIMEOUT 1000
|
||||
|
||||
struct multiboot_ops butterfly_ops;
|
||||
|
||||
typedef struct bfly_privdata_s
|
||||
{
|
||||
char * p_device;
|
||||
struct termios oldtio;
|
||||
int fd;
|
||||
|
||||
uint8_t twi_address;
|
||||
uint8_t chip_erase;
|
||||
|
||||
uint16_t buffersize;
|
||||
uint16_t flashsize;
|
||||
uint16_t eepromsize;
|
||||
|
||||
uint8_t progmode_active;
|
||||
} bfly_privdata_t;
|
||||
|
||||
static struct option bfly_optargs[] =
|
||||
{
|
||||
{ "address", 1, 0, 'a' }, /* [ -a <address ] */
|
||||
{ "device", 1, 0, 'd' }, /* -d <device> */
|
||||
{ "erase", 0, 0, 'e' }, /* [ -e ] */
|
||||
};
|
||||
|
||||
/* *************************************************************************
|
||||
* bfly_optarg_cb
|
||||
* ************************************************************************* */
|
||||
static int bfly_optarg_cb(int val, const char *arg, void *privdata)
|
||||
{
|
||||
bfly_privdata_t * p_priv;
|
||||
|
||||
p_priv = (bfly_privdata_t *)privdata;
|
||||
|
||||
switch (val)
|
||||
{
|
||||
case 'a': /* address */
|
||||
{
|
||||
char *endptr;
|
||||
|
||||
p_priv->twi_address = strtol(arg, &endptr, 16);
|
||||
if ((*endptr != '\0') ||
|
||||
(p_priv->twi_address < 0x01) ||
|
||||
(p_priv->twi_address > 0x7F)
|
||||
)
|
||||
{
|
||||
fprintf(stderr, "invalid address: '%s'\n", arg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd': /* device */
|
||||
if (p_priv->p_device != NULL)
|
||||
{
|
||||
fprintf(stderr, "invalid device: '%s'\n", arg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p_priv->p_device = strdup(optarg);
|
||||
if (p_priv->p_device == NULL)
|
||||
{
|
||||
perror("strdup()");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'e': /* no verify after write */
|
||||
p_priv->chip_erase = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case '?': /* error */
|
||||
fprintf(stderr, "Usage: butterfly_prog [options]\n"
|
||||
" -a <address> - optional: twi address for twiboot bridge mode\n"
|
||||
" -d <device> - selects butterfly serial device\n"
|
||||
" -r <flash|eeprom>:<file> - reads flash/eeprom to file (.bin | .hex | -)\n"
|
||||
" -w <flash|eeprom>:<file> - write flash/eeprom from file (.bin | .hex)\n"
|
||||
" -n - disable verify after write\n"
|
||||
" -p <0|1|2> - progress bar mode\n"
|
||||
"\n"
|
||||
"Example: butterfly_prog -d /dev/ttyUSB0 -w flash:code.hex\n"
|
||||
"\n");
|
||||
|
||||
return -1;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* bfly_optarg_cb */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_alloc
|
||||
* ************************************************************************* */
|
||||
static struct multiboot * butterfly_alloc(void)
|
||||
{
|
||||
struct multiboot * mboot = malloc(sizeof(struct multiboot));
|
||||
if (mboot == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(mboot, 0x00, sizeof(struct multiboot));
|
||||
mboot->ops= &butterfly_ops;
|
||||
|
||||
bfly_privdata_t * p_priv = malloc(sizeof(bfly_privdata_t));
|
||||
if (p_priv == NULL)
|
||||
{
|
||||
free(mboot);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(p_priv, 0x00, sizeof(bfly_privdata_t));
|
||||
|
||||
optarg_register(bfly_optargs, ARRAY_SIZE(bfly_optargs),
|
||||
bfly_optarg_cb, (void *)p_priv);
|
||||
|
||||
mboot->privdata = p_priv;
|
||||
return mboot;
|
||||
} /* butterfly_alloc */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_free
|
||||
* ************************************************************************* */
|
||||
static void butterfly_free(struct multiboot * p_mboot)
|
||||
{
|
||||
bfly_privdata_t * p_priv = (bfly_privdata_t *)p_mboot->privdata;
|
||||
|
||||
if (p_priv->p_device != NULL)
|
||||
{
|
||||
free(p_priv->p_device);
|
||||
}
|
||||
|
||||
free(p_priv);
|
||||
free(p_mboot);
|
||||
} /* butterfly_free */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_get_memtype
|
||||
* ************************************************************************* */
|
||||
static int butterfly_get_memtype(struct multiboot * p_mboot,
|
||||
const char * p_memname)
|
||||
{
|
||||
/* unused parameter */
|
||||
(void)p_mboot;
|
||||
|
||||
if (strcmp(p_memname, "flash") == 0)
|
||||
{
|
||||
return 'F';
|
||||
}
|
||||
else if (strcmp(p_memname, "eeprom") == 0)
|
||||
{
|
||||
return 'E';
|
||||
}
|
||||
|
||||
return -1;
|
||||
} /* butterfly_get_memtype */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_get_memsize
|
||||
* ************************************************************************* */
|
||||
static int butterfly_get_memsize(struct multiboot * p_mboot,
|
||||
int memtype)
|
||||
{
|
||||
bfly_privdata_t * p_priv = (bfly_privdata_t *)p_mboot->privdata;
|
||||
|
||||
if (!p_priv->progmode_active)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (memtype)
|
||||
{
|
||||
case 'F':
|
||||
return p_priv->flashsize;
|
||||
|
||||
case 'E':
|
||||
return p_priv->eepromsize;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
} /* butterfly_get_memsize */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_close_device
|
||||
* ************************************************************************* */
|
||||
static void butterfly_close_device(bfly_privdata_t * p_priv)
|
||||
{
|
||||
/* delay close() / tcsetattr() */
|
||||
usleep(100000);
|
||||
|
||||
tcsetattr(p_priv->fd, TCSANOW, &p_priv->oldtio);
|
||||
close(p_priv->fd);
|
||||
} /* butterfly_close_device */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterlfy_open_device
|
||||
* ************************************************************************* */
|
||||
static int butterfly_open_device(bfly_privdata_t * p_priv)
|
||||
{
|
||||
p_priv->fd = open(p_priv->p_device, O_RDWR | O_NOCTTY | O_CLOEXEC);
|
||||
if (p_priv->fd < 0)
|
||||
{
|
||||
perror("open()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tcgetattr(p_priv->fd, &p_priv->oldtio) < 0)
|
||||
{
|
||||
perror("tcgetattr(oldtio)");
|
||||
close(p_priv->fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct termios newtio;
|
||||
memset(&newtio, 0, sizeof(newtio));
|
||||
|
||||
newtio.c_iflag |= IGNBRK;
|
||||
newtio.c_cflag |= SERIAL_BAUDRATE | CS8 | CLOCAL | CREAD;
|
||||
|
||||
newtio.c_cc[VMIN] = 1;
|
||||
newtio.c_cc[VTIME] = 0;
|
||||
|
||||
int err = tcsetattr(p_priv->fd, TCSANOW, &newtio);
|
||||
if (err < 0)
|
||||
{
|
||||
perror("tcsetattr(newtio)");
|
||||
close(p_priv->fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* butterlfy_open_device */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_serial_read
|
||||
* ************************************************************************* */
|
||||
static int butterfly_serial_read(int fd, void * data, int size,
|
||||
unsigned int timeout_ms)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
fd_set fdset;
|
||||
struct timeval timeout;
|
||||
struct timeval * p_timeout = NULL;
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(fd, &fdset);
|
||||
|
||||
if (timeout_ms != 0)
|
||||
{
|
||||
p_timeout = &timeout;
|
||||
|
||||
timeout.tv_sec = timeout_ms / 1000;
|
||||
timeout.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
}
|
||||
|
||||
int ret = select(fd +1, &fdset, NULL, NULL, p_timeout);
|
||||
if (ret == -1)
|
||||
{
|
||||
perror("select");
|
||||
return -1;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (FD_ISSET(fd, &fdset))
|
||||
{
|
||||
int len = read(fd, data + pos, size - pos);
|
||||
if (len < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos += len;
|
||||
if (pos == size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
} /* butterfly_serial_read */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_expect_cr
|
||||
* ************************************************************************* */
|
||||
static int butterfly_expect_cr(bfly_privdata_t * p_priv)
|
||||
{
|
||||
uint8_t buffer[1];
|
||||
int result;
|
||||
|
||||
result = butterfly_serial_read(p_priv->fd, buffer, sizeof(buffer),
|
||||
SERIAL_TIMEOUT);
|
||||
if ((result == sizeof(buffer)) &&
|
||||
(buffer[0] == '\r')
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
} /* butterfly_expect_cr */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_enter_progmode
|
||||
* ************************************************************************* */
|
||||
static int butterfly_enter_progmode(bfly_privdata_t * p_priv)
|
||||
{
|
||||
if (p_priv->twi_address == 0x00)
|
||||
{
|
||||
(void)write(p_priv->fd, "P", 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t cmd[2] = { 'I' , p_priv->twi_address };
|
||||
(void)write(p_priv->fd, cmd, 2);
|
||||
}
|
||||
|
||||
return butterfly_expect_cr(p_priv);
|
||||
} /* butterfly_enter_progmode */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_leave_progmode
|
||||
* ************************************************************************* */
|
||||
static int butterfly_leave_progmode(bfly_privdata_t * p_priv)
|
||||
{
|
||||
(void)write(p_priv->fd, "L", 1);
|
||||
|
||||
return butterfly_expect_cr(p_priv);
|
||||
} /* butterfly_leave_progmode */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_get_signature
|
||||
* ************************************************************************* */
|
||||
static int butterfly_get_signature(bfly_privdata_t * p_priv,
|
||||
uint8_t * p_signature)
|
||||
{
|
||||
int result;
|
||||
uint8_t buffer[3];
|
||||
|
||||
(void)write(p_priv->fd, "s", 1);
|
||||
|
||||
result = butterfly_serial_read(p_priv->fd, buffer, sizeof(buffer),
|
||||
SERIAL_TIMEOUT);
|
||||
|
||||
if (result == 3)
|
||||
{
|
||||
p_signature[0] = buffer[2];
|
||||
p_signature[1] = buffer[1];
|
||||
p_signature[2] = buffer[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
} /* butterfly_get_signature */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_get_buffersize
|
||||
* ************************************************************************* */
|
||||
static int butterfly_get_buffersize(bfly_privdata_t * p_priv,
|
||||
uint16_t * p_buffersize)
|
||||
{
|
||||
int result;
|
||||
uint8_t buffer[3];
|
||||
|
||||
(void)write(p_priv->fd, "b", 1);
|
||||
|
||||
result = butterfly_serial_read(p_priv->fd, buffer, sizeof(buffer),
|
||||
SERIAL_TIMEOUT);
|
||||
if (result == sizeof(buffer))
|
||||
{
|
||||
if (buffer[0] == 'Y')
|
||||
{
|
||||
*p_buffersize = (buffer[1] << 8) | buffer[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
*p_buffersize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (result != sizeof(buffer));
|
||||
} /* butterfly_get_buffersize */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_chiperase
|
||||
* ************************************************************************* */
|
||||
static int butterfly_chiperase(bfly_privdata_t * p_priv)
|
||||
{
|
||||
(void)write(p_priv->fd, "e", 1);
|
||||
|
||||
return butterfly_expect_cr(p_priv);
|
||||
} /* butterfly_chiperase */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_set_address
|
||||
* ************************************************************************* */
|
||||
static int butterfly_set_address(bfly_privdata_t * p_priv, uint16_t pos)
|
||||
{
|
||||
uint8_t buffer[1];
|
||||
int result;
|
||||
|
||||
(void)write(p_priv->fd, "a", 1);
|
||||
|
||||
result = butterfly_serial_read(p_priv->fd, buffer, sizeof(buffer),
|
||||
SERIAL_TIMEOUT);
|
||||
if ((result == 1) &&
|
||||
(buffer[0] == 'Y')
|
||||
)
|
||||
{
|
||||
/* convert to word address */
|
||||
pos >>= 1;
|
||||
|
||||
uint8_t cmd[3] = { 'A', pos >> 8, pos & 0xFF };
|
||||
(void)write(p_priv->fd, cmd, sizeof(cmd));
|
||||
|
||||
result = butterfly_expect_cr(p_priv);
|
||||
}
|
||||
|
||||
return result;
|
||||
} /* butterfly_set_address */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_read_data
|
||||
* ************************************************************************* */
|
||||
static int butterfly_read_data(bfly_privdata_t * p_priv,
|
||||
uint8_t * p_data, uint16_t size,
|
||||
uint8_t memtype)
|
||||
{
|
||||
int result;
|
||||
|
||||
uint8_t cmd[4] = { 'g', size >> 8, size & 0xFF, memtype };
|
||||
(void)write(p_priv->fd, cmd, 4);
|
||||
|
||||
result = butterfly_serial_read(p_priv->fd, p_data, size,
|
||||
SERIAL_TIMEOUT);
|
||||
return (result != size);
|
||||
} /* butterfly_read_data */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_write_data
|
||||
* ************************************************************************* */
|
||||
static int butterfly_write_data(bfly_privdata_t * p_priv,
|
||||
const uint8_t * p_data, uint16_t size,
|
||||
uint8_t memtype)
|
||||
{
|
||||
uint8_t cmd[4] = { 'B', size >> 8, size & 0xFF, memtype };
|
||||
(void)write(p_priv->fd, cmd, 4);
|
||||
|
||||
(void)write(p_priv->fd, p_data, size);
|
||||
|
||||
return butterfly_expect_cr(p_priv);
|
||||
} /* butterfly_write_data */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_close
|
||||
* ************************************************************************* */
|
||||
static int butterfly_close(struct multiboot * p_mboot)
|
||||
{
|
||||
bfly_privdata_t * p_priv = (bfly_privdata_t *)p_mboot->privdata;
|
||||
|
||||
if (p_priv->progmode_active)
|
||||
{
|
||||
butterfly_leave_progmode(p_priv);
|
||||
}
|
||||
|
||||
butterfly_close_device(p_priv);
|
||||
|
||||
return 0;
|
||||
} /* butterfly_close */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_open
|
||||
* ************************************************************************* */
|
||||
static int butterfly_open(struct multiboot * p_mboot)
|
||||
{
|
||||
bfly_privdata_t * p_priv = (bfly_privdata_t *)p_mboot->privdata;
|
||||
|
||||
if (p_priv->p_device == NULL)
|
||||
{
|
||||
fprintf(stderr, "abort: no device given\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (butterfly_open_device(p_priv) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (butterfly_enter_progmode(p_priv) != 0)
|
||||
{
|
||||
fprintf(stderr, "failed to enter progmode\n");
|
||||
butterfly_close_device(p_priv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p_priv->progmode_active = 1;
|
||||
|
||||
uint8_t signature[3];
|
||||
if (butterfly_get_signature(p_priv, signature) != 0)
|
||||
{
|
||||
fprintf(stderr, "failed to get signature\n");
|
||||
butterfly_close_device(p_priv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const avr_chipinfo_t * p_chipinfo;
|
||||
p_chipinfo = chipinfo_get_by_signature(signature);
|
||||
if (p_chipinfo == NULL)
|
||||
{
|
||||
fprintf(stderr, "failed to identify chip signature [0x%02x 0x%02x 0x%02x]\n",
|
||||
signature[0], signature[1], signature[2]);
|
||||
butterfly_close_device(p_priv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p_priv->flashsize = p_chipinfo->flashsize;
|
||||
p_priv->eepromsize = p_chipinfo->eepromsize;
|
||||
|
||||
if (butterfly_get_buffersize(p_priv, &p_priv->buffersize) != 0)
|
||||
{
|
||||
fprintf(stderr, "failed to get buffersize\n");
|
||||
butterfly_close_device(p_priv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p_priv->twi_address != 0x00)
|
||||
{
|
||||
printf("twi address : 0x%02x\n",
|
||||
p_priv->twi_address);
|
||||
}
|
||||
|
||||
printf("device : %-16s (sig: 0x%02x 0x%02x 0x%02x)\n",
|
||||
p_chipinfo->name, p_chipinfo->sig[0],
|
||||
p_chipinfo->sig[1], p_chipinfo->sig[2]);
|
||||
|
||||
printf("flash size : 0x%04x / %5d\n",
|
||||
p_chipinfo->flashsize, p_chipinfo->flashsize);
|
||||
|
||||
printf("eeprom size : 0x%04x / %5d\n",
|
||||
p_chipinfo->eepromsize, p_chipinfo->eepromsize);
|
||||
|
||||
if (p_priv->chip_erase)
|
||||
{
|
||||
if (butterfly_chiperase(p_priv) != 0)
|
||||
{
|
||||
fprintf(stderr, "failed to chip erase\n");
|
||||
butterfly_close_device(p_priv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("chip erased : OK\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* butterfly_open */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_read
|
||||
* ************************************************************************* */
|
||||
static int butterfly_read(struct multiboot * p_mboot,
|
||||
struct databuf * p_dbuf,
|
||||
int memtype)
|
||||
{
|
||||
bfly_privdata_t * p_priv = (bfly_privdata_t *)p_mboot->privdata;
|
||||
char * p_progress_msg = (memtype == 'F') ? "reading flash" : "reading eeprom";
|
||||
|
||||
uint16_t pos = 0;
|
||||
uint16_t size = (memtype == 'F') ? p_priv->flashsize :
|
||||
p_priv->eepromsize;
|
||||
|
||||
if (butterfly_set_address(p_priv, pos) < 0)
|
||||
{
|
||||
fprintf(stderr, "failed to set address\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (pos < size)
|
||||
{
|
||||
p_mboot->progress_cb(p_progress_msg, pos, size);
|
||||
|
||||
uint16_t len = MIN(p_priv->buffersize, size - pos);
|
||||
if (butterfly_read_data(p_priv, p_dbuf->data + pos, len, memtype))
|
||||
{
|
||||
p_mboot->progress_cb(p_progress_msg, -1, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos += len;
|
||||
}
|
||||
|
||||
p_dbuf->length = pos;
|
||||
|
||||
p_mboot->progress_cb(p_progress_msg, pos, size);
|
||||
return 0;
|
||||
} /* butterfly_read */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_write
|
||||
* ************************************************************************* */
|
||||
static int butterfly_write(struct multiboot * p_mboot,
|
||||
struct databuf * p_dbuf,
|
||||
int memtype)
|
||||
{
|
||||
bfly_privdata_t * p_priv = (bfly_privdata_t *)p_mboot->privdata;
|
||||
char * p_progress_msg = (memtype == 'F') ? "writing flash" : "writing eeprom";
|
||||
|
||||
uint16_t pos = 0;
|
||||
|
||||
if (butterfly_set_address(p_priv, pos) < 0)
|
||||
{
|
||||
fprintf(stderr, "failed to set address\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (pos < p_dbuf->length)
|
||||
{
|
||||
p_mboot->progress_cb(p_progress_msg, pos, p_dbuf->length);
|
||||
|
||||
uint16_t len = MIN(p_priv->buffersize, p_dbuf->length - pos);
|
||||
if (butterfly_write_data(p_priv, p_dbuf->data + pos, len, memtype))
|
||||
{
|
||||
p_mboot->progress_cb(p_progress_msg, -1, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos += len;
|
||||
}
|
||||
|
||||
p_mboot->progress_cb(p_progress_msg, pos, p_dbuf->length);
|
||||
return 0;
|
||||
} /* butterfly_write */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* butterfly_verify
|
||||
* ************************************************************************* */
|
||||
static int butterfly_verify(struct multiboot * p_mboot,
|
||||
struct databuf * p_dbuf,
|
||||
int memtype)
|
||||
{
|
||||
bfly_privdata_t * p_priv = (bfly_privdata_t *)p_mboot->privdata;
|
||||
char * p_progress_msg = (memtype == 'F') ? "verifing flash" : "verifing eeprom";
|
||||
|
||||
uint16_t pos = 0;
|
||||
uint8_t comp[256];
|
||||
|
||||
if (butterfly_set_address(p_priv, pos) < 0)
|
||||
{
|
||||
fprintf(stderr, "failed to set address\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (pos < p_dbuf->length)
|
||||
{
|
||||
p_mboot->progress_cb(p_progress_msg, pos, p_dbuf->length);
|
||||
|
||||
uint16_t len = MIN(p_priv->buffersize, p_dbuf->length - pos);
|
||||
if (butterfly_read_data(p_priv, comp, len, memtype))
|
||||
{
|
||||
p_mboot->progress_cb(p_progress_msg, -1, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(comp, p_dbuf->data + pos, len) != 0x00)
|
||||
{
|
||||
p_mboot->progress_cb(p_progress_msg, -1, -1);
|
||||
fprintf(stderr, "verify failed at pos 0x%04x!!\n", pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos += len;
|
||||
}
|
||||
|
||||
p_dbuf->length = pos;
|
||||
|
||||
p_mboot->progress_cb(p_progress_msg, pos, p_dbuf->length);
|
||||
return 0;
|
||||
} /* butterfly_verify */
|
||||
|
||||
|
||||
struct multiboot_ops butterfly_ops =
|
||||
{
|
||||
.exec_name = "butterfly_prog",
|
||||
.alloc = butterfly_alloc,
|
||||
.free = butterfly_free,
|
||||
.get_memtype = butterfly_get_memtype,
|
||||
.get_memsize = butterfly_get_memsize,
|
||||
|
||||
.open = butterfly_open,
|
||||
.close = butterfly_close,
|
||||
.read = butterfly_read,
|
||||
.write = butterfly_write,
|
||||
.verify = butterfly_verify,
|
||||
};
|
@ -27,35 +27,47 @@
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
|
||||
|
||||
struct chipinfo
|
||||
static avr_chipinfo_t chips[] =
|
||||
{
|
||||
uint8_t sig[3];
|
||||
const char name[16];
|
||||
{ { 0x1E, 0x93, 0x07 }, "ATmega8", 0x2000, 0x200 },
|
||||
{ { 0x1E, 0x93, 0x0A }, "ATmega88", 0x2000, 0x200 },
|
||||
{ { 0x1E, 0x94, 0x06 }, "ATmega168", 0x4000, 0x200 },
|
||||
{ { 0x1E, 0x95, 0x02 }, "ATmega32", 0x8000, 0x400 },
|
||||
{ { 0x1E, 0x95, 0x0F }, "ATmega328p", 0x8000, 0x400 },
|
||||
};
|
||||
|
||||
static struct chipinfo chips[] =
|
||||
/* *************************************************************************
|
||||
* chipinfo_get_by_signature
|
||||
* ************************************************************************* */
|
||||
const avr_chipinfo_t * chipinfo_get_by_signature(const uint8_t *sig)
|
||||
{
|
||||
{ { 0x1E, 0x93, 0x07 }, "AVR Mega 8" },
|
||||
{ { 0x1E, 0x93, 0x0A }, "AVR Mega 88" },
|
||||
{ { 0x1E, 0x94, 0x06 }, "AVR Mega 168" },
|
||||
{ { 0x1E, 0x95, 0x02 }, "AVR Mega 32" },
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(chips); i++)
|
||||
{
|
||||
avr_chipinfo_t *chip = &chips[i];
|
||||
|
||||
if ((chip->sig[0] == sig[0]) &&
|
||||
(chip->sig[1] == sig[1]) &&
|
||||
(chip->sig[2] == sig[2])
|
||||
)
|
||||
{
|
||||
return chip;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} /* chipinfo_get_by_signature */
|
||||
|
||||
|
||||
/* *************************************************************************
|
||||
* chipinfo_get_avr_name
|
||||
* ************************************************************************* */
|
||||
const char * chipinfo_get_avr_name(const uint8_t *sig)
|
||||
{
|
||||
unsigned int i;
|
||||
const avr_chipinfo_t * p_chipinfo;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(chips); i++)
|
||||
{
|
||||
struct chipinfo *chip = &chips[i];
|
||||
if (chip->sig[0] == sig[0] && chip->sig[1] == sig[1] && chip->sig[2] == sig[2])
|
||||
{
|
||||
return chip->name;
|
||||
}
|
||||
}
|
||||
p_chipinfo = chipinfo_get_by_signature(sig);
|
||||
|
||||
return "unknown";
|
||||
return (p_chipinfo != NULL) ? p_chipinfo->name : "unknown";
|
||||
} /* chipinfo_get_avr_name */
|
||||
|
@ -3,6 +3,15 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct avr_chipinfo_s
|
||||
{
|
||||
uint8_t sig[3];
|
||||
const char name[16];
|
||||
uint16_t flashsize;
|
||||
uint16_t eepromsize;
|
||||
} avr_chipinfo_t;
|
||||
|
||||
const avr_chipinfo_t * chipinfo_get_by_signature (const uint8_t *sig);
|
||||
const char * chipinfo_get_avr_name (const uint8_t *sig);
|
||||
|
||||
#endif /* _CHIPINFO_H_ */
|
||||
|
@ -39,6 +39,7 @@ static struct multiboot_ops * prog_ops[] =
|
||||
&mpm_ops,
|
||||
&funk_ops,
|
||||
&eprog_ops,
|
||||
&butterfly_ops,
|
||||
};
|
||||
|
||||
struct mboot_action
|
||||
|
@ -35,5 +35,6 @@ extern struct multiboot_ops twi_ops;
|
||||
extern struct multiboot_ops mpm_ops;
|
||||
extern struct multiboot_ops funk_ops;
|
||||
extern struct multiboot_ops eprog_ops;
|
||||
extern struct multiboot_ops butterfly_ops;
|
||||
|
||||
#endif /* _MULTIBOOT_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user