ispdown/isp_down.c

553 lines
12 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#define DEVICE "/dev/usb/tts/0"
#define BAUDRATE B38400
#define TIMEOUT 1000
struct chip_ {
char shortname[8];
char longname[16];
char signature[3];
char devicecode;
int flash_size;
int eeprom_size;
};
typedef struct chip_ CHIP;
CHIP chips[] = {
{ "1200", "AT90S1200", { 0x00, 0x90, 0x1E }, 0x13, 0x200, 0x40 },
{ "2313", "AT90S2313", { 0x01, 0x91, 0x1E }, 0x12, 0x400, 0x80 }, // unknown devicecode!
{ "8515", "AT90S8515", { 0x01, 0x93, 0x1E }, 0x38, 0x1000, 0x200 },
{ "m103", "ATMega103", { 0x00, 0x00, 0x00 }, 0x41, 0x20000, 0x1000 },
{ "m128", "ATMega128", { 0x00, 0x00, 0x00 }, 0x00, 0x20000, 0x1000 }, // unknown devicecode!
{ "\0", "\0", { 0, 0, 0 }, 0, 0, 0 }
};
#define F_FLASH 0x01
#define F_FLASH_FILE 0x02
#define F_EEPROM 0x04
#define F_EEPROM_FILE 0x08
#define F_VERIFY 0x10
#define F_RESET 0x20
struct _cfg {
int mode;
CHIP *avr;
char *flash_file;
int fd_flash;
char *eeprom_file;
int fd_eeprom;
char *ser_device;
int fd_ser;
struct termios oldtio;
} cfg;
int debug = 0;
int isp_check(int fd) {
char buf[8];
write(fd, "S", 1);
read_ser(fd, buf, 7);
if (debug)
printf(" (expected: 'AVR ISP', got: '%7s')\n", buf);
return strncmp(buf, "AVR ISP", 7);
}
int isp_set_device(int fd, char device) {
char buf[2];
buf[0] = 'T';
buf[1] = device;
write(fd, buf, 2);
read_ser(fd, buf, 1);
if (debug)
printf(" (expected: '0x0D', got: '0x%X')\n", buf[0]);
return (buf[0] != 0x0D);
}
int isp_enter_progmode(int fd) {
char buf;
write(fd, "P", 1);
read_ser(fd, &buf, 1);
if (debug)
printf(" (expected: '0x0D', got: '0x%X')\n", buf);
return (buf != 0x0D);
}
int isp_led(int fd, int mode) {
char buf= (mode == 0) ? 'y' : 'x';
write(fd, &buf, 1);
read_ser(fd, &buf, 1);
if (debug)
printf(" (expected: '0x0D', got: '0x%X')\n", buf);
return (buf != 0x0D);
}
void isp_led_off() {
isp_led(cfg.fd_ser, 0);
}
int isp_check_sig(int fd, char *sig) {
char buf[3];
write(fd, "s", 1);
read_ser(fd, buf, 3);
if (debug)
printf(" (expected: '0x%X 0x%X 0x%X', got: '0x%X 0x%X 0x%X')\n", (*sig & 0xFF), (*(sig+1) & 0xFF), (*(sig+2) & 0xFF), (buf[0] & 0xFF), (buf[1] & 0xFF), (buf[2] & 0xFF));
return !((buf[0] & 0xFF) == (*sig & 0xFF) && (buf[1] & 0xFF) == (*(sig+1) & 0xFF) && (buf[2] & 0xFF) == (*(sig+2) & 0xFF));
}
int isp_chip_erase(int fd) {
char buf;
write(fd, "e", 1);
read_ser(fd, &buf, 1);
if (debug)
printf(" (expected: '0x0D', got: '0x%X')\n", buf);
return (buf != 0x0D);
}
int isp_leave_progmode(int fd) {
char buf;
write(fd, "L", 1);
read_ser(fd, &buf, 1);
if (debug)
printf(" (expected: '0x0D', got: '0x%X')\n", buf);
return (buf != 0x0D);
}
int isp_set_address(int fd, int addr) {
char buf[3];
buf[0] = 'A';
buf[1] = (addr >> 8) & 0xFF;
buf[2] = addr & 0xFF;
write(fd, buf, 3);
read_ser(fd, buf, 1);
return (buf[0] != 0x0D);
}
int isp_prg_flash(int fd, char *buf) {
char outbuf[2];
char ret[2];
outbuf[0] = 0x63;
outbuf[1] = *buf & 0xFF;
write(fd, outbuf, 2);
read_ser(fd, &ret[0], 1);
outbuf[0] = 0x43;
outbuf[1] = *(buf +1) & 0xFF;
write(fd, outbuf, 2);
read_ser(fd, &ret[1], 1);
return !(ret[0] == 0x0D && ret[1] == 0x0D);
}
int isp_verify_flash(int fd, char *buf) {
char inbuf[2];
write(fd, "R", 1);
read_ser(fd, inbuf, 2);
if (debug)
printf(" (expected: '0x%X 0x%X', got: '0x%X 0x%X')\n", (*buf & 0xFF), (*(buf+1) & 0xFF), (inbuf[1] & 0xFF), (inbuf[0] & 0xFF));
return !((inbuf[1] & 0xFF) == (*buf & 0xFF) && (inbuf[0] & 0xFF) == (*(buf+1) & 0xFF));
}
int isp_prg_eeprom(int fd, char val) {
char buf[2];
buf[0] = 'D';
buf[1] = val & 0xFF;
write(fd, buf, 2);
read_ser(fd, buf, 1);
return (buf[0] != 0x0D);
}
int isp_verify_eeprom(int fd, char val) {
char buf;
write(fd, "d", 1);
read_ser(fd, &buf, 1);
if (debug)
printf(" (expected: '0x%X', got: '0x%X')\n", (val & 0xFF), (buf & 0xFF));
return (val != buf);
}
void init_ser() {
struct termios newtio;
/* open rs232-device */
if ((cfg.fd_ser = open(cfg.ser_device, O_RDWR | O_NOCTTY | O_NONBLOCK)) <= 0) {
perror("init_ser(): open()");
exit(-1);
}
/* save old settings */
if (tcgetattr(cfg.fd_ser, &cfg.oldtio) != 0) {
perror("init_ser(): tcgetattr()");
exit(-1);
}
/* alte settings on exit wiederherstellen */
if (atexit(close_ser) != 0) {
perror("init_ser(): atexit()");
exit(-1);
}
/* neue settings */
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
newtio.c_lflag = 0; /* set input mode (non-canonical, no echo,...) */
newtio.c_cc[VTIME] = 100; /* inter-character timer unused */
newtio.c_cc[VMIN] = 100; /* blocking read until 5 chars received */
/* buffer flushen */
tcflush(cfg.fd_ser, TCIOFLUSH);
/* neue settings schreiben */
if (tcsetattr(cfg.fd_ser, TCSANOW, &newtio) != 0) {
perror("init_ser(): tcsetattr()");
exit(-1);
}
}
void close_ser() {
tcsetattr(cfg.fd_ser, TCSANOW, &cfg.oldtio);
close(cfg.fd_ser);
}
ssize_t read_ser(int fd, void *buf, size_t count) {
int timeouts = 10;
int mytimeout = TIMEOUT;
size_t myread = 0;
ssize_t retval;
while (count > 0 && timeouts > 0) {
usleep(mytimeout);
retval = read(fd, buf + myread, count);
if (retval > 0) {
myread+= retval;
count-= retval;
}
timeouts--;
mytimeout*= 2;
}
return myread;
}
void show_usage() {
CHIP *p = chips;
printf("USAGE:\n");
printf(" isp_down [OPTIONS] <flash-file> <eeprom-file>\n\n");
printf("OPTIONS:\n");
printf(" -avr <num> selects AVR-device\n");
while (p->shortname[0] != 0) {
printf(" %s -> %s %6d byte FLASH %4d byte EEPROM\n", p->shortname, p->longname, p->flash_size, p->eeprom_size);
p++;
}
printf(" -dev <dev> selects RS232-device (default: "DEVICE")\n");
printf(" -flash Write (1st) file to FLASH\n");
printf(" -eeprom Write (2nd) file to EEPROM\n");
printf(" -verify Verify writing\n");
printf(" -reset Only resets AVR\n");
printf(" -debug Prints debugging Information\n");
}
int main(int argc, char *argv[])
{
CHIP *p;
int arg;
/* Usage anzeigen */
if (argc <= 1) {
show_usage();
exit(-1);
}
/* cfg structur loeschen */
bzero(&cfg, sizeof(cfg));
cfg.ser_device = DEVICE;
for (arg = 1; arg < argc; arg++) {
if (!strcmp(argv[arg], "-avr")) {
/* check AVR-device */
if (++arg == argc) {
printf("ERROR: No AVR-Device\n\n");
exit(-1);
}
/* shortname suchen */
p = chips;
while (p->shortname[0] != 0) {
if (!strcmp(argv[arg], p->shortname)) {
cfg.avr = p;
break;
}
p++;
}
if (cfg.avr == NULL) {
printf(" ERROR: Unknown AVR-Device\n");
exit(-1);
}
} else if (!strcmp (argv[arg], "-dev")) {
/* check RS232 device */
if (++arg == argc) {
printf(" ERROR: No RS232-device\n");
exit(-1);
}
cfg.ser_device = argv[arg];
} else if (!strcmp (argv[arg], "-flash")) {
/* check flash */
if (++arg == argc) {
printf(" ERROR: No FLASH File\n");
exit(-1);
}
cfg.mode |= F_FLASH;
cfg.flash_file = argv[arg];
} else if (!strcmp (argv[arg], "-eeprom")) {
/* check eeprom */
if (++arg == argc) {
printf(" ERROR: No EEPROM File\n");
exit(-1);
}
cfg.mode |= F_EEPROM;
cfg.eeprom_file = argv[arg];
} else if (!strcmp (argv[arg], "-verify")) {
/* check verify */
cfg.mode |= F_VERIFY;
} else if (!strcmp (argv[arg], "-reset")) {
/* check reset */
cfg.mode |= F_RESET;
} else if (!strcmp (argv[arg], "-debug")) {
/* check debug */
debug= 1;
} else {
/* wrong parameter */
printf(" ERROR: Unknown parameter\n");
exit(-1);
}
}
if (!(cfg.mode & (F_FLASH | F_EEPROM | F_RESET))) {
printf (" ERROR: Nothing to do\n");
exit(-1);
}
if (cfg.mode & F_FLASH) {
if ((cfg.fd_flash = open(cfg.flash_file, O_RDONLY)) <= 0) {
perror("init_files(): open(flash_file)");
exit(-1);
}
}
if (cfg.mode & F_EEPROM) {
if ((cfg.fd_eeprom = open(cfg.eeprom_file, O_RDONLY)) <= 0) {
perror("init_files(): open(eeprom_file)");
exit(-1);
}
}
init_ser();
/* checken ob ein adapter vorhanden ist */
printf("checking avrisp\n");
if (isp_check(cfg.fd_ser)) {
printf(" ERROR: avr isp adapter not found\n");
exit(-1);
}
/* device code setzen */
printf("setting device code for %s\n", cfg.avr->longname);
if (isp_set_device(cfg.fd_ser, cfg.avr->devicecode)) {
printf(" ERROR: could not set device type\n");
exit(-1);
}
/* progammiermodus */
printf("entering programming mode\n");
if (isp_enter_progmode(cfg.fd_ser)) {
printf(" ERROR: could not enter programming mode\n");
exit(-1);
}
/* rote led an */
isp_led(cfg.fd_ser, 1);
atexit(isp_led_off);
/* signatur checken */
printf("checking signature\n");
if (isp_check_sig(cfg.fd_ser, cfg.avr->signature)) {
printf(" ERROR: wrong signature\n");
exit(-1);
}
/* chip loeschen */
if (cfg.mode & (F_FLASH | F_EEPROM)) {
printf("erase flash & eeprom\n");
if (isp_chip_erase(cfg.fd_ser)) {
printf(" ERROR: chip erase failed\n");
exit(-1);
}
}
/* progmode verlassen */
if (cfg.mode & (F_FLASH | F_EEPROM | F_RESET)) {
printf("resetting device\n");
if (isp_leave_progmode(cfg.fd_ser)) {
printf(" ERROR: device reset failed\n");
exit(-1);
}
}
/* -reset abgeschlossen */
if (cfg.mode & F_RESET) {
exit(0);
}
/* progammiermodus erneut aufrufen, da zwischenzeitlich reset */
if (cfg.mode & (F_FLASH | F_EEPROM)) {
printf("entering programming mode\n");
if (isp_enter_progmode(cfg.fd_ser)) {
printf(" ERROR: could not enter programming mode\n");
exit(-1);
}
}
if (cfg.mode & F_FLASH) {
int addr= 0;
char buf[2];
printf("programming flash\n");
while ((read(cfg.fd_flash, buf, 2) > 0) && (addr < (cfg.avr->flash_size/2))) {
if (isp_set_address(cfg.fd_ser, addr)) {
printf(" ERROR: could not set address %d\n", addr);
exit(-1);
}
if (isp_prg_flash(cfg.fd_ser, buf)) {
printf(" ERROR: programming failed on addr %d\n", addr);
exit(-1);
}
addr++;
}
printf("programming flash successful\n");
if (cfg.mode & F_VERIFY) {
addr= 0;
lseek(cfg.fd_flash, 0, SEEK_SET);
printf("verify flash\n");
while ((read(cfg.fd_flash, buf, 2) > 0) && (addr < (cfg.avr->flash_size/2))) {
if (isp_set_address(cfg.fd_ser, addr)) {
printf(" ERROR: could not set address %d\n", addr);
exit(-1);
}
if (isp_verify_flash(cfg.fd_ser, buf)) {
printf(" ERROR: verify failed on addr %d\n", addr);
exit(-1);
}
addr++;
}
printf("verify flash successful\n");
}
}
if (cfg.mode & F_EEPROM) {
int addr= 0;
char buf;
printf("programming eeprom\n");
while ((read(cfg.fd_eeprom, &buf, 1) > 0) && (addr < cfg.avr->eeprom_size)) {
if (isp_set_address(cfg.fd_ser, addr)) {
printf(" ERROR: could not set address %d\n", addr);
exit(-1);
}
if (isp_prg_eeprom(cfg.fd_ser, buf)) {
printf(" ERROR: programming failed on addr %d\n", addr);
exit(-1);
}
addr++;
}
printf("programming eeprom successful\n");
if (cfg.mode & F_EEPROM) {
addr= 0;
lseek(cfg.fd_eeprom, 0, SEEK_SET);
printf("verify eeprom\n");
while ((read(cfg.fd_eeprom, &buf, 1) > 0) && (addr < cfg.avr->eeprom_size)) {
if (isp_set_address(cfg.fd_ser, addr)) {
printf(" ERROR: could not set address %d\n", addr);
exit(-1);
}
if (isp_verify_eeprom(cfg.fd_ser, buf)) {
printf(" ERROR: verify failed on addr %d\n", addr);
exit(-1);
}
addr++;
}
printf("verify eeprom successful\n");
}
}
/* progmode verlassen */
printf("resetting device\n");
if (isp_leave_progmode(cfg.fd_ser)) {
printf(" ERROR: device reset failed\n");
exit(-1);
}
exit(0);
}