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
|
mpmboot
|
||||||
funkboot
|
funkboot
|
||||||
eprom_prog
|
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
|
TARGET_DIR=~/bin
|
||||||
BUILD_DIR = build
|
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))
|
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
|
||||||
|
|
||||||
struct chipinfo
|
static avr_chipinfo_t chips[] =
|
||||||
{
|
{
|
||||||
uint8_t sig[3];
|
{ { 0x1E, 0x93, 0x07 }, "ATmega8", 0x2000, 0x200 },
|
||||||
const char name[16];
|
{ { 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" },
|
unsigned int i;
|
||||||
{ { 0x1E, 0x93, 0x0A }, "AVR Mega 88" },
|
|
||||||
{ { 0x1E, 0x94, 0x06 }, "AVR Mega 168" },
|
for (i = 0; i < ARRAY_SIZE(chips); i++)
|
||||||
{ { 0x1E, 0x95, 0x02 }, "AVR Mega 32" },
|
{
|
||||||
};
|
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
|
* chipinfo_get_avr_name
|
||||||
* ************************************************************************* */
|
* ************************************************************************* */
|
||||||
const char * chipinfo_get_avr_name(const uint8_t *sig)
|
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++)
|
p_chipinfo = chipinfo_get_by_signature(sig);
|
||||||
{
|
|
||||||
struct chipinfo *chip = &chips[i];
|
|
||||||
if (chip->sig[0] == sig[0] && chip->sig[1] == sig[1] && chip->sig[2] == sig[2])
|
|
||||||
{
|
|
||||||
return chip->name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unknown";
|
return (p_chipinfo != NULL) ? p_chipinfo->name : "unknown";
|
||||||
} /* chipinfo_get_avr_name */
|
} /* chipinfo_get_avr_name */
|
||||||
|
@ -3,6 +3,15 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#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);
|
const char * chipinfo_get_avr_name (const uint8_t *sig);
|
||||||
|
|
||||||
#endif /* _CHIPINFO_H_ */
|
#endif /* _CHIPINFO_H_ */
|
||||||
|
@ -39,6 +39,7 @@ static struct multiboot_ops * prog_ops[] =
|
|||||||
&mpm_ops,
|
&mpm_ops,
|
||||||
&funk_ops,
|
&funk_ops,
|
||||||
&eprog_ops,
|
&eprog_ops,
|
||||||
|
&butterfly_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mboot_action
|
struct mboot_action
|
||||||
|
@ -35,5 +35,6 @@ extern struct multiboot_ops twi_ops;
|
|||||||
extern struct multiboot_ops mpm_ops;
|
extern struct multiboot_ops mpm_ops;
|
||||||
extern struct multiboot_ops funk_ops;
|
extern struct multiboot_ops funk_ops;
|
||||||
extern struct multiboot_ops eprog_ops;
|
extern struct multiboot_ops eprog_ops;
|
||||||
|
extern struct multiboot_ops butterfly_ops;
|
||||||
|
|
||||||
#endif /* _MULTIBOOT_H_ */
|
#endif /* _MULTIBOOT_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user