update esppilight lib

content of the library is not filtered on 433mhz only
This commit is contained in:
Florian committed 2018-11-28 20:41:37 +01:00
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
+915
View File
@@ -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. */
}
+76
View File
@@ -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 */
+357
View File
@@ -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
+544
View File
@@ -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
+174
View File
@@ -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);
// }
+129
View File
@@ -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 */
+624
View File
@@ -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 ]**************************