update esppilight lib
content of the library is not filtered on 433mhz only
This commit is contained in:
1 parent
a275e48ee1
commit
67dd7ac078
1030 files changed
+203335
-116
No files matched your search
@@ -0,0 +1,10 @@
|
||||
project(avrdude)
|
||||
|
||||
file(GLOB ${PROJECT_NAME}_sources "${PROJECT_SOURCE_DIR}/*.c")
|
||||
file(GLOB ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/*.h")
|
||||
|
||||
if(WIN32)
|
||||
list(REMOVE_ITEM ${PROJECT_NAME}_sources "${PROJECT_SOURCE_DIR}/avrgpio.c")
|
||||
endif()
|
||||
|
||||
set(${PROJECT_NAME}_files ${${PROJECT_NAME}_sources} ${${PROJECT_NAME}_headers} CACHE INTERNAL "")
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2009 Lars Immisch
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id: arduino.c 1294 2014-03-12 23:03:18Z joerg_wunsch $ */
|
||||
|
||||
/*
|
||||
* avrdude interface for Arduino programmer
|
||||
*
|
||||
* The Arduino programmer is mostly a STK500v1, just the signature bytes
|
||||
* are read differently.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "pgm.h"
|
||||
#include "stk500_private.h"
|
||||
#include "stk500.h"
|
||||
#include "serial.h"
|
||||
#include "arduino.h"
|
||||
#include "../pilight/core/log.h"
|
||||
|
||||
/* read signature bytes - arduino version */
|
||||
static int arduino_read_sig_bytes(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m) {
|
||||
unsigned char buf[32];
|
||||
|
||||
/* Signature byte reads are always 3 bytes. */
|
||||
|
||||
if(m->size < 3) {
|
||||
logprintf(LOG_ERR, "memsize too small for sig byte read");
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf[0] = Cmnd_STK_READ_SIGN;
|
||||
buf[1] = Sync_CRC_EOP;
|
||||
|
||||
serial_send(&pgm->fd, buf, 2);
|
||||
|
||||
if(serial_recv(&pgm->fd, buf, 5) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(buf[0] == Resp_STK_NOSYNC) {
|
||||
logprintf(LOG_ERR, "stk500_cmd(): programmer is out of sync");
|
||||
return -1;
|
||||
} else if (buf[0] != Resp_STK_INSYNC) {
|
||||
logprintf(LOG_ERR, "arduino_read_sig_bytes(): (a) protocol error, expect=0x%02x, resp=0x%02x", Resp_STK_INSYNC, buf[0]);
|
||||
return -2;
|
||||
}
|
||||
if(buf[4] != Resp_STK_OK) {
|
||||
logprintf(LOG_ERR, "arduino_read_sig_bytes(): (a) protocol error, expect=0x%02x, resp=0x%02x", Resp_STK_OK, buf[4]);
|
||||
return -3;
|
||||
}
|
||||
|
||||
m->buf[0] = buf[1];
|
||||
m->buf[1] = buf[2];
|
||||
m->buf[2] = buf[3];
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int arduino_open(PROGRAMMER * pgm, char * port) {
|
||||
union pinfo pinfo;
|
||||
strcpy(pgm->port, port);
|
||||
pinfo.baud = pgm->baudrate? pgm->baudrate: 115200;
|
||||
|
||||
if(serial_open(port, pinfo, &pgm->fd) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Clear DTR and RTS to unload the RESET capacitor
|
||||
* (for example in Arduino) */
|
||||
serial_set_dtr_rts(&pgm->fd, 0);
|
||||
usleep(250*1000);
|
||||
/* Set DTR and RTS back to high */
|
||||
serial_set_dtr_rts(&pgm->fd, 1);
|
||||
usleep(50*1000);
|
||||
|
||||
/*
|
||||
* drain any extraneous input
|
||||
*/
|
||||
stk500_drain(pgm, 0);
|
||||
|
||||
if(stk500_getsync(pgm) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void arduino_close(PROGRAMMER * pgm) {
|
||||
serial_set_dtr_rts(&pgm->fd, 0);
|
||||
serial_close(&pgm->fd);
|
||||
pgm->fd.ifd = -1;
|
||||
}
|
||||
|
||||
const char arduino_desc[] = "Arduino programmer";
|
||||
|
||||
void arduino_initpgm(PROGRAMMER * pgm) {
|
||||
/* This is mostly a STK500; just the signature is read
|
||||
differently than on real STK500v1
|
||||
and the DTR signal is set when opening the serial port
|
||||
for the Auto-Reset feature */
|
||||
stk500_initpgm(pgm);
|
||||
|
||||
strcpy(pgm->type, "Arduino");
|
||||
pgm->read_sig_bytes = arduino_read_sig_bytes;
|
||||
pgm->open = arduino_open;
|
||||
pgm->close = arduino_close;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2009 Lars Immisch
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id: arduino.h 1294 2014-03-12 23:03:18Z joerg_wunsch $ */
|
||||
|
||||
#ifndef arduino_h__
|
||||
#define arduino_h__
|
||||
|
||||
extern const char arduino_desc[];
|
||||
void arduino_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,915 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: avr.c 907 2010-01-12 15:42:40Z joerg_wunsch $ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
|
||||
#include "../pilight/core/log.h"
|
||||
#include "../pilight/core/common.h"
|
||||
#include "avr.h"
|
||||
#include "pindefs.h"
|
||||
#include "safemode.h"
|
||||
|
||||
FP_UpdateProgress avr_update_progress;
|
||||
|
||||
void avr_set_update_progress(FP_UpdateProgress callback) {
|
||||
avr_update_progress = callback;
|
||||
}
|
||||
|
||||
int parse_cmdbits(OPCODE * op, char *t) {
|
||||
int bitno;
|
||||
unsigned int n = 0, i = 0;
|
||||
char ch;
|
||||
char *e = NULL;
|
||||
char *q = NULL;
|
||||
int len;
|
||||
char **array = NULL;
|
||||
|
||||
bitno = 32;
|
||||
n = explode(t, " ", &array);
|
||||
for(i=0;i<n;i++) {
|
||||
bitno--;
|
||||
len = strlen(array[i]);
|
||||
ch = array[i][0];
|
||||
|
||||
if(len == 1) {
|
||||
switch(ch) {
|
||||
case '1':
|
||||
op->bit[bitno].type = AVR_CMDBIT_VALUE;
|
||||
op->bit[bitno].value = 1;
|
||||
op->bit[bitno].bitno = bitno % 8;
|
||||
break;
|
||||
case '0':
|
||||
op->bit[bitno].type = AVR_CMDBIT_VALUE;
|
||||
op->bit[bitno].value = 0;
|
||||
op->bit[bitno].bitno = bitno % 8;
|
||||
break;
|
||||
case 'x':
|
||||
op->bit[bitno].type = AVR_CMDBIT_IGNORE;
|
||||
op->bit[bitno].value = 0;
|
||||
op->bit[bitno].bitno = bitno % 8;
|
||||
break;
|
||||
case 'a':
|
||||
op->bit[bitno].type = AVR_CMDBIT_ADDRESS;
|
||||
op->bit[bitno].value = 0;
|
||||
op->bit[bitno].bitno = 8*(bitno/8) + bitno % 8;
|
||||
break;
|
||||
case 'i':
|
||||
op->bit[bitno].type = AVR_CMDBIT_INPUT;
|
||||
op->bit[bitno].value = 0;
|
||||
op->bit[bitno].bitno = bitno % 8;
|
||||
break;
|
||||
case 'o':
|
||||
op->bit[bitno].type = AVR_CMDBIT_OUTPUT;
|
||||
op->bit[bitno].value = 0;
|
||||
op->bit[bitno].bitno = bitno % 8;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(ch == 'a') {
|
||||
q = &array[i][1];
|
||||
op->bit[bitno].bitno = strtol(q, &e, 0);
|
||||
op->bit[bitno].type = AVR_CMDBIT_ADDRESS;
|
||||
op->bit[bitno].value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
array_free(&array, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int avr_read_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char * value)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
unsigned char data;
|
||||
OPCODE * readop, * lext;
|
||||
|
||||
if (pgm->cmd == NULL) {
|
||||
logprintf(LOG_ERR, "%s programmer uses avr_read_byte_default() but does not provide a cmd() method", pgm->type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* figure out what opcode to use
|
||||
*/
|
||||
if (mem->op[AVR_OP_READ_LO]) {
|
||||
if (addr & 0x00000001)
|
||||
readop = mem->op[AVR_OP_READ_HI];
|
||||
else
|
||||
readop = mem->op[AVR_OP_READ_LO];
|
||||
addr = addr / 2;
|
||||
}
|
||||
else {
|
||||
readop = mem->op[AVR_OP_READ];
|
||||
}
|
||||
|
||||
if (readop == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this device has a "load extended address" command, issue it.
|
||||
*/
|
||||
lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
|
||||
|
||||
if (lext != NULL) {
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
||||
avr_set_bits(lext, cmd);
|
||||
avr_set_addr(lext, cmd, addr);
|
||||
pgm->cmd(pgm, cmd, res);
|
||||
}
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
||||
avr_set_bits(readop, cmd);
|
||||
avr_set_addr(readop, cmd, addr);
|
||||
pgm->cmd(pgm, cmd, res);
|
||||
data = 0;
|
||||
avr_get_output(readop, res, &data);
|
||||
|
||||
*value = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the number of "interesting" bytes in a memory buffer,
|
||||
* "interesting" being defined as up to the last non-0xff data
|
||||
* value. This is useful for determining where to stop when dealing
|
||||
* with "flash" memory, since writing 0xff to flash is typically a
|
||||
* no-op. Always return an even number since flash is word addressed.
|
||||
*/
|
||||
int avr_mem_hiaddr(AVRMEM * mem)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
/* return the highest non-0xff address regardless of how much
|
||||
memory was read */
|
||||
for (i=mem->size-1; i>0; i--) {
|
||||
if (mem->buf[i] != 0xff) {
|
||||
n = i+1;
|
||||
if (n & 0x01)
|
||||
return n+1;
|
||||
else
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the entirety of the specified memory type into the
|
||||
* corresponding buffer of the avrpart pointed to by 'p'. If size =
|
||||
* 0, read the entire contents, otherwise, read 'size' bytes.
|
||||
*
|
||||
* Return the number of bytes read, or < 0 if an error occurs.
|
||||
*/
|
||||
int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size)
|
||||
{
|
||||
int wsize;
|
||||
unsigned char rbyte;
|
||||
unsigned long i;
|
||||
unsigned char * buf;
|
||||
AVRMEM * mem = NULL;
|
||||
int rc;
|
||||
|
||||
/* NEW */
|
||||
if(strcmp(memtype, "signature") == 0) {
|
||||
mem = p->sigmem;
|
||||
} else if(strcmp(memtype, "flash") == 0) {
|
||||
mem = p->flashmem;
|
||||
} else if(strcmp(memtype, "lfuse") == 0) {
|
||||
mem = p->lfusemem;
|
||||
} else if(strcmp(memtype, "hfuse") == 0) {
|
||||
mem = p->hfusemem;
|
||||
}
|
||||
// mem = avr_locate_mem(p, memtype);
|
||||
if (mem == NULL) {
|
||||
logprintf(LOG_ERR, "No \"%s\" memory for part %s", memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wsize = mem->size;
|
||||
if (size < wsize) {
|
||||
wsize = size;
|
||||
}
|
||||
|
||||
buf = mem->buf;
|
||||
if (size == 0) {
|
||||
size = mem->size;
|
||||
}
|
||||
|
||||
/*
|
||||
* start with all 0xff
|
||||
*/
|
||||
memset(buf, 0xff, size);
|
||||
|
||||
if (pgm->paged_load != NULL && mem->page_size != 0) {
|
||||
/*
|
||||
* the programmer supports a paged mode read
|
||||
*/
|
||||
int need_read, failure;
|
||||
unsigned int pageaddr;
|
||||
unsigned int npages, nread;
|
||||
|
||||
/* quickly scan number of pages to be written to first */
|
||||
for (pageaddr = 0, npages = 0;
|
||||
pageaddr < wsize;
|
||||
pageaddr += mem->page_size) {
|
||||
/* check whether this page must be read */
|
||||
for (i = pageaddr;
|
||||
i < pageaddr + mem->page_size;
|
||||
i++)
|
||||
if (i < mem->size) {
|
||||
npages++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (pageaddr = 0, failure = 0, nread = 0;
|
||||
!failure && pageaddr < wsize;
|
||||
pageaddr += mem->page_size) {
|
||||
/* check whether this page must be read */
|
||||
for (i = pageaddr, need_read = 0;
|
||||
i < pageaddr + mem->page_size;
|
||||
i++)
|
||||
if (i < mem->size) {
|
||||
need_read = 1;
|
||||
break;
|
||||
}
|
||||
if (need_read) {
|
||||
rc = pgm->paged_load(pgm, p, mem, mem->page_size,
|
||||
pageaddr, mem->page_size);
|
||||
if (rc < 0)
|
||||
/* paged load failed, fall back to byte-at-a-time read below */
|
||||
failure = 1;
|
||||
}
|
||||
nread++;
|
||||
report_progress(nread, npages, NULL);
|
||||
}
|
||||
if (!failure) {
|
||||
if (strcasecmp(mem->desc, "flash") == 0 ||
|
||||
strcasecmp(mem->desc, "application") == 0 ||
|
||||
strcasecmp(mem->desc, "apptable") == 0 ||
|
||||
strcasecmp(mem->desc, "boot") == 0)
|
||||
return avr_mem_hiaddr(mem);
|
||||
else
|
||||
return mem->size;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(mem->desc, "signature") == 0) {
|
||||
if (pgm->read_sig_bytes) {
|
||||
return pgm->read_sig_bytes(pgm, p, mem);
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<size; i++) {
|
||||
rc = pgm->read_byte(pgm, p, mem, i, &rbyte);
|
||||
if (rc != 0) {
|
||||
logprintf(LOG_ERR, "avr_read(): error reading address 0x%04lx", i);
|
||||
if (rc == -1)
|
||||
logprintf(LOG_ERR, "read operation not supported for memory \"%s\"", memtype);
|
||||
return -2;
|
||||
}
|
||||
buf[i] = rbyte;
|
||||
report_progress(i, size, NULL);
|
||||
}
|
||||
|
||||
if (strcasecmp(mem->desc, "flash") == 0)
|
||||
return avr_mem_hiaddr(mem);
|
||||
else
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* write a page data at the specified address
|
||||
*/
|
||||
int avr_write_page(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
OPCODE * wp, * lext;
|
||||
|
||||
if (pgm->cmd == NULL) {
|
||||
logprintf(LOG_ERR, "%s programmer uses avr_write_page() but does not provide a cmd() method", pgm->type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wp = mem->op[AVR_OP_WRITEPAGE];
|
||||
if (wp == NULL) {
|
||||
logprintf(LOG_ERR, "avr_write_page(): memory \"%s\" not configured for page writes", mem->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* if this memory is word-addressable, adjust the address
|
||||
* accordingly
|
||||
*/
|
||||
if ((mem->op[AVR_OP_LOADPAGE_LO]) || (mem->op[AVR_OP_READ_LO]))
|
||||
addr = addr / 2;
|
||||
|
||||
/*
|
||||
* If this device has a "load extended address" command, issue it.
|
||||
*/
|
||||
lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
|
||||
if (lext != NULL) {
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
||||
avr_set_bits(lext, cmd);
|
||||
avr_set_addr(lext, cmd, addr);
|
||||
pgm->cmd(pgm, cmd, res);
|
||||
}
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
||||
avr_set_bits(wp, cmd);
|
||||
avr_set_addr(wp, cmd, addr);
|
||||
pgm->cmd(pgm, cmd, res);
|
||||
|
||||
/*
|
||||
* since we don't know what voltage the target AVR is powered by, be
|
||||
* conservative and delay the max amount the spec says to wait
|
||||
*/
|
||||
usleep(mem->max_write_delay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char data)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
unsigned char r;
|
||||
int ready;
|
||||
int tries;
|
||||
unsigned long start_time;
|
||||
unsigned long prog_time;
|
||||
unsigned char b;
|
||||
unsigned short caddr;
|
||||
OPCODE * writeop;
|
||||
int rc;
|
||||
int readok=0;
|
||||
struct timeval tv;
|
||||
|
||||
if (pgm->cmd == NULL) {
|
||||
logprintf(LOG_ERR, "%s programmer uses avr_write_byte_default() but does not provide a cmd() method.", pgm->type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!mem->paged) {
|
||||
/*
|
||||
* check to see if the write is necessary by reading the existing
|
||||
* value and only write if we are changing the value; we can't
|
||||
* use this optimization for paged addressing.
|
||||
*/
|
||||
rc = pgm->read_byte(pgm, p, mem, addr, &b);
|
||||
if (rc != 0) {
|
||||
if (rc != -1) {
|
||||
return -2;
|
||||
}
|
||||
/*
|
||||
* the read operation is not support on this memory type
|
||||
*/
|
||||
}
|
||||
else {
|
||||
readok = 1;
|
||||
if (b == data) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* determine which memory opcode to use
|
||||
*/
|
||||
if (mem->op[AVR_OP_WRITE_LO]) {
|
||||
if (addr & 0x01)
|
||||
writeop = mem->op[AVR_OP_WRITE_HI];
|
||||
else
|
||||
writeop = mem->op[AVR_OP_WRITE_LO];
|
||||
caddr = addr / 2;
|
||||
}
|
||||
else if (mem->paged && mem->op[AVR_OP_LOADPAGE_LO]) {
|
||||
if (addr & 0x01)
|
||||
writeop = mem->op[AVR_OP_LOADPAGE_HI];
|
||||
else
|
||||
writeop = mem->op[AVR_OP_LOADPAGE_LO];
|
||||
caddr = addr / 2;
|
||||
}
|
||||
else {
|
||||
writeop = mem->op[AVR_OP_WRITE];
|
||||
caddr = addr;
|
||||
}
|
||||
|
||||
if (writeop == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
||||
avr_set_bits(writeop, cmd);
|
||||
avr_set_addr(writeop, cmd, caddr);
|
||||
avr_set_input(writeop, cmd, data);
|
||||
pgm->cmd(pgm, cmd, res);
|
||||
|
||||
if (mem->paged) {
|
||||
/*
|
||||
* in paged addressing, single bytes to be written to the memory
|
||||
* page complete immediately, we only need to delay when we commit
|
||||
* the whole page via the avr_write_page() routine.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (readok == 0) {
|
||||
/*
|
||||
* read operation not supported for this memory type, just wait
|
||||
* the max programming time and then return
|
||||
*/
|
||||
usleep(mem->max_write_delay); /* maximum write delay */
|
||||
return 0;
|
||||
}
|
||||
|
||||
tries = 0;
|
||||
ready = 0;
|
||||
while (!ready) {
|
||||
|
||||
if ((data == mem->readback[0]) ||
|
||||
(data == mem->readback[1])) {
|
||||
/*
|
||||
* use an extra long delay when we happen to be writing values
|
||||
* used for polled data read-back. In this case, polling
|
||||
* doesn't work, and we need to delay the worst case write time
|
||||
* specified for the chip.
|
||||
*/
|
||||
usleep(mem->max_write_delay);
|
||||
rc = pgm->read_byte(pgm, p, mem, addr, &r);
|
||||
if (rc != 0) {
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
else {
|
||||
gettimeofday (&tv, NULL);
|
||||
start_time = (tv.tv_sec * 1000000) + tv.tv_usec;
|
||||
do {
|
||||
/*
|
||||
* Do polling, but timeout after max_write_delay.
|
||||
*/
|
||||
rc = pgm->read_byte(pgm, p, mem, addr, &r);
|
||||
if (rc != 0) {
|
||||
return -4;
|
||||
}
|
||||
gettimeofday (&tv, NULL);
|
||||
prog_time = (tv.tv_sec * 1000000) + tv.tv_usec;
|
||||
} while ((r != data) &&
|
||||
((prog_time-start_time) < mem->max_write_delay));
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point we either have a valid readback or the
|
||||
* max_write_delay is expired.
|
||||
*/
|
||||
|
||||
if (r == data) {
|
||||
ready = 1;
|
||||
}
|
||||
else if (mem->pwroff_after_write) {
|
||||
/*
|
||||
* The device has been flagged as power-off after write to this
|
||||
* memory type. The reason we don't just blindly follow the
|
||||
* flag is that the power-off advice may only apply to some
|
||||
* memory bits but not all. We only actually power-off the
|
||||
* device if the data read back does not match what we wrote.
|
||||
*/
|
||||
logprintf(LOG_NOTICE, "this device must be powered off and back on to continue");
|
||||
if (pgm->pinno[PPI_AVR_VCC]) {
|
||||
logprintf(LOG_NOTICE, "attempting to do this now ...");
|
||||
pgm->powerdown(pgm);
|
||||
usleep(250000);
|
||||
rc = pgm->initialize(pgm, p);
|
||||
if (rc < 0) {
|
||||
logprintf(LOG_ERR, "initialization failed, rc=%d", rc);
|
||||
logprintf(LOG_ERR, "can't re-initialize device after programming the %s bits", mem->desc);
|
||||
return -3;
|
||||
}
|
||||
|
||||
logprintf(LOG_NOTICE, "device was successfully re-initialized");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
tries++;
|
||||
if (!ready && tries > 5) {
|
||||
/*
|
||||
* we wrote the data, but after waiting for what should have
|
||||
* been plenty of time, the memory cell still doesn't match what
|
||||
* we wrote. Indicate a write error.
|
||||
*/
|
||||
return -6;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* write a byte of data at the specified address
|
||||
*/
|
||||
int avr_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char data)
|
||||
{
|
||||
|
||||
unsigned char safemode_lfuse;
|
||||
unsigned char safemode_hfuse;
|
||||
unsigned char safemode_efuse;
|
||||
unsigned char safemode_fuse;
|
||||
|
||||
/* If we write the fuses, then we need to tell safemode that they *should* change */
|
||||
safemode_memfuses(0, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
|
||||
|
||||
if (strcmp(mem->desc, "fuse")==0) {
|
||||
safemode_fuse = data;
|
||||
}
|
||||
if (strcmp(mem->desc, "lfuse")==0) {
|
||||
safemode_lfuse = data;
|
||||
}
|
||||
if (strcmp(mem->desc, "hfuse")==0) {
|
||||
safemode_hfuse = data;
|
||||
}
|
||||
if (strcmp(mem->desc, "efuse")==0) {
|
||||
safemode_efuse = data;
|
||||
}
|
||||
|
||||
safemode_memfuses(1, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
|
||||
|
||||
return pgm->write_byte(pgm, p, mem, addr, data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write the whole memory region of the specified memory from the
|
||||
* corresponding buffer of the avrpart pointed to by 'p'. Write up to
|
||||
* 'size' bytes from the buffer. Data is only written if the new data
|
||||
* value is different from the existing data value. Data beyond
|
||||
* 'size' bytes is not affected.
|
||||
*
|
||||
* Return the number of bytes written, or -1 if an error occurs.
|
||||
*/
|
||||
int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size)
|
||||
{
|
||||
int rc;
|
||||
int wsize;
|
||||
long i;
|
||||
unsigned char data;
|
||||
AVRMEM * m = NULL;
|
||||
|
||||
/* NEW */
|
||||
if(strcmp(memtype, "flash") == 0) {
|
||||
m = p->flashmem;
|
||||
} else if(strcmp(memtype, "lfuse") == 0) {
|
||||
m = p->lfusemem;
|
||||
} else if(strcmp(memtype, "hfuse") == 0) {
|
||||
m = p->hfusemem;
|
||||
}
|
||||
|
||||
if (m == NULL) {
|
||||
logprintf(LOG_ERR, "No \"%s\" memory for part %s", memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wsize = m->size;
|
||||
if (size < wsize) {
|
||||
wsize = size;
|
||||
}
|
||||
else if (size > wsize) {
|
||||
logprintf(LOG_ERR, "%d bytes requested, but memory region is only %d bytes", size, wsize);
|
||||
logprintf(LOG_ERR, "Only %d bytes will actually be written", wsize);
|
||||
}
|
||||
|
||||
if (pgm->paged_write != NULL && m->page_size != 0) {
|
||||
/*
|
||||
* the programmer supports a paged mode write
|
||||
*/
|
||||
int need_write, failure;
|
||||
unsigned int pageaddr;
|
||||
unsigned int npages, nwritten;
|
||||
|
||||
/* quickly scan number of pages to be written to first */
|
||||
for (pageaddr = 0, npages = 0;
|
||||
pageaddr < wsize;
|
||||
pageaddr += m->page_size) {
|
||||
/* check whether this page must be written to */
|
||||
for (i = pageaddr;
|
||||
i < pageaddr + m->page_size;
|
||||
i++)
|
||||
if (i < m->size) {
|
||||
npages++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (pageaddr = 0, failure = 0, nwritten = 0;
|
||||
!failure && pageaddr < wsize;
|
||||
pageaddr += m->page_size) {
|
||||
/* check whether this page must be written to */
|
||||
for (i = pageaddr, need_write = 0;
|
||||
i < pageaddr + m->page_size;
|
||||
i++)
|
||||
if (i < m->size) {
|
||||
need_write = 1;
|
||||
break;
|
||||
}
|
||||
if (need_write) {
|
||||
rc = 0;
|
||||
if (rc >= 0)
|
||||
rc = pgm->paged_write(pgm, p, m, m->page_size, pageaddr, m->page_size);
|
||||
if (rc < 0)
|
||||
/* paged write failed, fall back to byte-at-a-time write below */
|
||||
failure = 1;
|
||||
}
|
||||
nwritten++;
|
||||
report_progress(nwritten, npages, NULL);
|
||||
}
|
||||
if (!failure)
|
||||
return wsize;
|
||||
/* else: fall back to byte-at-a-time write, for historical reasons */
|
||||
}
|
||||
|
||||
if (pgm->write_setup) {
|
||||
pgm->write_setup(pgm, p, m);
|
||||
}
|
||||
|
||||
for (i=0; i<wsize; i++) {
|
||||
data = m->buf[i];
|
||||
report_progress(i, wsize, NULL);
|
||||
|
||||
rc = avr_write_byte(pgm, p, m, i, data);
|
||||
if (rc) {
|
||||
logprintf(LOG_ERR, "***failed");
|
||||
}
|
||||
|
||||
if (m->paged) {
|
||||
/*
|
||||
* check to see if it is time to flush the page with a page
|
||||
* write
|
||||
*/
|
||||
if (((i % m->page_size) == m->page_size-1) ||
|
||||
(i == wsize-1)) {
|
||||
rc = avr_write_page(pgm, p, m, i);
|
||||
if (rc) {
|
||||
logprintf(LOG_ERR, " *** page %ld (addresses 0x%04lx - 0x%04lx) failed to write",
|
||||
i % m->page_size,
|
||||
i - m->page_size + 1, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* read the AVR device's signature bytes
|
||||
*/
|
||||
int avr_signature(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
int rc;
|
||||
|
||||
report_progress (0,1,"Reading");
|
||||
rc = avr_read(pgm, p, "signature", 0);
|
||||
if (rc < 0) {
|
||||
logprintf(LOG_ERR, "error reading signature data for part \"%s\", rc=%d", p->desc, rc);
|
||||
return -1;
|
||||
}
|
||||
report_progress (1,1,NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Verify the memory buffer of p with that of v. The byte range of v,
|
||||
* may be a subset of p. The byte range of p should cover the whole
|
||||
* chip's memory size.
|
||||
*
|
||||
* Return the number of bytes verified, or -1 if they don't match.
|
||||
*/
|
||||
int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size)
|
||||
{
|
||||
int i;
|
||||
unsigned char * buf1, * buf2;
|
||||
int vsize;
|
||||
AVRMEM * a = NULL, * b = NULL;
|
||||
|
||||
/* NEW */
|
||||
if(strcmp(memtype, "flash") == 0) {
|
||||
a = p->flashmem;
|
||||
} else if(strcmp(memtype, "lfuse") == 0) {
|
||||
a = p->lfusemem;
|
||||
} else if(strcmp(memtype, "hfuse") == 0) {
|
||||
a = p->hfusemem;
|
||||
}
|
||||
if (a == NULL) {
|
||||
logprintf(LOG_ERR, "No \"%s\" memory for part %s", memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* NEW */
|
||||
if(strcmp(memtype, "flash") == 0) {
|
||||
b = v->flashmem;
|
||||
} else if(strcmp(memtype, "lfuse") == 0) {
|
||||
b = v->lfusemem;
|
||||
} else if(strcmp(memtype, "hfuse") == 0) {
|
||||
b = v->hfusemem;
|
||||
}
|
||||
if (b == NULL) {
|
||||
logprintf(LOG_ERR, "No \"%s\" memory for part %s", memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf1 = a->buf;
|
||||
buf2 = b->buf;
|
||||
vsize = a->size;
|
||||
|
||||
if (vsize < size) {
|
||||
logprintf(LOG_ERR, "requested verification for %d bytes", size);
|
||||
logprintf(LOG_ERR, "%s memory region only contains %d bytes", memtype, vsize);
|
||||
logprintf(LOG_ERR, "Only %d bytes will be verified.", vsize);
|
||||
size = vsize;
|
||||
}
|
||||
|
||||
for (i=0; i<size; i++) {
|
||||
if (buf1[i] != buf2[i]) {
|
||||
logprintf(LOG_ERR, "verification error, first mismatch at byte 0x%04x", i);
|
||||
logprintf(LOG_ERR, "0x%02x != 0x%02x", buf1[i], buf2[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
int avr_get_cycle_count(PROGRAMMER * pgm, AVRPART * p, int * cycles)
|
||||
{
|
||||
AVRMEM * a = NULL;
|
||||
unsigned int cycle_count = 0;
|
||||
unsigned char v1;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
// a = avr_locate_mem(p, "eeprom");
|
||||
if (a == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=4; i>0; i--) {
|
||||
rc = pgm->read_byte(pgm, p, a, a->size-i, &v1);
|
||||
if (rc < 0) {
|
||||
logprintf(LOG_ERR, "can't read memory for cycle count, rc=%d", rc);
|
||||
return -1;
|
||||
}
|
||||
cycle_count = (cycle_count << 8) | v1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the EEPROM is erased, the cycle count reads 0xffffffff.
|
||||
* In this case we return a cycle_count of zero.
|
||||
* So, the calling function don't have to care about whether or not
|
||||
* the cycle count was initialized.
|
||||
*/
|
||||
if (cycle_count == 0xffffffff) {
|
||||
cycle_count = 0;
|
||||
}
|
||||
|
||||
*cycles = (int) cycle_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles)
|
||||
{
|
||||
AVRMEM * a = NULL;
|
||||
unsigned char v1;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
// a = avr_locate_mem(p, "eeprom");
|
||||
if (a == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=1; i<=4; i++) {
|
||||
v1 = cycles & 0xff;
|
||||
cycles = cycles >> 8;
|
||||
|
||||
rc = avr_write_byte(pgm, p, a, a->size-i, v1);
|
||||
if (rc < 0) {
|
||||
logprintf(LOG_ERR, "can't write memory for cycle count, rc=%d", rc);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int avr_chip_erase(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pgm->chip_erase(pgm, p);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Report the progress of a read or write operation from/to the
|
||||
* device.
|
||||
*
|
||||
* The first call of report_progress() should look like this (for a write op):
|
||||
*
|
||||
* report_progress (0, 1, "Writing");
|
||||
*
|
||||
* Then hdr should be passed NULL on subsequent calls while the
|
||||
* operation is progressing. Once the operation is complete, a final
|
||||
* call should be made as such to ensure proper termination of the
|
||||
* progress report:
|
||||
*
|
||||
* report_progress (1, 1, NULL);
|
||||
*
|
||||
* It would be nice if we could reduce the usage to one and only one
|
||||
* call for each of start, during and end cases. As things stand now,
|
||||
* that is not possible and makes maintenance a bit more work.
|
||||
*/
|
||||
void report_progress (int completed, int total, char *hdr)
|
||||
{
|
||||
static int last = 0;
|
||||
static double start_time;
|
||||
int percent = (completed * 100) / total;
|
||||
struct timeval tv;
|
||||
double t;
|
||||
|
||||
if (avr_update_progress == NULL)
|
||||
return;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
t = tv.tv_sec + ((double)tv.tv_usec)/1000000;
|
||||
|
||||
if (hdr) {
|
||||
last = 0;
|
||||
start_time = t;
|
||||
avr_update_progress (percent, t - start_time, hdr);
|
||||
}
|
||||
|
||||
if (percent > 100)
|
||||
percent = 100;
|
||||
|
||||
if (percent > last) {
|
||||
last = percent;
|
||||
avr_update_progress (percent, t - start_time, hdr);
|
||||
}
|
||||
|
||||
if (percent == 100)
|
||||
last = 0; /* Get ready for next time. */
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: avr.h 804 2009-02-23 22:04:57Z joerg_wunsch $ */
|
||||
|
||||
#ifndef __avr_h__
|
||||
#define __avr_h__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "avrpart.h"
|
||||
#include "pgm.h"
|
||||
|
||||
typedef void (*FP_UpdateProgress)(int percent, double etime, char *hdr);
|
||||
|
||||
extern struct avrpart parts[];
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void avr_set_update_progress(FP_UpdateProgress callback);
|
||||
|
||||
int parse_cmdbits(OPCODE * op, char *t);
|
||||
|
||||
int avr_read_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char * value);
|
||||
|
||||
int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size);
|
||||
|
||||
int avr_write_page(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr);
|
||||
|
||||
int avr_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char data);
|
||||
|
||||
int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char data);
|
||||
|
||||
int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size);
|
||||
|
||||
int avr_signature(PROGRAMMER * pgm, AVRPART * p);
|
||||
|
||||
int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size);
|
||||
|
||||
int avr_get_cycle_count(PROGRAMMER * pgm, AVRPART * p, int * cycles);
|
||||
|
||||
int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles);
|
||||
|
||||
int avr_mem_hiaddr(AVRMEM * mem);
|
||||
|
||||
int avr_chip_erase(PROGRAMMER * pgm, AVRPART * p);
|
||||
|
||||
void report_progress (int completed, int total, char *hdr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
/* $Id: bitbang.c 898 2010-01-08 20:02:35Z joerg_wunsch $ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "../pilight/core/log.h"
|
||||
#include "../pilight/core/mem.h"
|
||||
#include "avrdude.h"
|
||||
#include "avr.h"
|
||||
#include "pindefs.h"
|
||||
#include "pgm.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
struct itimerval {
|
||||
struct timeval it_value, it_interval;
|
||||
};
|
||||
#define SIGALRM 14
|
||||
#define ITIMER_REAL 0
|
||||
#endif
|
||||
|
||||
static int delay_decrement;
|
||||
static volatile int done;
|
||||
|
||||
typedef void (*mysighandler_t)(int);
|
||||
static mysighandler_t saved_alarmhandler;
|
||||
|
||||
static void alarmhandler(int signo)
|
||||
{
|
||||
done = 1;
|
||||
signal(SIGALRM, saved_alarmhandler);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calibrate the microsecond delay loop below.
|
||||
*/
|
||||
static void bitbang_calibrate_delay(void)
|
||||
{
|
||||
struct itimerval itv;
|
||||
volatile int i;
|
||||
|
||||
i = 0;
|
||||
done = 0;
|
||||
saved_alarmhandler = signal(SIGALRM, alarmhandler);
|
||||
/*
|
||||
* Set ITIMER_REAL to 100 ms. All known systems have a timer
|
||||
* granularity of 10 ms or better, so counting the delay cycles
|
||||
* accumulating over 100 ms should give us a rather realistic
|
||||
* picture, without annoying the user by a lengthy startup time (as
|
||||
* an alarm(1) would do). Of course, if heavy system activity
|
||||
* happens just during calibration but stops before the remaining
|
||||
* part of AVRDUDE runs, this will yield wrong values. There's not
|
||||
* much we can do about this.
|
||||
*/
|
||||
itv.it_value.tv_sec = 0;
|
||||
itv.it_value.tv_usec = 100000;
|
||||
itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0;
|
||||
#ifndef _WIN32
|
||||
setitimer(ITIMER_REAL, &itv, 0);
|
||||
#endif
|
||||
while (!done)
|
||||
i--;
|
||||
itv.it_value.tv_sec = itv.it_value.tv_usec = 0;
|
||||
#ifndef _WIN32
|
||||
setitimer(ITIMER_REAL, &itv, 0);
|
||||
#endif
|
||||
/*
|
||||
* Calculate back from 100 ms to 1 us.
|
||||
*/
|
||||
delay_decrement = -i / 100000;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delay for approximately the number of microseconds specified.
|
||||
* usleep()'s granularity is usually like 1 ms or 10 ms, so it's not
|
||||
* really suitable for short delays in bit-bang algorithms.
|
||||
*/
|
||||
void bitbang_delay(int us)
|
||||
{
|
||||
volatile int del = us * delay_decrement;
|
||||
|
||||
while (del > 0)
|
||||
del--;
|
||||
}
|
||||
|
||||
/*
|
||||
* transmit and receive a byte of data to/from the AVR device
|
||||
*/
|
||||
static unsigned char bitbang_txrx(PROGRAMMER * pgm, unsigned char byte)
|
||||
{
|
||||
int i;
|
||||
unsigned char r, b, rbyte;
|
||||
|
||||
rbyte = 0;
|
||||
for (i=7; i>=0; i--) {
|
||||
/*
|
||||
* Write and read one bit on SPI.
|
||||
* Some notes on timing: Let T be the time it takes to do
|
||||
* one pgm->setpin()-call resp. par clrpin()-call, then
|
||||
* - SCK is high for 2T
|
||||
* - SCK is low for 2T
|
||||
* - MOSI setuptime is 1T
|
||||
* - MOSI holdtime is 3T
|
||||
* - SCK low to MISO read is 2T to 3T
|
||||
* So we are within programming specs (expect for AT90S1200),
|
||||
* if and only if T>t_CLCL (t_CLCL=clock period of target system).
|
||||
*
|
||||
* Due to the delay introduced by "IN" and "OUT"-commands,
|
||||
* T is greater than 1us (more like 2us) on x86-architectures.
|
||||
* So programming works safely down to 1MHz target clock.
|
||||
*/
|
||||
|
||||
b = (byte >> i) & 0x01;
|
||||
|
||||
/* set the data input line as desired */
|
||||
pgm->setpin(pgm, pgm->pinno[PIN_AVR_MOSI], b);
|
||||
|
||||
pgm->setpin(pgm, pgm->pinno[PIN_AVR_SCK], 1);
|
||||
|
||||
/*
|
||||
* read the result bit (it is either valid from a previous falling
|
||||
* edge or it is ignored in the current context)
|
||||
*/
|
||||
r = pgm->getpin(pgm, pgm->pinno[PIN_AVR_MISO]);
|
||||
|
||||
pgm->setpin(pgm, pgm->pinno[PIN_AVR_SCK], 0);
|
||||
|
||||
rbyte |= r << i;
|
||||
}
|
||||
|
||||
return rbyte;
|
||||
}
|
||||
|
||||
|
||||
int bitbang_rdy_led(PROGRAMMER * pgm, int value)
|
||||
{
|
||||
// pgm->setpin(pgm, pgm->pinno[PIN_LED_RDY], !value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bitbang_err_led(PROGRAMMER * pgm, int value)
|
||||
{
|
||||
// pgm->setpin(pgm, pgm->pinno[PIN_LED_ERR], !value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bitbang_pgm_led(PROGRAMMER * pgm, int value)
|
||||
{
|
||||
// pgm->setpin(pgm, pgm->pinno[PIN_LED_PGM], !value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bitbang_vfy_led(PROGRAMMER * pgm, int value)
|
||||
{
|
||||
// pgm->setpin(pgm, pgm->pinno[PIN_LED_VFY], !value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* transmit an AVR device command and return the results; 'cmd' and
|
||||
* 'res' must point to at least a 4 byte data buffer
|
||||
*/
|
||||
int bitbang_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
|
||||
unsigned char res[4])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
res[i] = bitbang_txrx(pgm, cmd[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* transmit bytes via SPI and return the results; 'cmd' and
|
||||
* 'res' must point to data buffers
|
||||
*/
|
||||
int bitbang_spi(PROGRAMMER * pgm, unsigned char cmd[],
|
||||
unsigned char res[], int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
pgm->setpin(pgm, pgm->pinno[PIN_LED_PGM], 0);
|
||||
|
||||
for (i=0; i<count; i++) {
|
||||
res[i] = bitbang_txrx(pgm, cmd[i]);
|
||||
}
|
||||
|
||||
pgm->setpin(pgm, pgm->pinno[PIN_LED_PGM], 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* issue the 'chip erase' command to the AVR device
|
||||
*/
|
||||
int bitbang_chip_erase(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
|
||||
if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
|
||||
logprintf(LOG_ERR, "chip erase instruction not defined for part \"%s\"", p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pgm->pgm_led(pgm, ON);
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
||||
avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
|
||||
pgm->cmd(pgm, cmd, res);
|
||||
usleep(p->chip_erase_delay);
|
||||
pgm->initialize(pgm, p);
|
||||
|
||||
pgm->pgm_led(pgm, OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* issue the 'program enable' command to the AVR device
|
||||
*/
|
||||
int bitbang_program_enable(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
|
||||
if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
|
||||
logprintf(LOG_ERR, "program enable instruction not defined for part \"%s\"", p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd);
|
||||
pgm->cmd(pgm, cmd, res);
|
||||
|
||||
if (res[2] != cmd[1])
|
||||
return -2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize the AVR device and prepare it to accept commands
|
||||
*/
|
||||
int bitbang_initialize(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
int rc;
|
||||
int tries;
|
||||
|
||||
bitbang_calibrate_delay();
|
||||
|
||||
pgm->powerup(pgm);
|
||||
usleep(20000);
|
||||
|
||||
pgm->setpin(pgm, pgm->pinno[PIN_AVR_SCK], 0);
|
||||
pgm->setpin(pgm, pgm->pinno[PIN_AVR_RESET], 0);
|
||||
usleep(20000);
|
||||
|
||||
pgm->highpulsepin(pgm, pgm->pinno[PIN_AVR_RESET]);
|
||||
|
||||
usleep(20000); /* 20 ms XXX should be a per-chip parameter */
|
||||
|
||||
/*
|
||||
* Enable programming mode. If we are programming an AT90S1200, we
|
||||
* can only issue the command and hope it worked. If we are using
|
||||
* one of the other chips, the chip will echo 0x53 when issuing the
|
||||
* third byte of the command. In this case, try up to 32 times in
|
||||
* order to possibly get back into sync with the chip if we are out
|
||||
* of sync.
|
||||
*/
|
||||
|
||||
if (strcmp(p->desc, "AT90S1200")==0) {
|
||||
pgm->program_enable(pgm, p);
|
||||
}
|
||||
else {
|
||||
tries = 0;
|
||||
do {
|
||||
rc = pgm->program_enable(pgm, p);
|
||||
if ((rc == 0)||(rc == -1))
|
||||
break;
|
||||
pgm->highpulsepin(pgm, pgm->pinno[p->retry_pulse/*PIN_AVR_SCK*/]);
|
||||
tries++;
|
||||
} while (tries < 65);
|
||||
|
||||
/*
|
||||
* can't sync with the device, maybe it's not attached?
|
||||
*/
|
||||
if (rc) {
|
||||
logprintf(LOG_ERR, "AVR device not responding");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void verify_pin_assigned(PROGRAMMER * pgm, int pin, char * desc)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Verify all prerequisites for a bit-bang programmer are present.
|
||||
*/
|
||||
void bitbang_check_prerequisites(PROGRAMMER *pgm)
|
||||
{
|
||||
verify_pin_assigned(pgm, PIN_AVR_RESET, "AVR RESET");
|
||||
verify_pin_assigned(pgm, PIN_AVR_SCK, "AVR SCK");
|
||||
verify_pin_assigned(pgm, PIN_AVR_MISO, "AVR MISO");
|
||||
verify_pin_assigned(pgm, PIN_AVR_MOSI, "AVR MOSI");
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
/* $Id: bitbang.h 797 2009-02-17 15:31:27Z joerg_wunsch $ */
|
||||
|
||||
#ifndef avrbitbang_h
|
||||
#define avrbitbang_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bitbang_setpin(int fd, int pin, int value);
|
||||
int bitbang_getpin(int fd, int pin);
|
||||
int bitbang_highpulsepin(int fd, int pin);
|
||||
void bitbang_delay(unsigned int us);
|
||||
|
||||
void bitbang_check_prerequisites(PROGRAMMER *pgm);
|
||||
|
||||
int bitbang_rdy_led (PROGRAMMER * pgm, int value);
|
||||
int bitbang_err_led (PROGRAMMER * pgm, int value);
|
||||
int bitbang_pgm_led (PROGRAMMER * pgm, int value);
|
||||
int bitbang_vfy_led (PROGRAMMER * pgm, int value);
|
||||
int bitbang_cmd (PROGRAMMER * pgm, unsigned char cmd[4],
|
||||
unsigned char res[4]);
|
||||
int bitbang_spi (PROGRAMMER * pgm, unsigned char cmd[],
|
||||
unsigned char res[], int count);
|
||||
int bitbang_chip_erase (PROGRAMMER * pgm, AVRPART * p);
|
||||
int bitbang_program_enable (PROGRAMMER * pgm, AVRPART * p);
|
||||
void bitbang_powerup (PROGRAMMER * pgm);
|
||||
void bitbang_powerdown (PROGRAMMER * pgm);
|
||||
int bitbang_initialize (PROGRAMMER * pgm, AVRPART * p);
|
||||
void bitbang_disable (PROGRAMMER * pgm);
|
||||
void bitbang_enable (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: config.c 725 2007-01-30 13:41:54Z joerg_wunsch $ */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../pilight/core/log.h"
|
||||
#include "../pilight/core/mem.h"
|
||||
#include "avrconfig.h"
|
||||
|
||||
TOKEN * new_token(int primary)
|
||||
{
|
||||
TOKEN * tkn;
|
||||
|
||||
tkn = (TOKEN *)MALLOC(sizeof(TOKEN));
|
||||
if (tkn == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(tkn, 0, sizeof(TOKEN));
|
||||
|
||||
tkn->primary = primary;
|
||||
|
||||
return tkn;
|
||||
}
|
||||
|
||||
void free_token(TOKEN * tkn)
|
||||
{
|
||||
if (tkn) {
|
||||
switch (tkn->primary) {
|
||||
case TKN_STRING:
|
||||
case TKN_ID:
|
||||
if (tkn->value.string)
|
||||
FREE(tkn->value.string);
|
||||
tkn->value.string = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
FREE(tkn);
|
||||
}
|
||||
}
|
||||
|
||||
TOKEN * number(char * text)
|
||||
{
|
||||
struct token_t * tkn;
|
||||
|
||||
tkn = new_token(TKN_NUMBER);
|
||||
tkn->value.type = V_NUM;
|
||||
tkn->value.number = atof(text);
|
||||
|
||||
return tkn;
|
||||
}
|
||||
|
||||
TOKEN * hexnumber(char * text)
|
||||
{
|
||||
struct token_t * tkn;
|
||||
char * e;
|
||||
|
||||
tkn = new_token(TKN_NUMBER);
|
||||
tkn->value.type = V_NUM;
|
||||
tkn->value.number = strtoul(text, &e, 16);
|
||||
if ((e == text) || (*e != 0)) {
|
||||
logprintf(LOG_ERR, "%s:%d: can't scan hex number \"%s\"", infile, lineno, text);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tkn;
|
||||
}
|
||||
|
||||
TOKEN * string(char * text)
|
||||
{
|
||||
struct token_t * tkn;
|
||||
int len;
|
||||
|
||||
tkn = new_token(TKN_STRING);
|
||||
|
||||
len = strlen(text);
|
||||
|
||||
tkn->value.type = V_STR;
|
||||
tkn->value.string = (char *) MALLOC(len+1);
|
||||
if (tkn->value.string == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
strcpy(tkn->value.string, text);
|
||||
|
||||
return tkn;
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: config.h 725 2007-01-30 13:41:54Z joerg_wunsch $ */
|
||||
|
||||
#ifndef avrconfig_h
|
||||
#define avrconfig_h
|
||||
|
||||
#include "avrpart.h"
|
||||
#include "pindefs.h"
|
||||
#include "avr.h"
|
||||
#include "pgm.h"
|
||||
|
||||
#define MAX_STR_CONST 1024
|
||||
|
||||
enum { V_NONE, V_NUM, V_STR };
|
||||
typedef struct value_t {
|
||||
int type;
|
||||
double number;
|
||||
char * string;
|
||||
} VALUE;
|
||||
|
||||
|
||||
typedef struct token_t {
|
||||
int primary;
|
||||
VALUE value;
|
||||
} TOKEN;
|
||||
typedef struct token_t *token_p;
|
||||
|
||||
|
||||
extern FILE * in;
|
||||
extern PROGRAMMER * current_prog;
|
||||
extern AVRPART * current_part;
|
||||
extern AVRMEM * current_mem;
|
||||
extern int lineno;
|
||||
extern const char * infile;
|
||||
extern char default_programmer[];
|
||||
extern char default_parallel[];
|
||||
extern char default_serial[];
|
||||
|
||||
enum tokentype {
|
||||
K_READ = 258,
|
||||
K_WRITE = 259,
|
||||
K_READ_LO = 260,
|
||||
K_READ_HI = 261,
|
||||
K_WRITE_LO = 262,
|
||||
K_WRITE_HI = 263,
|
||||
K_LOADPAGE_LO = 264,
|
||||
K_LOADPAGE_HI = 265,
|
||||
K_LOAD_EXT_ADDR = 266,
|
||||
K_WRITEPAGE = 267,
|
||||
K_CHIP_ERASE = 268,
|
||||
K_PGM_ENABLE = 269,
|
||||
K_MEMORY = 270,
|
||||
K_PAGE_SIZE = 271,
|
||||
K_PAGED = 272,
|
||||
K_ARDUINO = 273,
|
||||
K_BAUDRATE = 274,
|
||||
K_BS2 = 275,
|
||||
K_BUFF = 276,
|
||||
K_BUSPIRATE = 277,
|
||||
K_CHIP_ERASE_DELAY = 278,
|
||||
K_DEDICATED = 279,
|
||||
K_DEFAULT_PARALLEL = 280,
|
||||
K_DEFAULT_PROGRAMMER = 281,
|
||||
K_DEFAULT_SERIAL = 282,
|
||||
K_DESC = 283,
|
||||
K_DEVICECODE = 284,
|
||||
K_DRAGON_DW = 285,
|
||||
K_DRAGON_HVSP = 286,
|
||||
K_DRAGON_ISP = 287,
|
||||
K_DRAGON_JTAG = 288,
|
||||
K_DRAGON_PDI = 289,
|
||||
K_DRAGON_PP = 290,
|
||||
K_GPIO = 291,
|
||||
K_STK500_DEVCODE = 292,
|
||||
K_AVR910_DEVCODE = 293,
|
||||
K_EEPROM = 294,
|
||||
K_ERRLED = 295,
|
||||
K_FLASH = 296,
|
||||
K_ID = 297,
|
||||
K_IO = 298,
|
||||
K_JTAG_MKI = 299,
|
||||
K_JTAG_MKII = 300,
|
||||
K_JTAG_MKII_AVR32 = 301,
|
||||
K_JTAG_MKII_DW = 302,
|
||||
K_JTAG_MKII_ISP = 303,
|
||||
K_JTAG_MKII_PDI = 304,
|
||||
K_LOADPAGE = 305,
|
||||
K_MAX_WRITE_DELAY = 306,
|
||||
K_MIN_WRITE_DELAY = 307,
|
||||
K_MISO = 308,
|
||||
K_MOSI = 309,
|
||||
K_NUM_PAGES = 310,
|
||||
K_NVM_BASE = 311,
|
||||
K_OFFSET = 312,
|
||||
K_PAGEL = 313,
|
||||
K_PAR = 314,
|
||||
K_PARALLEL = 315,
|
||||
K_PART = 316,
|
||||
K_PGMLED = 317,
|
||||
K_PROGRAMMER = 318,
|
||||
K_PSEUDO = 319,
|
||||
K_PWROFF_AFTER_WRITE = 320,
|
||||
K_RDYLED = 321,
|
||||
K_READBACK_P1 = 322,
|
||||
K_READBACK_P2 = 323,
|
||||
K_READMEM = 324,
|
||||
K_RESET = 325,
|
||||
K_RETRY_PULSE = 326,
|
||||
K_SERBB = 327,
|
||||
K_SERIAL = 328,
|
||||
K_SCK = 329,
|
||||
K_SIGNATURE = 330,
|
||||
K_SIZE = 331,
|
||||
K_STK500 = 332,
|
||||
K_STK500HVSP = 333,
|
||||
K_STK500PP = 334,
|
||||
K_STK500V2 = 335,
|
||||
K_STK500GENERIC = 336,
|
||||
K_STK600 = 337,
|
||||
K_STK600HVSP = 338,
|
||||
K_STK600PP = 339,
|
||||
K_AVR910 = 340,
|
||||
K_USBASP = 341,
|
||||
K_USBTINY = 342,
|
||||
K_BUTTERFLY = 343,
|
||||
K_TYPE = 344,
|
||||
K_VCC = 345,
|
||||
K_VFYLED = 346,
|
||||
K_NO = 347,
|
||||
K_YES = 348,
|
||||
K_TIMEOUT = 349,
|
||||
K_STABDELAY = 350,
|
||||
K_CMDEXEDELAY = 351,
|
||||
K_HVSPCMDEXEDELAY = 352,
|
||||
K_SYNCHLOOPS = 353,
|
||||
K_BYTEDELAY = 354,
|
||||
K_POLLVALUE = 355,
|
||||
K_POLLINDEX = 356,
|
||||
K_PREDELAY = 357,
|
||||
K_POSTDELAY = 358,
|
||||
K_POLLMETHOD = 359,
|
||||
K_MODE = 360,
|
||||
K_DELAY = 361,
|
||||
K_BLOCKSIZE = 362,
|
||||
K_READSIZE = 363,
|
||||
K_HVENTERSTABDELAY = 364,
|
||||
K_PROGMODEDELAY = 365,
|
||||
K_LATCHCYCLES = 366,
|
||||
K_TOGGLEVTG = 367,
|
||||
K_POWEROFFDELAY = 368,
|
||||
K_RESETDELAYMS = 369,
|
||||
K_RESETDELAYUS = 370,
|
||||
K_HVLEAVESTABDELAY = 371,
|
||||
K_RESETDELAY = 372,
|
||||
K_SYNCHCYCLES = 373,
|
||||
K_HVCMDEXEDELAY = 374,
|
||||
K_CHIPERASEPULSEWIDTH = 375,
|
||||
K_CHIPERASEPOLLTIMEOUT = 376,
|
||||
K_CHIPERASETIME = 377,
|
||||
K_PROGRAMFUSEPULSEWIDTH = 378,
|
||||
K_PROGRAMFUSEPOLLTIMEOUT = 379,
|
||||
K_PROGRAMLOCKPULSEWIDTH = 380,
|
||||
K_PROGRAMLOCKPOLLTIMEOUT = 381,
|
||||
K_PP_CONTROLSTACK = 382,
|
||||
K_HVSP_CONTROLSTACK = 383,
|
||||
K_ALLOWFULLPAGEBITSTREAM = 384,
|
||||
K_ENABLEPAGEPROGRAMMING = 385,
|
||||
K_HAS_JTAG = 386,
|
||||
K_HAS_DW = 387,
|
||||
K_HAS_PDI = 388,
|
||||
K_HAS_TPI = 389,
|
||||
K_IDR = 390,
|
||||
K_IS_AVR32 = 391,
|
||||
K_RAMPZ = 392,
|
||||
K_SPMCR = 393,
|
||||
K_EECR = 394,
|
||||
K_FLASH_INSTR = 395,
|
||||
K_EEPROM_INSTR = 396,
|
||||
TKN_COMMA = 397,
|
||||
TKN_EQUAL = 398,
|
||||
TKN_SEMI = 399,
|
||||
TKN_TILDE = 400,
|
||||
TKN_NUMBER = 401,
|
||||
TKN_STRING = 402,
|
||||
TKN_ID = 403
|
||||
};
|
||||
|
||||
char default_programmer[MAX_STR_CONST];
|
||||
char default_parallel[4096];
|
||||
char default_serial[4096];
|
||||
|
||||
char string_buf[MAX_STR_CONST];
|
||||
char *string_buf_ptr;
|
||||
|
||||
PROGRAMMER * current_prog;
|
||||
AVRPART * current_part;
|
||||
|
||||
int lineno;
|
||||
const char * infile;
|
||||
extern char string_buf[MAX_STR_CONST];
|
||||
extern char *string_buf_ptr;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int init_config(void);
|
||||
TOKEN * new_token(int primary);
|
||||
void free_token(TOKEN * tkn);
|
||||
void free_tokens(int n, ...);
|
||||
TOKEN * number(char * text);
|
||||
TOKEN * hexnumber(char * text);
|
||||
TOKEN * string(char * text);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2007 Joerg Wunsch
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: avrdude.h 788 2008-11-19 23:32:30Z joerg_wunsch $ */
|
||||
|
||||
#ifndef avrdude_h
|
||||
#define avrdude_h
|
||||
|
||||
extern char * progname; /* name of program, for messages */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Support for bitbanging GPIO pins using the /sys/class/gpio interface
|
||||
*
|
||||
* Copyright (C) 2010 Radoslav Kolev <radoslav@kolev.info>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <wiringx.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "avr.h"
|
||||
#include "pindefs.h"
|
||||
#include "pgm.h"
|
||||
#include "avrbitbang.h"
|
||||
#include "defines.h"
|
||||
#include "../pilight/core/log.h"
|
||||
#include "../pilight/config/settings.h"
|
||||
|
||||
/*
|
||||
* GPIO user space helpers
|
||||
*
|
||||
* Copyright 2009 Analog Devices Inc.
|
||||
* Michael Hennerich (hennerich@blackfin.uclinux.org)
|
||||
*
|
||||
* Licensed under the GPL-2 or later
|
||||
*/
|
||||
|
||||
#define GPIO_DIR_IN 0
|
||||
#define GPIO_DIR_OUT 1
|
||||
#define N_GPIO 256
|
||||
|
||||
/*
|
||||
* an array which holds open FDs to /sys/class/gpio/gpioXX/value for all needed pins
|
||||
*/
|
||||
static int gpio_fds[N_GPIO];
|
||||
|
||||
static int gpio_setpin(PROGRAMMER * pgm, int pin, int value) {
|
||||
if(gpio_fds[pin] != PINMODE_OUTPUT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Small delay for too fast computers */
|
||||
delayMicroseconds(1);
|
||||
|
||||
if(value == 1) {
|
||||
digitalWrite(pin, HIGH);
|
||||
} else {
|
||||
digitalWrite(pin, LOW);
|
||||
}
|
||||
|
||||
if(pgm->ispdelay > 1) {
|
||||
bitbang_delay(pgm->ispdelay);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_getpin(PROGRAMMER * pgm, int pin) {
|
||||
if(gpio_fds[pin] == PINMODE_INPUT) {
|
||||
return digitalRead(pin);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int gpio_highpulsepin(PROGRAMMER * pgm, int pin) {
|
||||
|
||||
if(gpio_fds[pin] == PINMODE_OUTPUT) {
|
||||
digitalWrite(pin, HIGH);
|
||||
digitalWrite(pin, LOW);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void gpio_display(PROGRAMMER *pgm, const char *p) {
|
||||
/* MAYBE */
|
||||
}
|
||||
|
||||
static void gpio_enable(PROGRAMMER *pgm) {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void gpio_disable(PROGRAMMER *pgm) {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void gpio_powerup(PROGRAMMER *pgm) {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void gpio_powerdown(PROGRAMMER *pgm) {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static int gpio_open(PROGRAMMER *pgm, char *port) {
|
||||
int i = 0;
|
||||
|
||||
bitbang_check_prerequisites(pgm);
|
||||
|
||||
for(i=0;i<N_PINS;i++) {
|
||||
if(pgm->pinno[i] != 0) {
|
||||
if(i == PIN_AVR_MISO) {
|
||||
gpio_fds[pgm->pinno[i]] = PINMODE_INPUT;
|
||||
pinMode(pgm->pinno[i], PINMODE_INPUT);
|
||||
} else {
|
||||
gpio_fds[pgm->pinno[i]] = PINMODE_OUTPUT;;
|
||||
pinMode(pgm->pinno[i], PINMODE_OUTPUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void gpio_close(PROGRAMMER *pgm) {
|
||||
if(gpio_fds[pgm->pinno[PIN_AVR_RESET]] == PINMODE_OUTPUT) {
|
||||
digitalWrite(pgm->pinno[PIN_AVR_RESET], HIGH);
|
||||
// digitalWrite(pgm->pinno[PIN_AVR_RESET], LOW);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void gpio_initpgm(PROGRAMMER *pgm)
|
||||
{
|
||||
strcpy(pgm->type, "GPIO");
|
||||
char *platform = GPIO_PLATFORM;
|
||||
if(settings_find_string("gpio-platform", &platform) != 0 || strcmp(platform, "none") == 0) {
|
||||
logprintf(LOG_ERR, "gpio_switch: no gpio-platform configured");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(wiringXSetup(platform, logprintf1) < 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pgm->rdy_led = bitbang_rdy_led;
|
||||
pgm->err_led = bitbang_err_led;
|
||||
pgm->pgm_led = bitbang_pgm_led;
|
||||
pgm->vfy_led = bitbang_vfy_led;
|
||||
pgm->initialize = bitbang_initialize;
|
||||
pgm->display = gpio_display;
|
||||
pgm->enable = gpio_enable;
|
||||
pgm->disable = gpio_disable;
|
||||
pgm->powerup = gpio_powerup;
|
||||
pgm->powerdown = gpio_powerdown;
|
||||
pgm->program_enable = bitbang_program_enable;
|
||||
pgm->chip_erase = bitbang_chip_erase;
|
||||
pgm->cmd = bitbang_cmd;
|
||||
pgm->open = gpio_open;
|
||||
pgm->close = gpio_close;
|
||||
pgm->setpin = gpio_setpin;
|
||||
pgm->getpin = gpio_getpin;
|
||||
pgm->highpulsepin = gpio_highpulsepin;
|
||||
pgm->read_byte = avr_read_byte_default;
|
||||
pgm->write_byte = avr_write_byte_default;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: par.h 722 2007-01-24 22:43:46Z joerg_wunsch $ */
|
||||
|
||||
#ifndef avrgpio_h
|
||||
#define avrgpio_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void gpio_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,251 @@
|
||||
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: avrpart.c 772 2008-06-07 21:03:41Z joerg_wunsch $ */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../pilight/core/log.h"
|
||||
#include "../pilight/core/mem.h"
|
||||
#include "avrdude.h"
|
||||
#include "avrpart.h"
|
||||
#include "pindefs.h"
|
||||
|
||||
/***
|
||||
*** Elementary functions dealing with OPCODE structures
|
||||
***/
|
||||
|
||||
OPCODE * avr_new_opcode(void)
|
||||
{
|
||||
OPCODE * m;
|
||||
|
||||
m = (OPCODE *)MALLOC(sizeof(*m));
|
||||
if (m == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(m, 0, sizeof(*m));
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* avr_set_bits()
|
||||
*
|
||||
* Set instruction bits in the specified command based on the opcode.
|
||||
*/
|
||||
int avr_set_bits(OPCODE * op, unsigned char * cmd)
|
||||
{
|
||||
int i, j, bit;
|
||||
unsigned char mask;
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_VALUE) {
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
if (op->bit[i].value)
|
||||
cmd[j] = cmd[j] | mask;
|
||||
else
|
||||
cmd[j] = cmd[j] & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* avr_set_addr()
|
||||
*
|
||||
* Set address bits in the specified command based on the opcode, and
|
||||
* the address.
|
||||
*/
|
||||
int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr)
|
||||
{
|
||||
int i, j, bit;
|
||||
unsigned long value;
|
||||
unsigned char mask;
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_ADDRESS) {
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
value = addr >> op->bit[i].bitno & 0x01;
|
||||
if (value)
|
||||
cmd[j] = cmd[j] | mask;
|
||||
else
|
||||
cmd[j] = cmd[j] & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* avr_set_input()
|
||||
*
|
||||
* Set input data bits in the specified command based on the opcode,
|
||||
* and the data byte.
|
||||
*/
|
||||
int avr_set_input(OPCODE * op, unsigned char * cmd, unsigned char data)
|
||||
{
|
||||
int i, j, bit;
|
||||
unsigned char value;
|
||||
unsigned char mask;
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_INPUT) {
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
value = data >> op->bit[i].bitno & 0x01;
|
||||
if (value)
|
||||
cmd[j] = cmd[j] | mask;
|
||||
else
|
||||
cmd[j] = cmd[j] & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* avr_get_output()
|
||||
*
|
||||
* Retreive output data bits from the command results based on the
|
||||
* opcode data.
|
||||
*/
|
||||
int avr_get_output(OPCODE * op, unsigned char * res, unsigned char * data)
|
||||
{
|
||||
int i, j, bit;
|
||||
unsigned char value;
|
||||
unsigned char mask;
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_OUTPUT) {
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
value = ((res[j] & mask) >> bit) & 0x01;
|
||||
value = value << op->bit[i].bitno;
|
||||
if (value)
|
||||
*data = *data | value;
|
||||
else
|
||||
*data = *data & ~value;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***
|
||||
*** Elementary functions dealing with AVRMEM structures
|
||||
***/
|
||||
|
||||
AVRMEM * avr_new_memtype(void)
|
||||
{
|
||||
AVRMEM * m;
|
||||
|
||||
m = (AVRMEM *)MALLOC(sizeof(*m));
|
||||
if (m == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(m, 0, sizeof(*m));
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
AVRMEM * avr_dup_mem(AVRMEM * m)
|
||||
{
|
||||
AVRMEM * n;
|
||||
|
||||
n = avr_new_memtype();
|
||||
|
||||
*n = *m;
|
||||
|
||||
n->buf = (unsigned char *)MALLOC(n->size);
|
||||
if (n->buf == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
memset(n->buf, 0, n->size);
|
||||
|
||||
memcpy(n->tags, m->tags, n->size);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elementary functions dealing with AVRPART structures
|
||||
*/
|
||||
|
||||
|
||||
AVRPART * avr_new_part(void)
|
||||
{
|
||||
AVRPART * p;
|
||||
|
||||
p = (AVRPART *)MALLOC(sizeof(AVRPART));
|
||||
if (p == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->id[0] = 0;
|
||||
p->desc[0] = 0;
|
||||
p->reset_disposition = RESET_DEDICATED;
|
||||
p->retry_pulse = PIN_AVR_SCK;
|
||||
p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK | AVRPART_ENABLEPAGEPROGRAMMING;
|
||||
p->lineno = 0;
|
||||
memset(p->signature, 0xFF, 3);
|
||||
p->ctl_stack_type = CTL_STACK_NONE;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
AVRPART * avr_dup_part(AVRPART * d)
|
||||
{
|
||||
AVRPART * p;
|
||||
|
||||
p = avr_new_part();
|
||||
*p = *d;
|
||||
|
||||
/* NEW */
|
||||
p->sigmem = avr_dup_mem(p->sigmem);
|
||||
p->flashmem = avr_dup_mem(p->flashmem);
|
||||
p->lfusemem = avr_dup_mem(p->lfusemem);
|
||||
p->hfusemem = avr_dup_mem(p->hfusemem);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: avrpart.h 916 2010-01-15 16:36:13Z joerg_wunsch $ */
|
||||
|
||||
#ifndef avrpart_h
|
||||
#define avrpart_h
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/*
|
||||
* AVR serial programming instructions
|
||||
*/
|
||||
enum {
|
||||
AVR_OP_READ,
|
||||
AVR_OP_WRITE,
|
||||
AVR_OP_READ_LO,
|
||||
AVR_OP_READ_HI,
|
||||
AVR_OP_WRITE_LO,
|
||||
AVR_OP_WRITE_HI,
|
||||
AVR_OP_LOADPAGE_LO,
|
||||
AVR_OP_LOADPAGE_HI,
|
||||
AVR_OP_LOAD_EXT_ADDR,
|
||||
AVR_OP_WRITEPAGE,
|
||||
AVR_OP_CHIP_ERASE,
|
||||
AVR_OP_PGM_ENABLE,
|
||||
AVR_OP_MAX
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
AVR_CMDBIT_IGNORE, /* bit is ignored on input and output */
|
||||
AVR_CMDBIT_VALUE, /* bit is set to 0 or 1 for input or output */
|
||||
AVR_CMDBIT_ADDRESS, /* this bit represents an input address bit */
|
||||
AVR_CMDBIT_INPUT, /* this bit is an input bit */
|
||||
AVR_CMDBIT_OUTPUT /* this bit is an output bit */
|
||||
};
|
||||
|
||||
enum { /* these are assigned to reset_disposition of AVRPART */
|
||||
RESET_DEDICATED, /* reset pin is dedicated */
|
||||
RESET_IO /* reset pin might be configured as an I/O pin */
|
||||
};
|
||||
|
||||
enum ctl_stack_t {
|
||||
CTL_STACK_NONE, /* no control stack defined */
|
||||
CTL_STACK_PP, /* parallel programming control stack */
|
||||
CTL_STACK_HVSP /* high voltage serial programming control stack */
|
||||
};
|
||||
|
||||
/*
|
||||
* serial programming instruction bit specifications
|
||||
*/
|
||||
typedef struct cmdbit {
|
||||
int type; /* AVR_CMDBIT_* */
|
||||
int bitno; /* which input bit to use for this command bit */
|
||||
int value; /* bit value if type == AVR_CMDBIT_VALUD */
|
||||
} CMDBIT;
|
||||
|
||||
typedef struct opcode {
|
||||
CMDBIT bit[32]; /* opcode bit specs */
|
||||
} OPCODE;
|
||||
|
||||
|
||||
#define AVRPART_SERIALOK 0x0001 /* part supports serial programming */
|
||||
#define AVRPART_PARALLELOK 0x0002 /* part supports parallel programming */
|
||||
#define AVRPART_PSEUDOPARALLEL 0x0004 /* part has pseudo parallel support */
|
||||
#define AVRPART_HAS_JTAG 0x0008 /* part has a JTAG i/f */
|
||||
#define AVRPART_ALLOWFULLPAGEBITSTREAM 0x0010 /* JTAG ICE mkII param. */
|
||||
#define AVRPART_ENABLEPAGEPROGRAMMING 0x0020 /* JTAG ICE mkII param. */
|
||||
#define AVRPART_HAS_DW 0x0040 /* part has a debugWire i/f */
|
||||
#define AVRPART_HAS_PDI 0x0080 /* part has PDI i/f rather than ISP (ATxmega) */
|
||||
#define AVRPART_AVR32 0x0100 /* part is in AVR32 family */
|
||||
#define AVRPART_INIT_SMC 0x0200 /* part will undergo chip erase */
|
||||
#define AVRPART_WRITE 0x0400 /* at least one write operation specified */
|
||||
#define AVRPART_HAS_TPI 0x0800 /* part has TPI i/f rather than ISP (ATtiny4/5/9/10) */
|
||||
|
||||
#define AVR_DESCLEN 64
|
||||
#define AVR_IDLEN 32
|
||||
#define CTL_STACK_SIZE 32
|
||||
#define FLASH_INSTR_SIZE 3
|
||||
#define EEPROM_INSTR_SIZE 20
|
||||
|
||||
#define TAG_ALLOCATED 1 /* memory byte is allocated */
|
||||
|
||||
#define AVR_MEMDESCLEN 64
|
||||
typedef struct avrmem {
|
||||
char desc[AVR_MEMDESCLEN]; /* memory description ("flash", "eeprom", etc) */
|
||||
int paged; /* page addressed (e.g. ATmega flash) */
|
||||
int size; /* total memory size in bytes */
|
||||
int page_size; /* size of memory page (if page addressed) */
|
||||
int num_pages; /* number of pages (if page addressed) */
|
||||
unsigned int offset; /* offset in IO memory (ATxmega) */
|
||||
int min_write_delay; /* microseconds */
|
||||
int max_write_delay; /* microseconds */
|
||||
int pwroff_after_write; /* after this memory type is written to,
|
||||
the device must be powered off and
|
||||
back on, see errata
|
||||
http://www.atmel.com/atmel/acrobat/doc1280.pdf */
|
||||
unsigned char readback[2]; /* polled read-back values */
|
||||
|
||||
int mode; /* stk500 v2 xml file parameter */
|
||||
int delay; /* stk500 v2 xml file parameter */
|
||||
int blocksize; /* stk500 v2 xml file parameter */
|
||||
int readsize; /* stk500 v2 xml file parameter */
|
||||
int pollindex; /* stk500 v2 xml file parameter */
|
||||
|
||||
unsigned char * buf; /* pointer to memory buffer */
|
||||
unsigned char tags[1024*1024]; /* allocation tags */
|
||||
OPCODE * op[AVR_OP_MAX]; /* opcodes */
|
||||
} AVRMEM;
|
||||
|
||||
typedef struct avrpart {
|
||||
char desc[AVR_DESCLEN]; /* long part name */
|
||||
char id[AVR_IDLEN]; /* short part name */
|
||||
int stk500_devcode; /* stk500 device code */
|
||||
int avr910_devcode; /* avr910 device code */
|
||||
int chip_erase_delay; /* microseconds */
|
||||
unsigned char pagel; /* for parallel programming */
|
||||
unsigned char bs2; /* for parallel programming */
|
||||
unsigned char signature[3]; /* expected value of signature bytes */
|
||||
int reset_disposition; /* see RESET_ enums */
|
||||
int retry_pulse; /* retry program enable by pulsing
|
||||
this pin (PIN_AVR_*) */
|
||||
unsigned flags; /* see AVRPART_ masks */
|
||||
|
||||
int timeout; /* stk500 v2 xml file parameter */
|
||||
int stabdelay; /* stk500 v2 xml file parameter */
|
||||
int cmdexedelay; /* stk500 v2 xml file parameter */
|
||||
int synchloops; /* stk500 v2 xml file parameter */
|
||||
int bytedelay; /* stk500 v2 xml file parameter */
|
||||
int pollindex; /* stk500 v2 xml file parameter */
|
||||
unsigned char pollvalue; /* stk500 v2 xml file parameter */
|
||||
int predelay; /* stk500 v2 xml file parameter */
|
||||
int postdelay; /* stk500 v2 xml file parameter */
|
||||
int pollmethod; /* stk500 v2 xml file parameter */
|
||||
|
||||
enum ctl_stack_t ctl_stack_type; /* what to use the ctl stack for */
|
||||
unsigned char controlstack[CTL_STACK_SIZE]; /* stk500v2 PP/HVSP ctl stack */
|
||||
unsigned char flash_instr[FLASH_INSTR_SIZE]; /* flash instructions (debugWire, JTAG) */
|
||||
unsigned char eeprom_instr[EEPROM_INSTR_SIZE]; /* EEPROM instructions (debugWire, JTAG) */
|
||||
|
||||
int hventerstabdelay; /* stk500 v2 hv mode parameter */
|
||||
int progmodedelay; /* stk500 v2 hv mode parameter */
|
||||
int latchcycles; /* stk500 v2 hv mode parameter */
|
||||
int togglevtg; /* stk500 v2 hv mode parameter */
|
||||
int poweroffdelay; /* stk500 v2 hv mode parameter */
|
||||
int resetdelayms; /* stk500 v2 hv mode parameter */
|
||||
int resetdelayus; /* stk500 v2 hv mode parameter */
|
||||
int hvleavestabdelay; /* stk500 v2 hv mode parameter */
|
||||
int resetdelay; /* stk500 v2 hv mode parameter */
|
||||
int chiperasepulsewidth; /* stk500 v2 hv mode parameter */
|
||||
int chiperasepolltimeout; /* stk500 v2 hv mode parameter */
|
||||
int chiperasetime; /* stk500 v2 hv mode parameter */
|
||||
int programfusepulsewidth; /* stk500 v2 hv mode parameter */
|
||||
int programfusepolltimeout; /* stk500 v2 hv mode parameter */
|
||||
int programlockpulsewidth; /* stk500 v2 hv mode parameter */
|
||||
int programlockpolltimeout; /* stk500 v2 hv mode parameter */
|
||||
int synchcycles; /* stk500 v2 hv mode parameter */
|
||||
int hvspcmdexedelay; /* stk500 v2 xml file parameter */
|
||||
|
||||
unsigned char idr; /* JTAG ICE mkII XML file parameter */
|
||||
unsigned char rampz; /* JTAG ICE mkII XML file parameter */
|
||||
unsigned char spmcr; /* JTAG ICE mkII XML file parameter */
|
||||
unsigned short eecr; /* JTAC ICE mkII XML file parameter */
|
||||
unsigned int nvm_base; /* Base address of NVM controller in ATxmega devices */
|
||||
|
||||
OPCODE * op[AVR_OP_MAX]; /* opcodes */
|
||||
|
||||
AVRMEM *sigmem;
|
||||
AVRMEM *flashmem;
|
||||
AVRMEM *lfusemem;
|
||||
AVRMEM *hfusemem;
|
||||
AVRMEM *fusesmem;
|
||||
AVRMEM *lockmem;
|
||||
char config_file[4096]; /* config file where defined */
|
||||
int lineno; /* config file line number */
|
||||
} AVRPART;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Functions for OPCODE structures */
|
||||
OPCODE * avr_new_opcode(void);
|
||||
int avr_set_bits(OPCODE * op, unsigned char * cmd);
|
||||
int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr);
|
||||
int avr_set_input(OPCODE * op, unsigned char * cmd, unsigned char data);
|
||||
int avr_get_output(OPCODE * op, unsigned char * res, unsigned char * data);
|
||||
|
||||
/* Functions for AVRMEM structures */
|
||||
AVRMEM * avr_new_memtype(void);
|
||||
int avr_initmem(AVRPART * p);
|
||||
AVRMEM * avr_dup_mem(AVRMEM * m);
|
||||
AVRMEM * avr_locate_mem(AVRPART * p, char * desc);
|
||||
|
||||
/* Functions for AVRPART structures */
|
||||
AVRPART * avr_new_part(void);
|
||||
AVRPART * avr_dup_part(AVRPART * d);
|
||||
typedef void (*walk_avrparts_cb)(const char *name, const char *desc,
|
||||
const char *cfgname, int cfglineno,
|
||||
void *cookie);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* avrpart_h */
|
||||
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2005 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2007 Joerg Wunsch
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: AVRUPD.c 819 2009-04-28 18:35:14Z joerg_wunsch $ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../pilight/core/log.h"
|
||||
#include "../pilight/core/mem.h"
|
||||
#include "avrdude.h"
|
||||
#include "avr.h"
|
||||
#include "avrconfig.h"
|
||||
#include "fileio.h"
|
||||
#include "avrupd.h"
|
||||
|
||||
AVRUPD * parse_op(char * s)
|
||||
{
|
||||
char buf[1024];
|
||||
char * p, * cp, c;
|
||||
AVRUPD * upd;
|
||||
int i;
|
||||
size_t fnlen;
|
||||
|
||||
upd = (AVRUPD *)MALLOC(sizeof(AVRUPD));
|
||||
if (upd == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
p = s;
|
||||
while ((i < (sizeof(buf)-1) && *p && (*p != ':')))
|
||||
buf[i++] = *p++;
|
||||
buf[i] = 0;
|
||||
|
||||
if (*p != ':') {
|
||||
upd->memtype = (char *)MALLOC(strlen("flash")+1);
|
||||
if (upd->memtype == NULL) {
|
||||
outofmem:
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strcpy(upd->memtype, "flash");
|
||||
upd->op = DEVICE_WRITE;
|
||||
upd->filename = (char *)MALLOC(strlen(buf) + 1);
|
||||
if (upd->filename == NULL)
|
||||
goto outofmem;
|
||||
strcpy(upd->filename, buf);
|
||||
upd->format = FMT_AUTO;
|
||||
return upd;
|
||||
}
|
||||
|
||||
upd->memtype = (char *)MALLOC(strlen(buf)+1);
|
||||
if (upd->memtype == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strcpy(upd->memtype, buf);
|
||||
|
||||
p++;
|
||||
if (*p == 'r') {
|
||||
upd->op = DEVICE_READ;
|
||||
}
|
||||
else if (*p == 'w') {
|
||||
upd->op = DEVICE_WRITE;
|
||||
}
|
||||
else if (*p == 'v') {
|
||||
upd->op = DEVICE_VERIFY;
|
||||
}
|
||||
else {
|
||||
logprintf(LOG_ERR, "invalid I/O mode '%c' in update specification", *p);
|
||||
logprintf(LOG_ERR,
|
||||
" allowed values are:\n"
|
||||
" r = read device\n"
|
||||
" w = write device\n"
|
||||
" v = verify device");
|
||||
FREE(upd->memtype);
|
||||
FREE(upd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p++;
|
||||
|
||||
if (*p != ':') {
|
||||
logprintf(LOG_ERR, "invalid update specification");
|
||||
FREE(upd->memtype);
|
||||
FREE(upd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p++;
|
||||
|
||||
/*
|
||||
* Now, parse the filename component. Instead of looking for the
|
||||
* leftmost possible colon delimiter, we look for the rightmost one.
|
||||
* If we found one, we do have a trailing :format specifier, and
|
||||
* process it. Otherwise, the remainder of the string is our file
|
||||
* name component. That way, the file name itself is allowed to
|
||||
* contain a colon itself (e. g. C:/some/file.hex), except the
|
||||
* optional format specifier becomes mandatory then.
|
||||
*/
|
||||
cp = p;
|
||||
p = strrchr(cp, ':');
|
||||
if (p == NULL) {
|
||||
upd->format = FMT_AUTO;
|
||||
fnlen = strlen(cp);
|
||||
upd->filename = (char *)MALLOC(fnlen + 1);
|
||||
} else {
|
||||
fnlen = p - cp;
|
||||
upd->filename = (char *)MALLOC(fnlen +1);
|
||||
c = *++p;
|
||||
if (c && p[1])
|
||||
/* More than one char - force failure below. */
|
||||
c = '?';
|
||||
switch (c) {
|
||||
case 'a': upd->format = FMT_AUTO; break;
|
||||
case 's': upd->format = FMT_SREC; break;
|
||||
case 'i': upd->format = FMT_IHEX; break;
|
||||
case 'r': upd->format = FMT_RBIN; break;
|
||||
case 'm': upd->format = FMT_IMM; break;
|
||||
case 'b': upd->format = FMT_BIN; break;
|
||||
case 'd': upd->format = FMT_DEC; break;
|
||||
case 'h': upd->format = FMT_HEX; break;
|
||||
case 'o': upd->format = FMT_OCT; break;
|
||||
default:
|
||||
logprintf(LOG_ERR, "invalid file format '%s' in update specifier", p);
|
||||
FREE(upd->memtype);
|
||||
FREE(upd);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (upd->filename == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
FREE(upd->memtype);
|
||||
FREE(upd);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(upd->filename, cp, fnlen);
|
||||
upd->filename[fnlen] = 0;
|
||||
|
||||
return upd;
|
||||
}
|
||||
|
||||
AVRUPD * dup_AVRUPD(AVRUPD * upd)
|
||||
{
|
||||
AVRUPD * u;
|
||||
|
||||
u = (AVRUPD *)MALLOC(sizeof(AVRUPD));
|
||||
if(u == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memcpy(u, upd, sizeof(AVRUPD));
|
||||
|
||||
if((u->memtype = MALLOC(strlen(upd->memtype)+1)) == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strcpy(u->memtype, upd->memtype);
|
||||
if((u->filename = MALLOC(strlen(upd->filename)+1)) == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strcpy(u->filename, upd->filename);
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
AVRUPD * new_AVRUPD(int op, char * memtype, int filefmt, char * filename)
|
||||
{
|
||||
AVRUPD * u;
|
||||
|
||||
u = (AVRUPD *)MALLOC(sizeof(AVRUPD));
|
||||
if (u == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
u->memtype = MALLOC(strlen(memtype)+1);
|
||||
strcpy(u->memtype, memtype);
|
||||
u->filename = MALLOC(strlen(filename)+1);
|
||||
strcpy(u->filename, filename);
|
||||
u->op = op;
|
||||
u->format = filefmt;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
int do_op(PROGRAMMER * pgm, struct avrpart * p, AVRUPD * upd, int nowrite,
|
||||
int verify)
|
||||
{
|
||||
struct avrpart * v;
|
||||
AVRMEM * mem = NULL;
|
||||
int size, vsize;
|
||||
int rc;
|
||||
|
||||
/* NEW */
|
||||
if(strcmp(upd->memtype, "flash") == 0) {
|
||||
mem = p->flashmem;
|
||||
} else if(strcmp(upd->memtype, "lfuse") == 0) {
|
||||
mem = p->lfusemem;
|
||||
} else if(strcmp(upd->memtype, "hfuse") == 0) {
|
||||
mem = p->hfusemem;
|
||||
}
|
||||
|
||||
if (mem == NULL) {
|
||||
logprintf(LOG_ERR, "\"%s\" memory type not defined for part \"%s\"", upd->memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (upd->op == DEVICE_READ) {
|
||||
/*
|
||||
* read out the specified device memory and write it to a file
|
||||
*/
|
||||
|
||||
report_progress(0,1,"Reading");
|
||||
rc = avr_read(pgm, p, upd->memtype, 0);
|
||||
if (rc < 0) {
|
||||
logprintf(LOG_ERR, "failed to read all of %s memory, rc=%d", mem->desc, rc);
|
||||
return -1;
|
||||
}
|
||||
report_progress(1,1,NULL);
|
||||
size = rc;
|
||||
|
||||
logprintf(LOG_INFO,
|
||||
"writing output file \"%s\"",
|
||||
strcmp(upd->filename, "-")==0 ? "<stdout>" : upd->filename);
|
||||
|
||||
rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size);
|
||||
if (rc < 0) {
|
||||
logprintf(LOG_ERR, "write to file '%s' failed", upd->filename);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (upd->op == DEVICE_WRITE) {
|
||||
/*
|
||||
* write the selected device memory using data from a file; first
|
||||
* read the data from the specified file
|
||||
*/
|
||||
|
||||
logprintf(LOG_INFO,
|
||||
"reading input file \"%s\"",
|
||||
strcmp(upd->filename, "-")==0 ? "<stdin>" : upd->filename);
|
||||
|
||||
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
|
||||
if (rc < 0) {
|
||||
logprintf(LOG_INFO, "write to file '%s' failed", upd->filename);
|
||||
return -1;
|
||||
}
|
||||
size = rc;
|
||||
|
||||
/*
|
||||
* write the buffer contents to the selected memory type
|
||||
*/
|
||||
logprintf(LOG_INFO, "writing %s (%d bytes)", mem->desc, size);
|
||||
|
||||
if (!nowrite) {
|
||||
report_progress(0,1,"Writing");
|
||||
rc = avr_write(pgm, p, upd->memtype, size);
|
||||
report_progress(1,1,NULL);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
logprintf(LOG_ERR, "failed to write %s memory, rc=%d", mem->desc, rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vsize = rc;
|
||||
|
||||
logprintf(LOG_INFO, "%d bytes of %s written", vsize, mem->desc);
|
||||
|
||||
}
|
||||
else if (upd->op == DEVICE_VERIFY) {
|
||||
/*
|
||||
* verify that the in memory file (p->mem[AVR_M_FLASH|AVR_M_EEPROM])
|
||||
* is the same as what is on the chip
|
||||
*/
|
||||
v = avr_dup_part(p);
|
||||
|
||||
logprintf(LOG_INFO, "verifying %s memory against %s:", mem->desc, upd->filename);
|
||||
logprintf(LOG_INFO, "load data %s data from input file %s:", mem->desc, upd->filename);
|
||||
|
||||
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
|
||||
if (rc < 0) {
|
||||
logprintf(LOG_ERR, "read from file '%s' failed", upd->filename);
|
||||
return -1;
|
||||
}
|
||||
size = rc;
|
||||
|
||||
logprintf(LOG_INFO, "input file %s contains %d bytes", upd->filename, size);
|
||||
|
||||
report_progress (0,1,"Reading");
|
||||
rc = avr_read(pgm, v, upd->memtype, size);
|
||||
if (rc < 0) {
|
||||
logprintf(LOG_ERR, "failed to read all of %s memory, rc=%d", mem->desc, rc);
|
||||
return -1;
|
||||
}
|
||||
report_progress (1,1,NULL);
|
||||
|
||||
logprintf(LOG_INFO, "verifying ...");
|
||||
|
||||
rc = avr_verify(p, v, upd->memtype, size);
|
||||
if (rc < 0) {
|
||||
logprintf(LOG_ERR, "verification error; content mismatch");
|
||||
return -1;
|
||||
}
|
||||
|
||||
logprintf(LOG_INFO, "%d bytes of %s verified", rc, mem->desc);
|
||||
|
||||
FREE(v->sigmem->buf);
|
||||
FREE(v->sigmem);
|
||||
FREE(v->flashmem->buf);
|
||||
FREE(v->flashmem);
|
||||
FREE(v->hfusemem->buf);
|
||||
FREE(v->hfusemem);
|
||||
FREE(v->lfusemem->buf);
|
||||
FREE(v->lfusemem);
|
||||
FREE(v);
|
||||
}
|
||||
else {
|
||||
logprintf(LOG_ERR, "invalid update operation (%d) requested", upd->op);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2005 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2007 Joerg Wunsch
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: AVRUPD.h 722 2007-01-24 22:43:46Z joerg_wunsch $ */
|
||||
|
||||
#ifndef avrupd_h
|
||||
#define avrupd_h
|
||||
|
||||
enum {
|
||||
DEVICE_READ,
|
||||
DEVICE_WRITE,
|
||||
DEVICE_VERIFY
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char * memtype;
|
||||
int op;
|
||||
char * filename;
|
||||
int format;
|
||||
} AVRUPD;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
AVRUPD * parse_op(char * s);
|
||||
AVRUPD * dup_AVRUPD(AVRUPD * upd);
|
||||
AVRUPD * new_AVRUPD(int op, char * memtype, int filefmt, char * filename);
|
||||
int do_op(PROGRAMMER * pgm, struct avrpart * p, AVRUPD * upd, int nowrite, int verify);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: fileio.c 929 2010-01-18 20:40:15Z joerg_wunsch $ */
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "../pilight/core/log.h"
|
||||
#include "../pilight/core/mem.h"
|
||||
#include "../pilight/core/common.h"
|
||||
#include "avrdude.h"
|
||||
#include "avr.h"
|
||||
#include "fileio.h"
|
||||
|
||||
#define IHEX_MAXDATA 256
|
||||
#define MAX_LINE_LEN 256 /* max line length for ASCII format input files */
|
||||
|
||||
struct ihexrec {
|
||||
unsigned char reclen;
|
||||
unsigned int loadofs;
|
||||
unsigned char rectyp;
|
||||
unsigned char data[IHEX_MAXDATA];
|
||||
unsigned char cksum;
|
||||
};
|
||||
|
||||
static int b2ihex(unsigned char * inbuf, int bufsize,
|
||||
int recsize, int startaddr,
|
||||
char * outfile, FILE * outf)
|
||||
{
|
||||
unsigned char * buf;
|
||||
unsigned int nextaddr;
|
||||
int n, nbytes, n_64k;
|
||||
int i;
|
||||
unsigned char cksum;
|
||||
|
||||
if (recsize > 255) {
|
||||
logprintf(LOG_ERR, "recsize=%d, must be < 256", recsize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
n_64k = 0;
|
||||
nextaddr = startaddr;
|
||||
buf = inbuf;
|
||||
nbytes = 0;
|
||||
|
||||
while (bufsize) {
|
||||
n = recsize;
|
||||
if (n > bufsize)
|
||||
n = bufsize;
|
||||
|
||||
if ((nextaddr + n) > 0x10000)
|
||||
n = 0x10000 - nextaddr;
|
||||
|
||||
if (n) {
|
||||
cksum = 0;
|
||||
fprintf(outf, ":%02X%04X00", n, nextaddr);
|
||||
cksum += n + ((nextaddr >> 8) & 0x0ff) + (nextaddr & 0x0ff);
|
||||
for (i=0; i<n; i++) {
|
||||
fprintf(outf, "%02X", buf[i]);
|
||||
cksum += buf[i];
|
||||
}
|
||||
cksum = -cksum;
|
||||
fprintf(outf, "%02X\n", cksum);
|
||||
|
||||
nextaddr += n;
|
||||
nbytes += n;
|
||||
}
|
||||
|
||||
if (nextaddr >= 0x10000) {
|
||||
int lo, hi;
|
||||
/* output an extended address record */
|
||||
n_64k++;
|
||||
lo = n_64k & 0xff;
|
||||
hi = (n_64k >> 8) & 0xff;
|
||||
cksum = 0;
|
||||
fprintf(outf, ":02000004%02X%02X", hi, lo);
|
||||
cksum += 2 + 0 + 4 + hi + lo;
|
||||
cksum = -cksum;
|
||||
fprintf(outf, "%02X\n", cksum);
|
||||
nextaddr = 0;
|
||||
}
|
||||
|
||||
/* advance to next 'recsize' bytes */
|
||||
buf += n;
|
||||
bufsize -= n;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
add the end of record data line
|
||||
-----------------------------------------------------------------*/
|
||||
cksum = 0;
|
||||
n = 0;
|
||||
nextaddr = 0;
|
||||
fprintf(outf, ":%02X%04X01", n, nextaddr);
|
||||
cksum += n + ((nextaddr >> 8) & 0x0ff) + (nextaddr & 0x0ff) + 1;
|
||||
cksum = -cksum;
|
||||
fprintf(outf, "%02X\n", cksum);
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
|
||||
static int ihex_readrec(struct ihexrec * ihex, char * rec)
|
||||
{
|
||||
int i, j;
|
||||
char buf[8];
|
||||
int offset, len;
|
||||
char * e;
|
||||
unsigned char cksum;
|
||||
int rc;
|
||||
|
||||
len = strlen(rec);
|
||||
offset = 1;
|
||||
cksum = 0;
|
||||
|
||||
/* reclen */
|
||||
if (offset + 2 > len)
|
||||
return -1;
|
||||
for (i=0; i<2; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
ihex->reclen = strtoul(buf, &e, 16);
|
||||
if (e == buf || *e != 0)
|
||||
return -1;
|
||||
|
||||
/* load offset */
|
||||
if (offset + 4 > len)
|
||||
return -1;
|
||||
for (i=0; i<4; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
ihex->loadofs = strtoul(buf, &e, 16);
|
||||
if (e == buf || *e != 0)
|
||||
return -1;
|
||||
|
||||
/* record type */
|
||||
if (offset + 2 > len)
|
||||
return -1;
|
||||
for (i=0; i<2; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
ihex->rectyp = strtoul(buf, &e, 16);
|
||||
if (e == buf || *e != 0)
|
||||
return -1;
|
||||
|
||||
cksum = ihex->reclen + ((ihex->loadofs >> 8) & 0x0ff) + (ihex->loadofs & 0x0ff) + ihex->rectyp;
|
||||
|
||||
/* data */
|
||||
for (j=0; j<ihex->reclen; j++) {
|
||||
if (offset + 2 > len)
|
||||
return -1;
|
||||
for (i=0; i<2; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
ihex->data[j] = strtoul(buf, &e, 16);
|
||||
if (e == buf || *e != 0)
|
||||
return -1;
|
||||
cksum += ihex->data[j];
|
||||
}
|
||||
|
||||
/* cksum */
|
||||
if (offset + 2 > len)
|
||||
return -1;
|
||||
for (i=0; i<2; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
ihex->cksum = strtoul(buf, &e, 16);
|
||||
if (e == buf || *e != 0)
|
||||
return -1;
|
||||
|
||||
rc = -cksum & 0x000000ff;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Intel Hex to binary buffer
|
||||
*
|
||||
* Given an open file 'inf' which contains Intel Hex formated data,
|
||||
* parse the file and lay it out within the memory buffer pointed to
|
||||
* by outbuf. The size of outbuf, 'bufsize' is honored; if data would
|
||||
* fall outsize of the memory buffer outbuf, an error is generated.
|
||||
*
|
||||
* Return the maximum memory address within 'outbuf' that was written.
|
||||
* If an error occurs, return -1.
|
||||
*
|
||||
* */
|
||||
static int ihex2b(char * infile, FILE * inf,
|
||||
unsigned char * outbuf, int bufsize)
|
||||
{
|
||||
char buffer [ MAX_LINE_LEN ];
|
||||
unsigned char * buf;
|
||||
unsigned int nextaddr, baseaddr, maxaddr, offsetaddr;
|
||||
int i;
|
||||
int lineno;
|
||||
int len;
|
||||
struct ihexrec ihex;
|
||||
int rc;
|
||||
|
||||
lineno = 0;
|
||||
buf = outbuf;
|
||||
baseaddr = 0;
|
||||
maxaddr = 0;
|
||||
offsetaddr = 0;
|
||||
nextaddr = 0;
|
||||
|
||||
while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) {
|
||||
lineno++;
|
||||
len = strlen(buffer);
|
||||
if (buffer[len-1] == '\n')
|
||||
buffer[--len] = 0;
|
||||
if (buffer[0] != ':')
|
||||
continue;
|
||||
rc = ihex_readrec(&ihex, buffer);
|
||||
if (rc < 0) {
|
||||
logprintf(LOG_ERR, "invalid record at line %d of \"%s\"", lineno, infile);
|
||||
return -1;
|
||||
}
|
||||
else if (rc != ihex.cksum) {
|
||||
logprintf(LOG_ERR, "ERROR: checksum mismatch at line %d of \"%s\"", lineno, infile);
|
||||
logprintf(LOG_ERR, "checksum=0x%02x, computed checksum=0x%02x", ihex.cksum, rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (ihex.rectyp) {
|
||||
case 0: /* data record */
|
||||
nextaddr = ihex.loadofs + baseaddr;
|
||||
if ((nextaddr + ihex.reclen) > (bufsize+offsetaddr)) {
|
||||
logprintf(LOG_ERR, "ERROR: address 0x%04x out of range at line %d of %s", nextaddr+ihex.reclen, lineno, infile);
|
||||
return -1;
|
||||
}
|
||||
for (i=0; i<ihex.reclen; i++) {
|
||||
buf[nextaddr+i-offsetaddr] = ihex.data[i];
|
||||
}
|
||||
if (nextaddr+ihex.reclen > maxaddr)
|
||||
maxaddr = nextaddr+ihex.reclen;
|
||||
break;
|
||||
|
||||
case 1: /* end of file record */
|
||||
return maxaddr-offsetaddr;
|
||||
break;
|
||||
|
||||
case 2: /* extended segment address record */
|
||||
baseaddr = (ihex.data[0] << 8 | ihex.data[1]) << 4;
|
||||
break;
|
||||
|
||||
case 3: /* start segment address record */
|
||||
/* we don't do anything with the start address */
|
||||
break;
|
||||
|
||||
case 4: /* extended linear address record */
|
||||
baseaddr = (ihex.data[0] << 8 | ihex.data[1]) << 16;
|
||||
if(nextaddr == 0) offsetaddr = baseaddr; // if provided before any data, then remember it
|
||||
break;
|
||||
|
||||
case 5: /* start linear address record */
|
||||
/* we don't do anything with the start address */
|
||||
break;
|
||||
|
||||
default:
|
||||
logprintf(LOG_ERR, "don't know how to deal with rectype=%d at line %d of %s", ihex.rectyp, lineno, infile);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
} /* while */
|
||||
|
||||
logprintf(LOG_ERR, "no end of file record found for Intel Hex file \"%s\"", infile);
|
||||
|
||||
return maxaddr-offsetaddr;
|
||||
}
|
||||
|
||||
static int fileio_imm(struct fioparms * fio,
|
||||
char * filename, FILE * f, unsigned char * buf, int size)
|
||||
{
|
||||
int rc = 0;
|
||||
char *e = NULL, **array = NULL;
|
||||
unsigned long b = 0;
|
||||
int loc = 0;
|
||||
unsigned int n = 0, i = 0;
|
||||
|
||||
switch (fio->op) {
|
||||
case FIO_READ:
|
||||
loc = 0;
|
||||
n = explode(filename, " ,", &array);
|
||||
for(i=0;i<n;i++) {
|
||||
if(loc < size) {
|
||||
b = strtoul(array[i], &e, 0);
|
||||
/* check for binary formated (0b10101001) strings */
|
||||
b = (strncmp (array[i], "0b", 2))?
|
||||
strtoul (array[i], &e, 0):
|
||||
strtoul (array[i] + 2, &e, 2);
|
||||
if (*e != 0) {
|
||||
logprintf(LOG_ERR, "invalid byte value (%s) specified for immediate mode", array[i]);
|
||||
array_free(&array, n);
|
||||
return -1;
|
||||
}
|
||||
buf[loc++] = b;
|
||||
rc = loc;
|
||||
}
|
||||
}
|
||||
array_free(&array, n);
|
||||
break;
|
||||
default:
|
||||
logprintf(LOG_ERR, "fileio: invalid operation=%d", fio->op);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rc < 0 || (fio->op == FIO_WRITE && rc < size)) {
|
||||
logprintf(LOG_ERR, "%s error %s %s: %s; %s %d of the expected %d bytes",
|
||||
fio->iodesc, fio->dir, filename, strerror(errno), fio->rw, rc, size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int fileio_ihex(struct fioparms * fio,
|
||||
char * filename, FILE * f, unsigned char * buf, int size)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch (fio->op) {
|
||||
case FIO_WRITE:
|
||||
rc = b2ihex(buf, size, 32, 0, filename, f);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case FIO_READ:
|
||||
rc = ihex2b(filename, f, buf, size);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
logprintf(LOG_ERR, "invalid Intex Hex file I/O operation=%d", fio->op);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int fileio_setparms(int op, struct fioparms * fp)
|
||||
{
|
||||
fp->op = op;
|
||||
|
||||
switch (op) {
|
||||
case FIO_READ:
|
||||
fp->mode = "r";
|
||||
fp->iodesc = "input";
|
||||
fp->dir = "from";
|
||||
fp->rw = "read";
|
||||
break;
|
||||
|
||||
case FIO_WRITE:
|
||||
fp->mode = "w";
|
||||
fp->iodesc = "output";
|
||||
fp->dir = "to";
|
||||
fp->rw = "wrote";
|
||||
break;
|
||||
|
||||
default:
|
||||
logprintf(LOG_ERR, "invalid I/O operation %d", op);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fmt_autodetect(char * fname)
|
||||
{
|
||||
FILE * f;
|
||||
unsigned char buf[MAX_LINE_LEN];
|
||||
int i;
|
||||
int len;
|
||||
int found;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (f == NULL) {
|
||||
logprintf(LOG_ERR, "error opening %s: %s", fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets((char *)buf, MAX_LINE_LEN, f)!=NULL) {
|
||||
buf[MAX_LINE_LEN-1] = 0;
|
||||
len = strlen((char *)buf);
|
||||
if (buf[len-1] == '\n')
|
||||
buf[--len] = 0;
|
||||
|
||||
/* check for binary data */
|
||||
found = 0;
|
||||
for (i=0; i<len; i++) {
|
||||
if (buf[i] > 127) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
fclose(f);
|
||||
return FMT_RBIN;
|
||||
}
|
||||
|
||||
/* check for lines that look like intel hex */
|
||||
if ((buf[0] == ':') && (len >= 11)) {
|
||||
found = 1;
|
||||
for (i=1; i<len; i++) {
|
||||
if (!isxdigit(buf[1])) {
|
||||
found = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
fclose(f);
|
||||
return FMT_IHEX;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for lines that look like motorola s-record */
|
||||
if ((buf[0] == 'S') && (len >= 10) && isdigit(buf[1])) {
|
||||
found = 1;
|
||||
for (i=1; i<len; i++) {
|
||||
if (!isxdigit(buf[1])) {
|
||||
found = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
fclose(f);
|
||||
return FMT_SREC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fileio(int op, char * filename, FILEFMT format,
|
||||
struct avrpart * p, char * memtype, int size)
|
||||
{
|
||||
int rc;
|
||||
FILE * f;
|
||||
char * fname;
|
||||
unsigned char * buf;
|
||||
struct fioparms fio;
|
||||
AVRMEM * mem = NULL;
|
||||
|
||||
if(strcmp(memtype, "flash") == 0) {
|
||||
mem = p->flashmem;
|
||||
} else if(strcmp(memtype, "lfuse") == 0) {
|
||||
mem = p->lfusemem;
|
||||
} else if(strcmp(memtype, "hfuse") == 0) {
|
||||
mem = p->hfusemem;
|
||||
}
|
||||
if (mem == NULL) {
|
||||
logprintf(LOG_ERR, "fileio(): memory type \"%s\" not configured for device \"%s\"", memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = fileio_setparms(op, &fio);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
/* point at the requested memory buffer */
|
||||
buf = mem->buf;
|
||||
if (fio.op == FIO_READ)
|
||||
size = mem->size;
|
||||
|
||||
if (fio.op == FIO_READ) {
|
||||
/* 0xff fill unspecified memory */
|
||||
memset(buf, 0xff, size);
|
||||
}
|
||||
|
||||
fname = filename;
|
||||
f = NULL;
|
||||
|
||||
if (format == FMT_AUTO) {
|
||||
format = fmt_autodetect(fname);
|
||||
logprintf(LOG_INFO, "%s file %s auto detected as Intel Hex", fio.iodesc, fname);
|
||||
}
|
||||
|
||||
if (format != FMT_IMM) {
|
||||
f = fopen(fname, fio.mode);
|
||||
if (f == NULL) {
|
||||
logprintf(LOG_ERR, "can't open %s file %s: %s", fio.iodesc, fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case FMT_IHEX:
|
||||
rc = fileio_ihex(&fio, fname, f, buf, size);
|
||||
break;
|
||||
case FMT_IMM:
|
||||
rc = fileio_imm(&fio, fname, f, buf, size);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rc > 0) {
|
||||
if ((op == FIO_READ) && (strcasecmp(mem->desc, "flash") == 0)) {
|
||||
/*
|
||||
* if we are reading flash, just mark the size as being the
|
||||
* highest non-0xff byte
|
||||
*/
|
||||
rc = avr_mem_hiaddr(mem);
|
||||
}
|
||||
}
|
||||
if (format != FMT_IMM) {
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: fileio.h 722 2007-01-24 22:43:46Z joerg_wunsch $ */
|
||||
|
||||
#ifndef fileio_h
|
||||
#define fileio_h
|
||||
|
||||
typedef enum {
|
||||
FMT_AUTO,
|
||||
FMT_SREC,
|
||||
FMT_IHEX,
|
||||
FMT_RBIN,
|
||||
FMT_IMM,
|
||||
FMT_HEX,
|
||||
FMT_DEC,
|
||||
FMT_OCT,
|
||||
FMT_BIN
|
||||
} FILEFMT;
|
||||
|
||||
struct fioparms {
|
||||
int op;
|
||||
char * mode;
|
||||
char * iodesc;
|
||||
char * dir;
|
||||
char * rw;
|
||||
};
|
||||
|
||||
enum {
|
||||
FIO_READ,
|
||||
FIO_WRITE
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
char * fmtstr(FILEFMT format);
|
||||
|
||||
int fileio_setparms(int op, struct fioparms * fp);
|
||||
|
||||
int fileio(int op, char * filename, FILEFMT format,
|
||||
struct avrpart * p, char * memtype, int size);
|
||||
|
||||
int fmt_autodetect(char * fname);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: pgm.c 797 2009-02-17 15:31:27Z joerg_wunsch $ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../pilight/core/log.h"
|
||||
#include "../pilight/core/mem.h"
|
||||
#include "avrdude.h"
|
||||
#include "pgm.h"
|
||||
|
||||
static int pgm_default_2 (struct programmer_t *, AVRPART *);
|
||||
static int pgm_default_3 (struct programmer_t * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char * value);
|
||||
static void pgm_default_4 (struct programmer_t *);
|
||||
static int pgm_default_5 (struct programmer_t * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char data);
|
||||
static void pgm_default_6 (struct programmer_t *, const char *);
|
||||
|
||||
|
||||
static int pgm_default_open (struct programmer_t *pgm, char * name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pgm_default_led (struct programmer_t * pgm, int value)
|
||||
{
|
||||
/*
|
||||
* If programmer has no LEDs, just do nothing.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void pgm_default_powerup_powerdown (struct programmer_t * pgm)
|
||||
{
|
||||
/*
|
||||
* If programmer does not support powerup/down, just do nothing.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
PROGRAMMER * pgm_new(void)
|
||||
{
|
||||
int i;
|
||||
PROGRAMMER * pgm;
|
||||
|
||||
pgm = (PROGRAMMER *)MALLOC(sizeof(*pgm));
|
||||
if (pgm == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(pgm, 0, sizeof(*pgm));
|
||||
|
||||
pgm->desc[0] = 0;
|
||||
pgm->type[0] = 0;
|
||||
pgm->lineno = 0;
|
||||
pgm->baudrate = 0;
|
||||
|
||||
for (i=0; i<N_PINS; i++)
|
||||
pgm->pinno[i] = 0;
|
||||
|
||||
/*
|
||||
* mandatory functions - these are called without checking to see
|
||||
* whether they are assigned or not
|
||||
*/
|
||||
pgm->initialize = pgm_default_2;
|
||||
pgm->display = pgm_default_6;
|
||||
pgm->enable = pgm_default_4;
|
||||
pgm->disable = pgm_default_4;
|
||||
pgm->powerup = pgm_default_powerup_powerdown;
|
||||
pgm->powerdown = pgm_default_powerup_powerdown;
|
||||
pgm->program_enable = pgm_default_2;
|
||||
pgm->chip_erase = pgm_default_2;
|
||||
pgm->open = pgm_default_open;
|
||||
pgm->close = pgm_default_4;
|
||||
pgm->read_byte = pgm_default_3;
|
||||
pgm->write_byte = pgm_default_5;
|
||||
|
||||
/*
|
||||
* predefined functions - these functions have a valid default
|
||||
* implementation. Hence, they don't need to be defined in
|
||||
* the programmer.
|
||||
*/
|
||||
pgm->rdy_led = pgm_default_led;
|
||||
pgm->err_led = pgm_default_led;
|
||||
pgm->pgm_led = pgm_default_led;
|
||||
pgm->vfy_led = pgm_default_led;
|
||||
|
||||
/*
|
||||
* optional functions - these are checked to make sure they are
|
||||
* assigned before they are called
|
||||
*/
|
||||
pgm->cmd = NULL;
|
||||
pgm->spi = NULL;
|
||||
pgm->paged_write = NULL;
|
||||
pgm->paged_load = NULL;
|
||||
pgm->write_setup = NULL;
|
||||
pgm->read_sig_bytes = NULL;
|
||||
pgm->set_vtarget = NULL;
|
||||
pgm->set_varef = NULL;
|
||||
pgm->set_fosc = NULL;
|
||||
pgm->perform_osccal = NULL;
|
||||
pgm->setup = NULL;
|
||||
pgm->teardown = NULL;
|
||||
|
||||
return pgm;
|
||||
}
|
||||
|
||||
|
||||
static void pgm_default(void)
|
||||
{
|
||||
logprintf(LOG_NOTICE, "AVR programmer operation not supported");
|
||||
}
|
||||
|
||||
|
||||
static int pgm_default_2 (struct programmer_t * pgm, AVRPART * p)
|
||||
{
|
||||
pgm_default();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pgm_default_3 (struct programmer_t * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char * value)
|
||||
{
|
||||
pgm_default();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void pgm_default_4 (struct programmer_t * pgm)
|
||||
{
|
||||
pgm_default();
|
||||
}
|
||||
|
||||
static int pgm_default_5 (struct programmer_t * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char data)
|
||||
{
|
||||
pgm_default();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void pgm_default_6 (struct programmer_t * pgm, const char * p)
|
||||
{
|
||||
pgm_default();
|
||||
}
|
||||
|
||||
|
||||
// void programmer_display(PROGRAMMER * pgm, const char * p)
|
||||
// {
|
||||
// logprintf(LOG_INFO, "%sProgrammer Type : %s", p, pgm->type);
|
||||
// logprintf(LOG_INFO, "%sDescription : %s", p, pgm->desc);
|
||||
|
||||
// pgm->display(pgm, p);
|
||||
// }
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: pgm.h 797 2009-02-17 15:31:27Z joerg_wunsch $ */
|
||||
|
||||
#ifndef pgm_h
|
||||
#define pgm_h
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "avrpart.h"
|
||||
#include "serial.h"
|
||||
#include "pindefs.h"
|
||||
|
||||
#define ON 1
|
||||
#define OFF 0
|
||||
|
||||
#define PGM_DESCLEN 80
|
||||
#define PGM_PORTLEN 4096
|
||||
#define PGM_TYPELEN 32
|
||||
|
||||
typedef enum {
|
||||
EXIT_VCC_UNSPEC,
|
||||
EXIT_VCC_ENABLED,
|
||||
EXIT_VCC_DISABLED
|
||||
} exit_vcc_t;
|
||||
|
||||
typedef enum {
|
||||
EXIT_RESET_UNSPEC,
|
||||
EXIT_RESET_ENABLED,
|
||||
EXIT_RESET_DISABLED
|
||||
} exit_reset_t;
|
||||
|
||||
typedef struct programmer_t {
|
||||
char desc[PGM_DESCLEN];
|
||||
char type[PGM_TYPELEN];
|
||||
char port[PGM_PORTLEN];
|
||||
unsigned int pinno[N_PINS];
|
||||
exit_vcc_t exit_vcc;
|
||||
exit_reset_t exit_reset;
|
||||
int ppidata;
|
||||
int ppictrl;
|
||||
int baudrate;
|
||||
double bitclock; /* JTAG ICE clock period in microseconds */
|
||||
int ispdelay; /* ISP clock delay */
|
||||
union filedescriptor fd;
|
||||
int page_size; /* page size if the programmer supports paged write/load */
|
||||
int (*rdy_led) (struct programmer_t * pgm, int value);
|
||||
int (*err_led) (struct programmer_t * pgm, int value);
|
||||
int (*pgm_led) (struct programmer_t * pgm, int value);
|
||||
int (*vfy_led) (struct programmer_t * pgm, int value);
|
||||
int (*initialize) (struct programmer_t * pgm, AVRPART * p);
|
||||
void (*display) (struct programmer_t * pgm, const char * p);
|
||||
void (*enable) (struct programmer_t * pgm);
|
||||
void (*disable) (struct programmer_t * pgm);
|
||||
void (*powerup) (struct programmer_t * pgm);
|
||||
void (*powerdown) (struct programmer_t * pgm);
|
||||
int (*program_enable) (struct programmer_t * pgm, AVRPART * p);
|
||||
int (*chip_erase) (struct programmer_t * pgm, AVRPART * p);
|
||||
int (*cmd) (struct programmer_t * pgm, unsigned char cmd[4],
|
||||
unsigned char res[4]);
|
||||
int (*spi) (struct programmer_t * pgm, unsigned char cmd[],
|
||||
unsigned char res[], int count);
|
||||
int (*open) (struct programmer_t * pgm, char * port);
|
||||
void (*close) (struct programmer_t * pgm);
|
||||
int (*paged_write) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned int page_size, unsigned int baseaddr,
|
||||
unsigned int n_bytes);
|
||||
int (*paged_load) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned int page_size, unsigned int baseaddr,
|
||||
unsigned int n_bytes);
|
||||
void (*write_setup) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m);
|
||||
int (*write_byte) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned long addr, unsigned char value);
|
||||
int (*read_byte) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned long addr, unsigned char * value);
|
||||
int (*read_sig_bytes) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m);
|
||||
void (*print_parms) (struct programmer_t * pgm);
|
||||
int (*set_vtarget) (struct programmer_t * pgm, double v);
|
||||
int (*set_varef) (struct programmer_t * pgm, unsigned int chan, double v);
|
||||
int (*set_fosc) (struct programmer_t * pgm, double v);
|
||||
int (*set_sck_period) (struct programmer_t * pgm, double v);
|
||||
int (*setpin) (struct programmer_t * pgm, int pin, int value);
|
||||
int (*getpin) (struct programmer_t * pgm, int pin);
|
||||
int (*highpulsepin) (struct programmer_t * pgm, int pin);
|
||||
int (*parseexitspecs) (struct programmer_t * pgm, char *s);
|
||||
int (*perform_osccal) (struct programmer_t * pgm);
|
||||
void (*setup) (struct programmer_t * pgm);
|
||||
void (*teardown) (struct programmer_t * pgm);
|
||||
char config_file[4096]; /* config file where defined */
|
||||
int lineno; /* config file line number */
|
||||
void *cookie; /* for private use by the programmer */
|
||||
char flag; /* for private use of the programmer */
|
||||
} PROGRAMMER;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
PROGRAMMER * pgm_new(void);
|
||||
|
||||
void programmer_display(PROGRAMMER * pgm, const char * p);
|
||||
|
||||
typedef void (*walk_programmers_cb)(const char *name, const char *desc,
|
||||
const char *cfgname, int cfglineno,
|
||||
void *cookie);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* $Id: pindefs.h 515 2005-09-18 20:12:23Z joerg_wunsch $ */
|
||||
|
||||
#ifndef __pindefs_h__
|
||||
#define __pindefs_h__
|
||||
|
||||
enum {
|
||||
PPI_AVR_VCC=1,
|
||||
PPI_AVR_BUFF,
|
||||
PIN_AVR_RESET,
|
||||
PIN_AVR_SCK,
|
||||
PIN_AVR_MOSI,
|
||||
PIN_AVR_MISO,
|
||||
PIN_LED_ERR,
|
||||
PIN_LED_RDY,
|
||||
PIN_LED_PGM,
|
||||
PIN_LED_VFY,
|
||||
N_PINS
|
||||
};
|
||||
#define PIN_INVERSE 0x80 /* flag for inverted pin in serbb */
|
||||
#define PIN_MASK 0x7f
|
||||
|
||||
#define LED_ON(fd,pin) ppi_setpin(fd,pin,0)
|
||||
#define LED_OFF(fd,pin) ppi_setpin(fd,pin,1)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* avrdude is Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* This file: Copyright (C) 2005-2007 Colin O'Flynn <coflynn@newae.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "../pilight/core/log.h"
|
||||
#include "avrdude.h"
|
||||
#include "avr.h"
|
||||
#include "pgm.h"
|
||||
#include "safemode.h"
|
||||
|
||||
/* This value from ac_cfg.h */
|
||||
/*
|
||||
* Writes the specified fuse in fusename (can be "lfuse", "hfuse", or
|
||||
* "efuse") and verifies it. Will try up to tries amount of times
|
||||
* before giving up
|
||||
*/
|
||||
int safemode_writefuse (unsigned char fuse, const char * fusename, PROGRAMMER * pgm,
|
||||
AVRPART * p, int tries)
|
||||
{
|
||||
AVRMEM * m = NULL;
|
||||
unsigned char fuseread;
|
||||
int returnvalue = -1;
|
||||
|
||||
// m = avr_locate_mem(p, fusename);
|
||||
if (m == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Keep trying to write then read back the fuse values */
|
||||
while (tries > 0) {
|
||||
if (avr_write_byte(pgm, p, m, 0, fuse) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (pgm->read_byte(pgm, p, m, 0, &fuseread) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Report information to user if needed */
|
||||
logprintf(LOG_ERR, "AVR wrote %s to %x, read as %x. %d attempts left", fusename, fuse, fuseread, tries-1);
|
||||
|
||||
/* If fuse wrote OK, no need to keep going */
|
||||
if (fuse == fuseread) {
|
||||
tries = 0;
|
||||
returnvalue = 0;
|
||||
}
|
||||
tries--;
|
||||
}
|
||||
|
||||
return returnvalue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads the fuses three times, checking that all readings are the
|
||||
* same. This will ensure that the before values aren't in error!
|
||||
*/
|
||||
int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse,
|
||||
unsigned char * efuse, unsigned char * fuse,
|
||||
PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
|
||||
unsigned char value;
|
||||
unsigned char fusegood = 0;
|
||||
unsigned char allowfuseread = 1;
|
||||
unsigned char safemode_lfuse;
|
||||
unsigned char safemode_hfuse;
|
||||
unsigned char safemode_efuse;
|
||||
unsigned char safemode_fuse;
|
||||
AVRMEM * m = NULL;
|
||||
|
||||
safemode_lfuse = *lfuse;
|
||||
safemode_hfuse = *hfuse;
|
||||
safemode_efuse = *efuse;
|
||||
safemode_fuse = *fuse;
|
||||
|
||||
|
||||
/* Read fuse three times */
|
||||
// fusegood = 2; /* If AVR device doesn't support this fuse, don't want
|
||||
// to generate a verify error */
|
||||
// m = avr_locate_mem(p, "fuse");
|
||||
// if (m != NULL) {
|
||||
// fusegood = 0; /* By default fuse is a failure */
|
||||
// if(pgm->read_byte(pgm, p, m, 0, &safemode_fuse) != 0)
|
||||
// {
|
||||
// allowfuseread = 0;
|
||||
// }
|
||||
// if(pgm->read_byte(pgm, p, m, 0, &value) != 0)
|
||||
// {
|
||||
// allowfuseread = 0;
|
||||
// }
|
||||
// if (value == safemode_fuse) {
|
||||
// if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
|
||||
// {
|
||||
// allowfuseread = 0;
|
||||
// }
|
||||
// if (value == safemode_fuse)
|
||||
// {
|
||||
// fusegood = 1; /* Fuse read OK three times */
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// //Programmer does not allow fuse reading.... no point trying anymore
|
||||
// if (allowfuseread == 0)
|
||||
// {
|
||||
// return -5;
|
||||
// }
|
||||
|
||||
// if (fusegood == 0) {
|
||||
// logprintf(LOG_ERR, "AVR verify error, unable to read fuse properly.");
|
||||
// logprintf(LOG_ERR, "Programmer may not be reliable.");
|
||||
// return -1;
|
||||
// }
|
||||
// else if ((fusegood == 1)) {
|
||||
// logprintf(LOG_INFO, "AVR fuse reads as %X", safemode_lfuse);
|
||||
// }
|
||||
|
||||
|
||||
/* Read lfuse three times */
|
||||
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
|
||||
to generate a verify error */
|
||||
m = p->lfusemem;
|
||||
if (m != NULL) {
|
||||
fusegood = 0; /* By default fuse is a failure */
|
||||
if (pgm->read_byte(pgm, p, m, 0, &safemode_lfuse) != 0) {
|
||||
allowfuseread = 0;
|
||||
}
|
||||
if (pgm->read_byte(pgm, p, m, 0, &value) != 0) {
|
||||
allowfuseread = 0;
|
||||
}
|
||||
if (value == safemode_lfuse) {
|
||||
if (pgm->read_byte(pgm, p, m, 0, &value) != 0) {
|
||||
allowfuseread = 0;
|
||||
}
|
||||
if (value == safemode_lfuse) {
|
||||
fusegood = 1; /* Fuse read OK three times */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Programmer does not allow fuse reading.... no point trying anymore
|
||||
if (allowfuseread == 0) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
|
||||
if (fusegood == 0) {
|
||||
logprintf(LOG_ERR, "AVR verify error, unable to read lfuse properly.");
|
||||
logprintf(LOG_ERR, "Programmer may not be reliable.");
|
||||
return -1;
|
||||
}
|
||||
else if (fusegood == 1) {
|
||||
logprintf(LOG_INFO, "AVR lfuse reads as %X", safemode_lfuse);
|
||||
}
|
||||
|
||||
/* Read hfuse three times */
|
||||
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
|
||||
to generate a verify error */
|
||||
m = p->hfusemem;
|
||||
if (m != NULL) {
|
||||
fusegood = 0; /* By default fuse is a failure */
|
||||
if (pgm->read_byte(pgm, p, m, 0, &safemode_hfuse) != 0) {
|
||||
allowfuseread = 0;
|
||||
}
|
||||
if (pgm->read_byte(pgm, p, m, 0, &value) != 0) {
|
||||
allowfuseread = 0;
|
||||
}
|
||||
if (value == safemode_hfuse) {
|
||||
if (pgm->read_byte(pgm, p, m, 0, &value) != 0) {
|
||||
allowfuseread = 0;
|
||||
}
|
||||
if (value == safemode_hfuse) {
|
||||
fusegood = 1; /* Fuse read OK three times */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Programmer does not allow fuse reading.... no point trying anymore
|
||||
if (allowfuseread == 0) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
if (fusegood == 0) {
|
||||
logprintf(LOG_ERR, "AVR verify error, unable to read hfuse properly.");
|
||||
logprintf(LOG_ERR, "Programmer may not be reliable.");
|
||||
return -1;
|
||||
}
|
||||
else if (fusegood == 1) {
|
||||
logprintf(LOG_INFO, "AVR hfuse reads as %X", safemode_lfuse);
|
||||
}
|
||||
|
||||
/* Read efuse three times */
|
||||
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
|
||||
to generate a verify error */
|
||||
// m = avr_locate_mem(p, "efuse");
|
||||
// if (m != NULL) {
|
||||
// fusegood = 0; /* By default fuse is a failure */
|
||||
// if (pgm->read_byte(pgm, p, m, 0, &safemode_efuse) != 0)
|
||||
// {
|
||||
// allowfuseread = 0;
|
||||
// }
|
||||
// if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
|
||||
// {
|
||||
// allowfuseread = 0;
|
||||
// }
|
||||
// if (value == safemode_efuse) {
|
||||
// if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
|
||||
// {
|
||||
// allowfuseread = 0;
|
||||
// }
|
||||
// if (value == safemode_efuse){
|
||||
// fusegood = 1; /* Fuse read OK three times */
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// //Programmer does not allow fuse reading.... no point trying anymore
|
||||
// if (allowfuseread == 0)
|
||||
// {
|
||||
// return -5;
|
||||
// }
|
||||
|
||||
// if (fusegood == 0) {
|
||||
// logprintf(LOG_ERR, "AVR verify error, unable to read efuse properly.");
|
||||
// logprintf(LOG_ERR, "Programmer may not be reliable.");
|
||||
// return -1;
|
||||
// }
|
||||
// else if ((fusegood == 1)) {
|
||||
// logprintf(LOG_INFO, "AVR efuse reads as %X", safemode_lfuse);
|
||||
// }
|
||||
|
||||
*lfuse = safemode_lfuse;
|
||||
*hfuse = safemode_hfuse;
|
||||
*efuse = safemode_efuse;
|
||||
*fuse = safemode_fuse;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This routine will store the current values pointed to by lfuse,
|
||||
* hfuse, and efuse into an internal buffer in this routine when save
|
||||
* is set to 1. When save is 0 (or not 1 really) it will copy the
|
||||
* values from the internal buffer into the locations pointed to be
|
||||
* lfuse, hfuse, and efuse. This allows you to change the fuse bits if
|
||||
* needed from another routine (ie: have it so if user requests fuse
|
||||
* bits are changed, the requested value is now verified
|
||||
*/
|
||||
int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse,
|
||||
unsigned char * efuse, unsigned char * fuse)
|
||||
{
|
||||
static unsigned char safemode_lfuse = 0xff;
|
||||
static unsigned char safemode_hfuse = 0xff;
|
||||
static unsigned char safemode_efuse = 0xff;
|
||||
static unsigned char safemode_fuse = 0xff;
|
||||
|
||||
switch (save) {
|
||||
|
||||
/* Save the fuses as safemode setting */
|
||||
case 1:
|
||||
safemode_lfuse = *lfuse;
|
||||
safemode_hfuse = *hfuse;
|
||||
safemode_efuse = *efuse;
|
||||
safemode_fuse = *fuse;
|
||||
|
||||
break;
|
||||
/* Read back the fuses */
|
||||
default:
|
||||
*lfuse = safemode_lfuse;
|
||||
*hfuse = safemode_hfuse;
|
||||
*efuse = safemode_efuse;
|
||||
*fuse = safemode_fuse;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* avrdude is Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* This file: Copyright (C) 2005 Colin O'Flynn <coflynn@newae.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
#ifndef safemode_h
|
||||
#define safemode_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Writes the specified fuse in fusename (can be "lfuse", "hfuse", or "efuse") and verifies it. Will try up to tries
|
||||
amount of times before giving up */
|
||||
int safemode_writefuse (unsigned char fuse, const char * fusename, PROGRAMMER * pgm, AVRPART * p, int tries);
|
||||
|
||||
/* Reads the fuses three times, checking that all readings are the same. This will ensure that the before values aren't in error! */
|
||||
int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse, PROGRAMMER * pgm, AVRPART * p);
|
||||
|
||||
/* This routine will store the current values pointed to by lfuse, hfuse, and efuse into an internal buffer in this routine
|
||||
when save is set to 1. When save is 0 (or not 1 really) it will copy the values from the internal buffer into the locations
|
||||
pointed to be lfuse, hfuse, and efuse. This allows you to change the fuse bits if needed from another routine (ie: have it so
|
||||
if user requests fuse bits are changed, the requested value is now verified */
|
||||
int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* safemode_h */
|
||||
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id: ser_posix.c 1294 2014-03-12 23:03:18Z joerg_wunsch $ */
|
||||
|
||||
/*
|
||||
* Posix serial interface for avrdude.
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../pilight/core/log.h"
|
||||
#include "../pilight/core/mem.h"
|
||||
#include "avrdude.h"
|
||||
#include "serial.h"
|
||||
|
||||
long serial_recv_timeout = 5000; /* ms */
|
||||
|
||||
static struct termios original_termios;
|
||||
static int saved_original_termios;
|
||||
|
||||
static int ser_setspeed(union filedescriptor *fd, long baud) {
|
||||
int rc = 0;
|
||||
struct termios termios;
|
||||
speed_t speed = baud;
|
||||
|
||||
if(!isatty(fd->ifd)) {
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize terminal modes
|
||||
*/
|
||||
if(tcgetattr(fd->ifd, &termios) < 0) {
|
||||
logprintf(LOG_ERR, "ser_setspeed(): tcgetattr() failed");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy termios for ser_close if we haven't already
|
||||
*/
|
||||
if(!saved_original_termios++) {
|
||||
original_termios = termios;
|
||||
}
|
||||
|
||||
termios.c_iflag = IGNBRK;
|
||||
termios.c_oflag = 0;
|
||||
termios.c_lflag = 0;
|
||||
termios.c_cflag = (CS8 | CREAD | CLOCAL);
|
||||
termios.c_cc[VMIN] = 1;
|
||||
termios.c_cc[VTIME] = 0;
|
||||
|
||||
cfsetospeed(&termios, speed);
|
||||
cfsetispeed(&termios, speed);
|
||||
|
||||
if(tcsetattr(fd->ifd, TCSANOW, &termios) < 0) {
|
||||
logprintf(LOG_ERR, "%s: ser_setspeed(): tcsetattr() failed");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Everything is now set up for a local line without modem control
|
||||
* or flow control, so clear O_NONBLOCK again.
|
||||
*/
|
||||
rc = fcntl(fd->ifd, F_GETFL, 0);
|
||||
if(rc != -1) {
|
||||
fcntl(fd->ifd, F_SETFL, rc & ~O_NONBLOCK);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ser_set_dtr_rts(union filedescriptor *fdp, int is_on) {
|
||||
unsigned int ctl = 0;
|
||||
|
||||
if(ioctl(fdp->ifd, TIOCMGET, &ctl) < 0) {
|
||||
// perror("ioctl(\"TIOCMGET\")");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(is_on > 0) {
|
||||
/* Set DTR and RTS */
|
||||
ctl |= (TIOCM_DTR | TIOCM_RTS);
|
||||
} else {
|
||||
/* Clear DTR and RTS */
|
||||
ctl &= ~(TIOCM_DTR | TIOCM_RTS);
|
||||
}
|
||||
|
||||
if(ioctl(fdp->ifd, TIOCMSET, &ctl) < 0) {
|
||||
// perror("ioctl(\"TIOCMSET\")");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp) {
|
||||
int rc = 0, fd = 0;
|
||||
|
||||
/*
|
||||
* open the serial port
|
||||
*/
|
||||
if((fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0) {
|
||||
logprintf(LOG_ERR, "ser_open(): can't open device \"%s\": %s", port, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdp->ifd = fd;
|
||||
|
||||
/*
|
||||
* set serial line attributes
|
||||
*/
|
||||
if((rc = ser_setspeed(fdp, pinfo.baud)) > 0) {
|
||||
logprintf(LOG_ERR, "ser_open(): can't set attributes for device \"%s\": %s", port, strerror(-rc));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ser_close(union filedescriptor *fd) {
|
||||
/*
|
||||
* restore original termios settings from ser_open
|
||||
*/
|
||||
if(saved_original_termios > 0) {
|
||||
if(tcsetattr(fd->ifd, TCSANOW | TCSADRAIN, &original_termios) > 0) {
|
||||
logprintf(LOG_ERR, "ser_close(): can't reset attributes for device: %s", strerror(errno));
|
||||
}
|
||||
saved_original_termios = 0;
|
||||
}
|
||||
|
||||
close(fd->ifd);
|
||||
}
|
||||
|
||||
|
||||
static int ser_send(union filedescriptor *fd, unsigned char * buf, size_t buflen) {
|
||||
int rc = 0;
|
||||
unsigned char *p = buf;
|
||||
size_t len = buflen;
|
||||
|
||||
if(len <= 0)
|
||||
return 0;
|
||||
|
||||
while(len) {
|
||||
rc = write(fd->ifd, p, (len > 1024) ? 1024 : len);
|
||||
if(rc < 0) {
|
||||
logprintf(LOG_ERR, "ser_send(): write error: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
p += rc;
|
||||
len -= rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen) {
|
||||
struct timeval timeout, to2;
|
||||
fd_set rfds;
|
||||
int nfds = 0, rc = 0;
|
||||
unsigned char *p = buf;
|
||||
size_t len = 0;
|
||||
|
||||
timeout.tv_sec = serial_recv_timeout / 1000L;
|
||||
timeout.tv_usec = (serial_recv_timeout % 1000L) * 1000;
|
||||
to2 = timeout;
|
||||
|
||||
while(len < buflen) {
|
||||
reselect:
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(fd->ifd, &rfds);
|
||||
|
||||
nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &to2);
|
||||
if(nfds == 0) {
|
||||
logprintf(LOG_ERR, "ser_recv(): programmer is not responding");
|
||||
return -1;
|
||||
} else if(nfds == -1) {
|
||||
if(errno == EINTR || errno == EAGAIN) {
|
||||
logprintf(LOG_ERR, "ser_recv(): programmer is not responding, reselecting");
|
||||
goto reselect;
|
||||
} else {
|
||||
logprintf(LOG_ERR, "ser_recv(): select(): %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rc = read(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len);
|
||||
if(rc < 0) {
|
||||
logprintf(LOG_ERR, "ser_recv(): read error: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
p += rc;
|
||||
len += rc;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ser_drain(union filedescriptor *fd, int display) {
|
||||
struct timeval timeout;
|
||||
fd_set rfds;
|
||||
int nfds = 0, rc = 0;
|
||||
unsigned char buf;
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 250000;
|
||||
|
||||
while(1) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(fd->ifd, &rfds);
|
||||
|
||||
reselect:
|
||||
nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &timeout);
|
||||
if(nfds == 0) {
|
||||
break;
|
||||
} else if(nfds == -1) {
|
||||
if(errno == EINTR) {
|
||||
goto reselect;
|
||||
} else {
|
||||
logprintf(LOG_ERR, "ser_drain(): select(): %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rc = read(fd->ifd, &buf, 1);
|
||||
if(rc < 0) {
|
||||
logprintf(LOG_ERR, "ser_drain(): read error: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct serial_device serial_serdev = {
|
||||
.open = ser_open,
|
||||
.setspeed = ser_setspeed,
|
||||
.close = ser_close,
|
||||
.send = ser_send,
|
||||
.recv = ser_recv,
|
||||
.drain = ser_drain,
|
||||
.set_dtr_rts = ser_set_dtr_rts,
|
||||
.flags = SERDEV_FL_CANSETSPEED,
|
||||
};
|
||||
|
||||
struct serial_device *serdev = &serial_serdev;
|
||||
|
||||
#endif /* WIN32NATIVE */
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id: ser_win32.c 1294 2014-03-12 23:03:18Z joerg_wunsch $ */
|
||||
|
||||
/*
|
||||
* Native Win32 serial interface for avrdude.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "../pilight/core/log.h"
|
||||
#include "../pilight/core/mem.h"
|
||||
#include "serial.h"
|
||||
|
||||
long serial_recv_timeout = 5000; /* ms */
|
||||
|
||||
#define W32SERBUFSIZE 1024
|
||||
|
||||
static BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) {
|
||||
COMMTIMEOUTS ctmo;
|
||||
ZeroMemory (&ctmo, sizeof(COMMTIMEOUTS));
|
||||
ctmo.ReadIntervalTimeout = timeout;
|
||||
ctmo.ReadTotalTimeoutMultiplier = timeout;
|
||||
ctmo.ReadTotalTimeoutConstant = timeout;
|
||||
|
||||
return SetCommTimeouts(hComPort, &ctmo);
|
||||
}
|
||||
|
||||
static int ser_setspeed(union filedescriptor *fd, long baud) {
|
||||
DCB dcb;
|
||||
HANDLE hComPort = (HANDLE)fd->pfd;
|
||||
|
||||
ZeroMemory (&dcb, sizeof(DCB));
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
dcb.BaudRate = baud;
|
||||
dcb.fBinary = 1;
|
||||
dcb.fDtrControl = DTR_CONTROL_DISABLE;
|
||||
dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||||
dcb.ByteSize = 8;
|
||||
dcb.Parity = NOPARITY;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
|
||||
if(!SetCommState(hComPort, &dcb)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp) {
|
||||
LPVOID lpMsgBuf;
|
||||
HANDLE hComPort=INVALID_HANDLE_VALUE;
|
||||
char *newname = 0;
|
||||
|
||||
if(strncasecmp(port, "com", strlen("com")) == 0) {
|
||||
// prepend "\\\\.\\" to name, required for port # >= 10
|
||||
newname = MALLOC(strlen("\\\\.\\") + strlen(port) + 1);
|
||||
|
||||
if(newname == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strcpy(newname, "\\\\.\\");
|
||||
strcat(newname, port);
|
||||
|
||||
port = newname;
|
||||
}
|
||||
|
||||
hComPort = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if(hComPort == INVALID_HANDLE_VALUE) {
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
logprintf(LOG_ERR, "ser_open(): can't open device \"%s\": %s", port, (char*)lpMsgBuf);
|
||||
if(newname != NULL) {
|
||||
FREE(newname);
|
||||
}
|
||||
LocalFree(lpMsgBuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!SetupComm(hComPort, W32SERBUFSIZE, W32SERBUFSIZE)) {
|
||||
CloseHandle(hComPort);
|
||||
logprintf(LOG_ERR, "ser_open(): can't set buffers for \"%s\"", port);
|
||||
if(newname != NULL) {
|
||||
FREE(newname);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdp->pfd = (void *)hComPort;
|
||||
if(ser_setspeed(fdp, pinfo.baud) != 0) {
|
||||
CloseHandle(hComPort);
|
||||
logprintf(LOG_ERR, "ser_open(): can't set com-state for \"%s\"", port);
|
||||
if(newname != NULL) {
|
||||
FREE(newname);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!serial_w32SetTimeOut(hComPort, 0)) {
|
||||
CloseHandle(hComPort);
|
||||
logprintf(LOG_ERR, "ser_open(): can't set initial timeout for \"%s\"", port);
|
||||
if(newname != NULL) {
|
||||
FREE(newname);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(newname != NULL) {
|
||||
FREE(newname);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ser_close(union filedescriptor *fd) {
|
||||
HANDLE hComPort=(HANDLE)fd->pfd;
|
||||
if(hComPort != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle (hComPort);
|
||||
}
|
||||
|
||||
hComPort = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
static int ser_set_dtr_rts(union filedescriptor *fd, int is_on) {
|
||||
HANDLE hComPort=(HANDLE)fd->pfd;
|
||||
|
||||
if(is_on > 0) {
|
||||
EscapeCommFunction(hComPort, SETDTR);
|
||||
EscapeCommFunction(hComPort, SETRTS);
|
||||
} else {
|
||||
EscapeCommFunction(hComPort, CLRDTR);
|
||||
EscapeCommFunction(hComPort, CLRRTS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ser_send(union filedescriptor *fd, unsigned char *buf, size_t buflen) {
|
||||
size_t len = buflen;
|
||||
DWORD written;
|
||||
|
||||
HANDLE hComPort = (HANDLE)fd->pfd;
|
||||
|
||||
if(hComPort == INVALID_HANDLE_VALUE) {
|
||||
logprintf(LOG_ERR, "ser_send(): port not open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
serial_w32SetTimeOut(hComPort,500);
|
||||
|
||||
if(!WriteFile(hComPort, buf, buflen, &written, NULL)) {
|
||||
logprintf(LOG_ERR, "ser_send(): write error"); // TODO
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(written != buflen) {
|
||||
logprintf(LOG_ERR, "ser_send(): size/send mismatch");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ser_recv(union filedescriptor *fd, unsigned char *buf, size_t buflen) {
|
||||
DWORD read;
|
||||
|
||||
HANDLE hComPort = (HANDLE)fd->pfd;
|
||||
|
||||
if(hComPort == INVALID_HANDLE_VALUE) {
|
||||
logprintf(LOG_ERR, "ser_read(): port not open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
serial_w32SetTimeOut(hComPort, serial_recv_timeout);
|
||||
|
||||
if(!ReadFile(hComPort, buf, buflen, &read, NULL)) {
|
||||
LPVOID lpMsgBuf;
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
logprintf(LOG_ERR, "ser_recv(): read error: %s", (char*)lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* time out detected */
|
||||
if(read == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ser_drain(union filedescriptor *fd, int display) {
|
||||
unsigned char buf[10];
|
||||
BOOL readres;
|
||||
DWORD read;
|
||||
|
||||
HANDLE hComPort=(HANDLE)fd->pfd;
|
||||
|
||||
if(hComPort == INVALID_HANDLE_VALUE) {
|
||||
logprintf(LOG_ERR, "%s: ser_drain(): port not open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
serial_w32SetTimeOut(hComPort,250);
|
||||
|
||||
while(1) {
|
||||
readres=ReadFile(hComPort, buf, 1, &read, NULL);
|
||||
if(!readres) {
|
||||
LPVOID lpMsgBuf;
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
logprintf(LOG_ERR, "ser_drain(): read error: %s", (char*)lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(read <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct serial_device serial_serdev = {
|
||||
.open = ser_open,
|
||||
.setspeed = ser_setspeed,
|
||||
.close = ser_close,
|
||||
.send = ser_send,
|
||||
.recv = ser_recv,
|
||||
.drain = ser_drain,
|
||||
.set_dtr_rts = ser_set_dtr_rts,
|
||||
.flags = SERDEV_FL_CANSETSPEED,
|
||||
};
|
||||
|
||||
struct serial_device *serdev = &serial_serdev;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id: serial.h 1294 2014-03-12 23:03:18Z joerg_wunsch $ */
|
||||
|
||||
/* This is the API for the generic serial interface. The implementations are
|
||||
actually provided by the target dependant files:
|
||||
|
||||
ser_posix.c : posix serial interface.
|
||||
ser_win32.c : native win32 serial interface.
|
||||
|
||||
The target file will be selected at configure time. */
|
||||
|
||||
#ifndef serial_h
|
||||
#define serial_h
|
||||
|
||||
extern long serial_recv_timeout;
|
||||
union filedescriptor
|
||||
{
|
||||
int ifd;
|
||||
void *pfd;
|
||||
struct
|
||||
{
|
||||
void *handle;
|
||||
int rep; /* bulk read endpoint */
|
||||
int wep; /* bulk write endpoint */
|
||||
int eep; /* event read endpoint */
|
||||
int max_xfer; /* max transfer size */
|
||||
int use_interrupt_xfer; /* device uses interrupt transfers */
|
||||
} usb;
|
||||
};
|
||||
|
||||
union pinfo
|
||||
{
|
||||
long baud;
|
||||
struct
|
||||
{
|
||||
unsigned short vid;
|
||||
unsigned short pid;
|
||||
unsigned short flags;
|
||||
#define PINFO_FL_USEHID 0x0001
|
||||
#define PINFO_FL_SILENT 0x0002 /* don't complain if not found */
|
||||
} usbinfo;
|
||||
};
|
||||
|
||||
|
||||
struct serial_device
|
||||
{
|
||||
// open should return -1 on error, other values on success
|
||||
int (*open)(char * port, union pinfo pinfo, union filedescriptor *fd);
|
||||
int (*setspeed)(union filedescriptor *fd, long baud);
|
||||
void (*close)(union filedescriptor *fd);
|
||||
|
||||
int (*send)(union filedescriptor *fd, unsigned char * buf, size_t buflen);
|
||||
int (*recv)(union filedescriptor *fd, unsigned char * buf, size_t buflen);
|
||||
int (*drain)(union filedescriptor *fd, int display);
|
||||
|
||||
int (*set_dtr_rts)(union filedescriptor *fd, int is_on);
|
||||
|
||||
int flags;
|
||||
#define SERDEV_FL_NONE 0x0000 /* no flags */
|
||||
#define SERDEV_FL_CANSETSPEED 0x0001 /* device can change speed */
|
||||
};
|
||||
|
||||
extern struct serial_device *serdev;
|
||||
extern struct serial_device serial_serdev;
|
||||
extern struct serial_device usb_serdev;
|
||||
extern struct serial_device usb_serdev_frame;
|
||||
extern struct serial_device avrdoper_serdev;
|
||||
|
||||
#define serial_open (serdev->open)
|
||||
#define serial_setspeed (serdev->setspeed)
|
||||
#define serial_close (serdev->close)
|
||||
#define serial_send (serdev->send)
|
||||
#define serial_recv (serdev->recv)
|
||||
#define serial_drain (serdev->drain)
|
||||
#define serial_set_dtr_rts (serdev->set_dtr_rts)
|
||||
|
||||
#endif /* serial_h */
|
||||
@@ -0,0 +1,624 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2008,2014 Joerg Wunsch
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id: stk500.c 1294 2014-03-12 23:03:18Z joerg_wunsch $ */
|
||||
|
||||
/*
|
||||
* avrdude interface for Atmel STK500 programmer
|
||||
*
|
||||
* Note: most commands use the "universal command" feature of the
|
||||
* programmer in a "pass through" mode, exceptions are "program
|
||||
* enable", "paged read", and "paged write".
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../pilight/core/log.h"
|
||||
#include "avrdude.h"
|
||||
#include "avr.h"
|
||||
#include "pgm.h"
|
||||
#include "stk500.h"
|
||||
#include "stk500_private.h"
|
||||
#include "serial.h"
|
||||
|
||||
#define STK500_XTAL 7372800U
|
||||
#define MAX_SYNC_ATTEMPTS 1
|
||||
|
||||
struct pdata {
|
||||
unsigned char ext_addr_byte; /* Record ext-addr byte set in the target device (if used) */
|
||||
};
|
||||
|
||||
#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
|
||||
|
||||
static int stk500_send(PROGRAMMER *pgm, unsigned char *buf, size_t len) {
|
||||
return serial_send(&pgm->fd, buf, len);
|
||||
}
|
||||
|
||||
static int stk500_recv(PROGRAMMER *pgm, unsigned char *buf, size_t len) {
|
||||
if(serial_recv(&pgm->fd, buf, len) < 0) {
|
||||
logprintf(LOG_ERR, "stk500_recv(): programmer is not responding");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int stk500_drain(PROGRAMMER *pgm, int display) {
|
||||
return serial_drain(&pgm->fd, display);
|
||||
}
|
||||
|
||||
int stk500_getsync(PROGRAMMER * pgm) {
|
||||
unsigned char buf[32], resp[32];
|
||||
int attempt = 0;
|
||||
|
||||
/*
|
||||
* get in sync */
|
||||
buf[0] = Cmnd_STK_GET_SYNC;
|
||||
buf[1] = Sync_CRC_EOP;
|
||||
|
||||
/*
|
||||
* First send and drain a few times to get rid of line noise
|
||||
*/
|
||||
stk500_send(pgm, buf, 2);
|
||||
stk500_drain(pgm, 0);
|
||||
stk500_send(pgm, buf, 2);
|
||||
stk500_drain(pgm, 0);
|
||||
|
||||
for(attempt = 0; attempt < MAX_SYNC_ATTEMPTS; attempt++) {
|
||||
stk500_send(pgm, buf, 2);
|
||||
stk500_recv(pgm, resp, 1);
|
||||
if(resp[0] == Resp_STK_INSYNC){
|
||||
break;
|
||||
}
|
||||
logprintf(LOG_ERR, "stk500_getsync() attempt %d of %d: not in sync: resp=0x%02x",
|
||||
attempt + 1, MAX_SYNC_ATTEMPTS, resp[0]);
|
||||
}
|
||||
if(attempt == MAX_SYNC_ATTEMPTS) {
|
||||
stk500_drain(pgm, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(stk500_recv(pgm, resp, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(resp[0] != Resp_STK_OK) {
|
||||
logprintf(LOG_ERR, "stk500_getsync(): can't communicate with device: resp=0x%02x", resp[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* transmit an AVR device command and return the results; 'cmd' and
|
||||
* 'res' must point to at least a 4 byte data buffer
|
||||
*/
|
||||
static int stk500_cmd(PROGRAMMER *pgm, const unsigned char *cmd, unsigned char *res) {
|
||||
unsigned char buf[32];
|
||||
|
||||
buf[0] = Cmnd_STK_UNIVERSAL;
|
||||
buf[1] = cmd[0];
|
||||
buf[2] = cmd[1];
|
||||
buf[3] = cmd[2];
|
||||
buf[4] = cmd[3];
|
||||
buf[5] = Sync_CRC_EOP;
|
||||
|
||||
stk500_send(pgm, buf, 6);
|
||||
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(buf[0] != Resp_STK_INSYNC) {
|
||||
logprintf(LOG_ERR, "stk500_cmd(): programmer is out of sync");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res[0] = cmd[1];
|
||||
res[1] = cmd[2];
|
||||
res[2] = cmd[3];
|
||||
if(stk500_recv(pgm, &res[3], 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(buf[0] != Resp_STK_OK) {
|
||||
logprintf(LOG_ERR, "stk500_cmd(): protocol error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* issue the 'chip erase' command to the AVR device
|
||||
*/
|
||||
static int stk500_chip_erase(PROGRAMMER *pgm, AVRPART *p) {
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
|
||||
if(pgm->cmd == NULL) {
|
||||
logprintf(LOG_ERR, "Error: %s programmer uses stk500_chip_erase() but does not provide a cmd() method.", pgm->type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(p->op[AVR_OP_CHIP_ERASE] == NULL) {
|
||||
logprintf(LOG_ERR, "chip erase instruction not defined for part \"%s\"", p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pgm->pgm_led(pgm, ON);
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
||||
avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
|
||||
pgm->cmd(pgm, cmd, res);
|
||||
usleep(p->chip_erase_delay);
|
||||
pgm->initialize(pgm, p);
|
||||
|
||||
pgm->pgm_led(pgm, OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* issue the 'program enable' command to the AVR device
|
||||
*/
|
||||
static int stk500_program_enable(PROGRAMMER *pgm, AVRPART *p) {
|
||||
unsigned char buf[16];
|
||||
int tries=0;
|
||||
|
||||
retry:
|
||||
|
||||
tries++;
|
||||
|
||||
buf[0] = Cmnd_STK_ENTER_PROGMODE;
|
||||
buf[1] = Sync_CRC_EOP;
|
||||
|
||||
stk500_send(pgm, buf, 2);
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(buf[0] == Resp_STK_NOSYNC) {
|
||||
if(tries > 33) {
|
||||
logprintf(LOG_ERR, "stk500_program_enable(): can't get into sync");
|
||||
return -1;
|
||||
}
|
||||
if(stk500_getsync(pgm) < 0) {
|
||||
return -1;
|
||||
}
|
||||
goto retry;
|
||||
} else if(buf[0] != Resp_STK_INSYNC) {
|
||||
logprintf(LOG_ERR, "%s: stk500_program_enable(): protocol error, expect=0x%02x, resp=0x%02x\n", Resp_STK_INSYNC, buf[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(stk500_recv(pgm, buf, 1) < 0)
|
||||
return -1;
|
||||
if(buf[0] == Resp_STK_OK) {
|
||||
return 0;
|
||||
} else if(buf[0] == Resp_STK_NODEVICE) {
|
||||
logprintf(LOG_ERR, "stk500_program_enable(): no device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(buf[0] == Resp_STK_FAILED) {
|
||||
logprintf(LOG_ERR, "stk500_program_enable(): failed to enter programming mode");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
logprintf(LOG_ERR, "stk500_program_enable(): unknown response=0x%02x", buf[0]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize the AVR device and prepare it to accept commands
|
||||
*/
|
||||
static int stk500_initialize(PROGRAMMER *pgm, AVRPART *p) {
|
||||
unsigned char buf[32];
|
||||
AVRMEM *m = NULL;
|
||||
int tries = 0;
|
||||
|
||||
tries = 0;
|
||||
|
||||
retry:
|
||||
tries++;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
/*
|
||||
* set device programming parameters
|
||||
*/
|
||||
buf[0] = Cmnd_STK_SET_DEVICE;
|
||||
buf[1] = p->stk500_devcode;
|
||||
buf[2] = 0; /* device revision */
|
||||
|
||||
if((p->flags & AVRPART_SERIALOK) && (p->flags & AVRPART_PARALLELOK)) {
|
||||
buf[3] = 0; /* device supports parallel and serial programming */
|
||||
} else {
|
||||
buf[3] = 1; /* device supports parallel only */
|
||||
}
|
||||
|
||||
if(p->flags & AVRPART_PARALLELOK) {
|
||||
if(p->flags & AVRPART_PSEUDOPARALLEL) {
|
||||
buf[4] = 0; /* pseudo parallel interface */
|
||||
} else {
|
||||
buf[4] = 1; /* full parallel interface */
|
||||
}
|
||||
}
|
||||
|
||||
buf[5] = 1; /* polling supported - XXX need this in config file */
|
||||
buf[6] = 1; /* programming is self-timed - XXX need in config file */
|
||||
buf[7] = 0;
|
||||
buf[8] = 0;
|
||||
buf[8] += p->lfusemem->size;
|
||||
buf[8] += p->hfusemem->size;
|
||||
|
||||
m = p->flashmem;
|
||||
if(m != NULL) {
|
||||
buf[9] = m->readback[0];
|
||||
buf[10] = m->readback[1];
|
||||
if(m->paged == 1) {
|
||||
buf[13] = (m->page_size >> 8) & 0x00ff;
|
||||
buf[14] = m->page_size & 0x00ff;
|
||||
}
|
||||
buf[17] = (m->size >> 24) & 0xff;
|
||||
buf[18] = (m->size >> 16) & 0xff;
|
||||
buf[19] = (m->size >> 8) & 0xff;
|
||||
buf[20] = m->size & 0xff;
|
||||
}
|
||||
|
||||
buf[11] = 0xff;
|
||||
buf[12] = 0xff;
|
||||
buf[15] = 0;
|
||||
buf[16] = 0;
|
||||
buf[21] = Sync_CRC_EOP;
|
||||
|
||||
stk500_send(pgm, buf, 22);
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(buf[0] == Resp_STK_NOSYNC) {
|
||||
logprintf(LOG_ERR, "stk500_initialize(): programmer not in sync, resp=0x%02x", buf[0]);
|
||||
if(tries > 33) {
|
||||
return -1;
|
||||
}
|
||||
if(stk500_getsync(pgm) < 0) {
|
||||
return -1;
|
||||
}
|
||||
goto retry;
|
||||
} else if(buf[0] != Resp_STK_INSYNC) {
|
||||
logprintf(LOG_ERR, "stk500_initialize(): (a) protocol error, expect=0x%02x, resp=0x%02x", Resp_STK_INSYNC, buf[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(buf[0] != Resp_STK_OK) {
|
||||
logprintf(LOG_ERR, "stk500_initialize(): (b) protocol error, expect=0x%02x, resp=0x%02x", Resp_STK_OK, buf[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pgm->program_enable(pgm, p);
|
||||
}
|
||||
|
||||
static int stk500_loadaddr(PROGRAMMER *pgm, AVRMEM *mem, unsigned int addr) {
|
||||
unsigned char buf[16];
|
||||
int tries = 0;
|
||||
unsigned char ext_byte;
|
||||
OPCODE * lext;
|
||||
|
||||
tries = 0;
|
||||
|
||||
retry:
|
||||
tries++;
|
||||
|
||||
/* To support flash > 64K words the correct Extended Address Byte is needed */
|
||||
lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
|
||||
if(lext != NULL) {
|
||||
ext_byte = (addr >> 16) & 0xff;
|
||||
if(ext_byte != PDATA(pgm)->ext_addr_byte) {
|
||||
/* Either this is the first addr load, or a 64K word boundary is
|
||||
* crossed, so set the ext addr byte */
|
||||
avr_set_bits(lext, buf);
|
||||
avr_set_addr(lext, buf, addr);
|
||||
stk500_cmd(pgm, buf, buf);
|
||||
PDATA(pgm)->ext_addr_byte = ext_byte;
|
||||
}
|
||||
}
|
||||
|
||||
buf[0] = Cmnd_STK_LOAD_ADDRESS;
|
||||
buf[1] = addr & 0xff;
|
||||
buf[2] = (addr >> 8) & 0xff;
|
||||
buf[3] = Sync_CRC_EOP;
|
||||
|
||||
stk500_send(pgm, buf, 4);
|
||||
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(buf[0] == Resp_STK_NOSYNC) {
|
||||
if(tries > 33) {
|
||||
logprintf(LOG_ERR, "stk500_loadaddr(): can't get into sync");
|
||||
return -1;
|
||||
}
|
||||
if(stk500_getsync(pgm) < 0) {
|
||||
return -1;
|
||||
}
|
||||
goto retry;
|
||||
} else if(buf[0] != Resp_STK_INSYNC) {
|
||||
logprintf(LOG_ERR, "stk500_loadaddr(): (a) protocol error, expect=0x%02x, resp=0x%02x", Resp_STK_INSYNC, buf[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(buf[0] == Resp_STK_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
logprintf(LOG_ERR, "loadaddr(): (b) protocol error, expect=0x%02x, resp=0x%02x", Resp_STK_INSYNC, buf[0]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int stk500_paged_write(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m,
|
||||
unsigned int page_size,
|
||||
unsigned int addr, unsigned int n_bytes) {
|
||||
|
||||
unsigned char buf[page_size + 16];
|
||||
int memtype = 0, a_div = 0, block_size = 0, tries = 0;
|
||||
unsigned int n = 0, i = 0;
|
||||
|
||||
if(strcmp(m->desc, "flash") == 0) {
|
||||
memtype = 'F';
|
||||
} else if(strcmp(m->desc, "eeprom") == 0) {
|
||||
memtype = 'E';
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if((m->op[AVR_OP_LOADPAGE_LO]) || (m->op[AVR_OP_READ_LO])) {
|
||||
a_div = 2;
|
||||
} else {
|
||||
a_div = 1;
|
||||
}
|
||||
|
||||
n = addr + n_bytes;
|
||||
|
||||
for(; addr < n; addr += block_size) {
|
||||
if(n - addr < page_size) {
|
||||
block_size = n - addr;
|
||||
} else {
|
||||
block_size = page_size;
|
||||
}
|
||||
tries = 0;
|
||||
retry:
|
||||
tries++;
|
||||
stk500_loadaddr(pgm, m, addr/a_div);
|
||||
|
||||
/* build command block and avoid multiple send commands as it leads to a crash
|
||||
of the silabs usb serial driver on mac os x */
|
||||
i = 0;
|
||||
buf[i++] = Cmnd_STK_PROG_PAGE;
|
||||
buf[i++] = (block_size >> 8) & 0xff;
|
||||
buf[i++] = block_size & 0xff;
|
||||
buf[i++] = memtype;
|
||||
|
||||
memcpy(&buf[i], &m->buf[addr], block_size);
|
||||
|
||||
i += block_size;
|
||||
buf[i++] = Sync_CRC_EOP;
|
||||
stk500_send(pgm, buf, i);
|
||||
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(buf[0] == Resp_STK_NOSYNC) {
|
||||
if(tries > 33) {
|
||||
logprintf(LOG_ERR, "stk500_paged_write(): can't get into sync", progname);
|
||||
return -3;
|
||||
}
|
||||
if(stk500_getsync(pgm) < 0) {
|
||||
return -1;
|
||||
}
|
||||
goto retry;
|
||||
} else if(buf[0] != Resp_STK_INSYNC) {
|
||||
logprintf(LOG_ERR, "stk500_paged_write(): (a) protocol error, expect=0x%02x, resp=0x%02x", Resp_STK_INSYNC, buf[0]);
|
||||
return -4;
|
||||
}
|
||||
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(buf[0] != Resp_STK_OK) {
|
||||
logprintf(LOG_ERR, "stk500_paged_write(): (a) protocol error, expect=0x%02x, resp=0x%02x", Resp_STK_INSYNC, buf[0]);
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
|
||||
return n_bytes;
|
||||
}
|
||||
|
||||
static int stk500_paged_load(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m,
|
||||
unsigned int page_size,
|
||||
unsigned int addr, unsigned int n_bytes) {
|
||||
unsigned char buf[16];
|
||||
int memtype = 0, a_div = 0, tries = 0, block_size = 0;
|
||||
unsigned int n = 0;
|
||||
|
||||
if(strcmp(m->desc, "flash") == 0) {
|
||||
memtype = 'F';
|
||||
} else if(strcmp(m->desc, "eeprom") == 0) {
|
||||
memtype = 'E';
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if((m->op[AVR_OP_LOADPAGE_LO]) || (m->op[AVR_OP_READ_LO])) {
|
||||
a_div = 2;
|
||||
} else {
|
||||
a_div = 1;
|
||||
}
|
||||
|
||||
n = addr + n_bytes;
|
||||
for(; addr < n; addr += block_size) {
|
||||
if(n - addr < page_size) {
|
||||
block_size = n - addr;
|
||||
} else {
|
||||
block_size = page_size;
|
||||
}
|
||||
|
||||
tries = 0;
|
||||
retry:
|
||||
tries++;
|
||||
stk500_loadaddr(pgm, m, addr/a_div);
|
||||
buf[0] = Cmnd_STK_READ_PAGE;
|
||||
buf[1] = (block_size >> 8) & 0xff;
|
||||
buf[2] = block_size & 0xff;
|
||||
buf[3] = memtype;
|
||||
buf[4] = Sync_CRC_EOP;
|
||||
stk500_send(pgm, buf, 5);
|
||||
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(buf[0] == Resp_STK_NOSYNC) {
|
||||
if(tries > 33) {
|
||||
logprintf(LOG_ERR, "stk500_paged_load(): can't get into sync");
|
||||
return -3;
|
||||
}
|
||||
if(stk500_getsync(pgm) < 0) {
|
||||
return -1;
|
||||
goto retry;
|
||||
}
|
||||
} else if(buf[0] != Resp_STK_INSYNC) {
|
||||
logprintf(LOG_ERR, "stk500_paged_load(): (a) protocol error, expect=0x%02x, resp=0x%02x", Resp_STK_INSYNC, buf[0]);
|
||||
return -4;
|
||||
}
|
||||
|
||||
if(stk500_recv(pgm, &m->buf[addr], block_size) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(buf[0] != Resp_STK_OK) {
|
||||
logprintf(LOG_ERR, "stk500_paged_load(): (a) protocol error, expect=0x%02x, resp=0x%02x", Resp_STK_OK, buf[0]);
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
|
||||
return n_bytes;
|
||||
}
|
||||
|
||||
|
||||
static void stk500_display(PROGRAMMER * pgm, const char * p) {
|
||||
}
|
||||
|
||||
static void stk500_disable(PROGRAMMER * pgm) {
|
||||
unsigned char buf[16];
|
||||
int tries=0;
|
||||
|
||||
retry:
|
||||
tries++;
|
||||
buf[0] = Cmnd_STK_LEAVE_PROGMODE;
|
||||
buf[1] = Sync_CRC_EOP;
|
||||
stk500_send(pgm, buf, 2);
|
||||
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return;
|
||||
}
|
||||
if(buf[0] == Resp_STK_NOSYNC) {
|
||||
if(tries > 33) {
|
||||
logprintf(LOG_ERR, "stk500_disable(): can't get into sync");
|
||||
return;
|
||||
}
|
||||
if(stk500_getsync(pgm) < 0) {
|
||||
return;
|
||||
}
|
||||
goto retry;
|
||||
} else if(buf[0] != Resp_STK_INSYNC) {
|
||||
logprintf(LOG_ERR, "stk500_disable(): protocol error, expect=0x%02x, resp=0x%02x", Resp_STK_INSYNC, buf[0]);
|
||||
return;
|
||||
}
|
||||
if(stk500_recv(pgm, buf, 1) < 0) {
|
||||
return;
|
||||
}
|
||||
if(buf[0] == Resp_STK_OK) {
|
||||
return;
|
||||
} else if(buf[0] == Resp_STK_NODEVICE) {
|
||||
logprintf(LOG_ERR, "stk500_disable(): no device");
|
||||
return;
|
||||
}
|
||||
logprintf(LOG_ERR, "stk500_disable(): unknown response=0x%02x", buf[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
static void stk500_enable(PROGRAMMER *pgm) {
|
||||
return;
|
||||
}
|
||||
|
||||
static void stk500_close(PROGRAMMER *pgm) {
|
||||
serial_close(&pgm->fd);
|
||||
pgm->fd.ifd = -1;
|
||||
}
|
||||
|
||||
const char stk500_desc[] = "Atmel STK500 Version 1.x firmware";
|
||||
|
||||
void stk500_initpgm(PROGRAMMER * pgm) {
|
||||
strcpy(pgm->type, "STK500");
|
||||
|
||||
/*
|
||||
* mandatory functions
|
||||
*/
|
||||
pgm->initialize = stk500_initialize;
|
||||
pgm->display = stk500_display;
|
||||
pgm->enable = stk500_enable;
|
||||
pgm->disable = stk500_disable;
|
||||
pgm->program_enable = stk500_program_enable;
|
||||
pgm->chip_erase = stk500_chip_erase;
|
||||
pgm->cmd = stk500_cmd;
|
||||
pgm->close = stk500_close;
|
||||
pgm->read_byte = avr_read_byte_default;
|
||||
pgm->write_byte = avr_write_byte_default;
|
||||
|
||||
/*
|
||||
* optional functions
|
||||
*/
|
||||
pgm->paged_write = stk500_paged_write;
|
||||
pgm->paged_load = stk500_paged_load;
|
||||
pgm->page_size = 256;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id: stk500.h 1294 2014-03-12 23:03:18Z joerg_wunsch $ */
|
||||
|
||||
#ifndef stk500_h
|
||||
#define stk500_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char stk500_desc[];
|
||||
void stk500_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
/* used by arduino.c to avoid duplicate code */
|
||||
int stk500_getsync(PROGRAMMER * pgm);
|
||||
int stk500_drain(PROGRAMMER * pgm, int display);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
//**** ATMEL AVR - A P P L I C A T I O N N O T E ************************
|
||||
//*
|
||||
//* Title: AVR061 - STK500 Communication Protocol
|
||||
//* Filename: command.h
|
||||
//* Version: 1.0
|
||||
//* Last updated: 09.09.2002
|
||||
//*
|
||||
//* Support E-mail: avr@atmel.com
|
||||
//*
|
||||
//**************************************************************************
|
||||
|
||||
// *****************[ STK Message constants ]***************************
|
||||
|
||||
#define STK_SIGN_ON_MESSAGE "AVR STK" // Sign on string for Cmnd_STK_GET_SIGN_ON
|
||||
|
||||
// *****************[ STK Response constants ]***************************
|
||||
|
||||
#define Resp_STK_OK 0x10 // ' '
|
||||
#define Resp_STK_FAILED 0x11 // ' '
|
||||
#define Resp_STK_UNKNOWN 0x12 // ' '
|
||||
#define Resp_STK_NODEVICE 0x13 // ' '
|
||||
#define Resp_STK_INSYNC 0x14 // ' '
|
||||
#define Resp_STK_NOSYNC 0x15 // ' '
|
||||
|
||||
#define Resp_ADC_CHANNEL_ERROR 0x16 // ' '
|
||||
#define Resp_ADC_MEASURE_OK 0x17 // ' '
|
||||
#define Resp_PWM_CHANNEL_ERROR 0x18 // ' '
|
||||
#define Resp_PWM_ADJUST_OK 0x19 // ' '
|
||||
|
||||
// *****************[ STK Special constants ]***************************
|
||||
|
||||
#define Sync_CRC_EOP 0x20 // 'SPACE'
|
||||
|
||||
// *****************[ STK Command constants ]***************************
|
||||
|
||||
#define Cmnd_STK_GET_SYNC 0x30 // ' '
|
||||
#define Cmnd_STK_GET_SIGN_ON 0x31 // ' '
|
||||
|
||||
#define Cmnd_STK_SET_PARAMETER 0x40 // ' '
|
||||
#define Cmnd_STK_GET_PARAMETER 0x41 // ' '
|
||||
#define Cmnd_STK_SET_DEVICE 0x42 // ' '
|
||||
#define Cmnd_STK_SET_DEVICE_EXT 0x45 // ' '
|
||||
|
||||
#define Cmnd_STK_ENTER_PROGMODE 0x50 // ' '
|
||||
#define Cmnd_STK_LEAVE_PROGMODE 0x51 // ' '
|
||||
#define Cmnd_STK_CHIP_ERASE 0x52 // ' '
|
||||
#define Cmnd_STK_CHECK_AUTOINC 0x53 // ' '
|
||||
#define Cmnd_STK_LOAD_ADDRESS 0x55 // ' '
|
||||
#define Cmnd_STK_UNIVERSAL 0x56 // ' '
|
||||
#define Cmnd_STK_UNIVERSAL_MULTI 0x57 // ' '
|
||||
|
||||
#define Cmnd_STK_PROG_FLASH 0x60 // ' '
|
||||
#define Cmnd_STK_PROG_DATA 0x61 // ' '
|
||||
#define Cmnd_STK_PROG_FUSE 0x62 // ' '
|
||||
#define Cmnd_STK_PROG_LOCK 0x63 // ' '
|
||||
#define Cmnd_STK_PROG_PAGE 0x64 // ' '
|
||||
#define Cmnd_STK_PROG_FUSE_EXT 0x65 // ' '
|
||||
|
||||
#define Cmnd_STK_READ_FLASH 0x70 // ' '
|
||||
#define Cmnd_STK_READ_DATA 0x71 // ' '
|
||||
#define Cmnd_STK_READ_FUSE 0x72 // ' '
|
||||
#define Cmnd_STK_READ_LOCK 0x73 // ' '
|
||||
#define Cmnd_STK_READ_PAGE 0x74 // ' '
|
||||
#define Cmnd_STK_READ_SIGN 0x75 // ' '
|
||||
#define Cmnd_STK_READ_OSCCAL 0x76 // ' '
|
||||
#define Cmnd_STK_READ_FUSE_EXT 0x77 // ' '
|
||||
#define Cmnd_STK_READ_OSCCAL_EXT 0x78 // ' '
|
||||
|
||||
// *****************[ STK Parameter constants ]***************************
|
||||
|
||||
#define Parm_STK_HW_VER 0x80 // ' ' - R
|
||||
#define Parm_STK_SW_MAJOR 0x81 // ' ' - R
|
||||
#define Parm_STK_SW_MINOR 0x82 // ' ' - R
|
||||
#define Parm_STK_LEDS 0x83 // ' ' - R/W
|
||||
#define Parm_STK_VTARGET 0x84 // ' ' - R/W
|
||||
#define Parm_STK_VADJUST 0x85 // ' ' - R/W
|
||||
#define Parm_STK_OSC_PSCALE 0x86 // ' ' - R/W
|
||||
#define Parm_STK_OSC_CMATCH 0x87 // ' ' - R/W
|
||||
#define Parm_STK_RESET_DURATION 0x88 // ' ' - R/W
|
||||
#define Parm_STK_SCK_DURATION 0x89 // ' ' - R/W
|
||||
|
||||
#define Parm_STK_BUFSIZEL 0x90 // ' ' - R/W, Range {0..255}
|
||||
#define Parm_STK_BUFSIZEH 0x91 // ' ' - R/W, Range {0..255}
|
||||
#define Parm_STK_DEVICE 0x92 // ' ' - R/W, Range {0..255}
|
||||
#define Parm_STK_PROGMODE 0x93 // ' ' - 'P' or 'S'
|
||||
#define Parm_STK_PARAMODE 0x94 // ' ' - TRUE or FALSE
|
||||
#define Parm_STK_POLLING 0x95 // ' ' - TRUE or FALSE
|
||||
#define Parm_STK_SELFTIMED 0x96 // ' ' - TRUE or FALSE
|
||||
#define Param_STK500_TOPCARD_DETECT 0x98 // ' ' - Detect top-card attached
|
||||
|
||||
// *****************[ STK status bit definitions ]***************************
|
||||
|
||||
#define Stat_STK_INSYNC 0x01 // INSYNC status bit, '1' - INSYNC
|
||||
#define Stat_STK_PROGMODE 0x02 // Programming mode, '1' - PROGMODE
|
||||
#define Stat_STK_STANDALONE 0x04 // Standalone mode, '1' - SM mode
|
||||
#define Stat_STK_RESET 0x08 // RESET button, '1' - Pushed
|
||||
#define Stat_STK_PROGRAM 0x10 // Program button, ' 1' - Pushed
|
||||
#define Stat_STK_LEDG 0x20 // Green LED status, '1' - Lit
|
||||
#define Stat_STK_LEDR 0x40 // Red LED status, '1' - Lit
|
||||
#define Stat_STK_LEDBLINK 0x80 // LED blink ON/OFF, '1' - Blink
|
||||
|
||||
|
||||
// *****************************[ End Of COMMAND.H ]**************************
|
||||
Reference in new issue
Block a user