avrdude/src/xbee.c

1679 lines
50 KiB
C
Raw Permalink Normal View History

/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2015-2020 David Sainty
*
* 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$ */
/*
* avrdude interface for AVR devices Over-The-Air programmable via an
* XBee Series 2 device.
*
* The XBee programmer is STK500v1 (optiboot) encapsulated in the XBee
* API protocol. The bootloader supporting this protocol is available at:
*
* https://github.com/davidsainty/xbeeboot
*/
#include "ac_cfg.h"
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
#include <sys/time.h>
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "avrdude.h"
#include "libavrdude.h"
#include "stk500_private.h"
#include "stk500.h"
#include "xbee.h"
/*
* After eight seconds the AVR bootloader watchdog will kick in. But
* to allow for the possibility of eight seconds upstream and another
* eight seconds downstream, allow for 16 retries (of roughly one
* second each).
*/
#ifndef XBEE_MAX_RETRIES
#define XBEE_MAX_RETRIES 16
#endif
/*
* Maximum chunk size, which is the maximum encapsulated payload to be
* delivered to the remote CPU.
*
* There is an additional overhead of 3 bytes encapsulation, one
* "REQUEST" byte, one sequence number byte, and one
* "FIRMWARE_DELIVER" request type.
*
* The ZigBee maximum (unfragmented) payload is 84 bytes. Source
* routing decreases that by two bytes overhead, plus two bytes per
* hop. Maximum hop support is for 11 or 25 hops depending on
* firmware.
*
* Network layer encryption decreases the maximum payload by 18 bytes.
* APS end-to-end encryption decreases the maximum payload by 9 bytes.
* Both these layers are available in concert, as seen in the section
* "Network and APS layer encryption", decreasing our maximum payload
* by both 18 bytes and 9 bytes.
*
* Our maximum payload size should therefore ideally be 84 - 18 - 9 =
* 57 bytes, and therefore a chunk size of 54 bytes for zero hops.
*
* Source: XBee X2C manual: "Maximum RF payload size" section for most
* details; "Network layer encryption and decryption" section for the
* reference to 18 bytes of overhead; and "Enable APS encryption" for
* the reference to 9 bytes of overhead.
*/
#ifndef XBEEBOOT_MAX_CHUNK
#define XBEEBOOT_MAX_CHUNK 54
#endif
/*
* Maximum source route intermediate hops. This is described in the
* documentation variously as 40 hops (routing table); OR 25 hops
* (firmware 4x58 or later); OR 11 hops (firmware earlier than 4x58).
*
* What isn't described is how to know if a given source route length
* is actually supported by the mesh for our target device.
*/
#ifndef XBEE_MAX_INTERMEDIATE_HOPS
#define XBEE_MAX_INTERMEDIATE_HOPS 40
#endif
/* Protocol */
#define XBEEBOOT_PACKET_TYPE_ACK 0
#define XBEEBOOT_PACKET_TYPE_REQUEST 1
/*
* Read signature bytes - Direct copy of the Arduino behaviour to
* satisfy Optiboot.
*/
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
static int xbee_read_sig_bytes(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m) {
unsigned char buf[32];
/* Signature byte reads are always 3 bytes. */
if (m->size < 3) {
pmsg_error("memsize too small for sig byte read\n");
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) {
pmsg_error("programmer is out of sync\n");
return -1;
} else if (buf[0] != Resp_STK_INSYNC) {
msg_error("\n");
pmsg_error("protocol expects sync byte 0x%02x but got 0x%02x\n", Resp_STK_INSYNC, buf[0]);
return -2;
}
if (buf[4] != Resp_STK_OK) {
msg_error("\n");
pmsg_error("protocol expects OK byte 0x%02x but got 0x%02x\n", Resp_STK_OK, buf[4]);
return -3;
}
m->buf[0] = buf[1];
m->buf[1] = buf[2];
m->buf[2] = buf[3];
return 3;
}
struct XBeeSequenceStatistics {
struct timeval sendTime;
};
struct XBeeStaticticsSummary {
struct timeval minimum;
struct timeval maximum;
struct timeval sum;
unsigned long samples;
};
#define XBEE_STATS_GROUPS 4
#define XBEE_STATS_FRAME_LOCAL 0
#define XBEE_STATS_FRAME_REMOTE 1
#define XBEE_STATS_TRANSMIT 2
#define XBEE_STATS_RECEIVE 3
static const char* groupNames[] =
{
"FRAME_LOCAL",
"FRAME_REMOTE",
"TRANSMIT",
"RECEIVE"
};
struct XBeeBootSession {
struct serial_device *serialDevice;
union filedescriptor serialDescriptor;
unsigned char xbee_address[10];
int directMode;
unsigned char outSequence;
unsigned char inSequence;
/*
* XBee API frame sequence number.
*/
unsigned char txSequence;
/*
* Set to non-zero if the transport is broken to the point it is
* considered unusable.
*/
int transportUnusable;
int xbeeResetPin;
size_t inInIndex;
size_t inOutIndex;
unsigned char inBuffer[256];
int sourceRouteHops; /* -1 if unset */
int sourceRouteChanged;
/*
* The source route is an array of intermediate 16 bit addresses,
* starting with the address nearest to the target address, and
* finishing with the address closest to our local device.
*/
unsigned char sourceRoute[2 * XBEE_MAX_INTERMEDIATE_HOPS];
struct XBeeSequenceStatistics sequenceStatistics[256 * XBEE_STATS_GROUPS];
struct XBeeStaticticsSummary groupSummary[XBEE_STATS_GROUPS];
};
static void xbeeStatsReset(struct XBeeStaticticsSummary *summary)
{
summary->minimum.tv_sec = 0;
summary->minimum.tv_usec = 0;
summary->maximum.tv_sec = 0;
summary->maximum.tv_usec = 0;
summary->sum.tv_sec = 0;
summary->sum.tv_usec = 0;
summary->samples = 0;
}
static void xbeeStatsAdd(struct XBeeStaticticsSummary *summary,
struct timeval const *sample)
{
summary->sum.tv_usec += sample->tv_usec;
if (summary->sum.tv_usec > 1000000) {
summary->sum.tv_usec -= 1000000;
summary->sum.tv_sec++;
}
summary->sum.tv_sec += sample->tv_sec;
if (summary->samples == 0 ||
summary->minimum.tv_sec > sample->tv_sec ||
(summary->minimum.tv_sec == sample->tv_sec &&
summary->minimum.tv_usec > sample->tv_usec)) {
summary->minimum = *sample;
}
if (summary->maximum.tv_sec < sample->tv_sec ||
(summary->maximum.tv_sec == sample->tv_sec &&
summary->maximum.tv_usec < sample->tv_usec)) {
summary->maximum = *sample;
}
summary->samples++;
}
static void xbeeStatsSummarise(struct XBeeStaticticsSummary const *summary)
{
pmsg_notice(" Minimum response time: %lu.%06lu\n", summary->minimum.tv_sec, summary->minimum.tv_usec);
pmsg_notice(" Maximum response time: %lu.%06lu\n", summary->maximum.tv_sec, summary->maximum.tv_usec);
struct timeval average;
const unsigned long samples = summary->samples;
average.tv_sec = summary->sum.tv_sec / samples;
unsigned long long usecs = summary->sum.tv_usec;
usecs += (summary->sum.tv_sec % samples) * 1000000;
usecs = usecs / samples;
average.tv_sec += usecs / 1000000;
average.tv_usec = usecs % 1000000;
pmsg_notice(" Average response time: %lu.%06lu\n", average.tv_sec, average.tv_usec);
}
static void XBeeBootSessionInit(struct XBeeBootSession *xbs) {
xbs->serialDevice = &serial_serdev;
xbs->directMode = 1;
xbs->xbeeResetPin = XBEE_DEFAULT_RESET_PIN;
xbs->outSequence = 0;
xbs->inSequence = 0;
xbs->txSequence = 0;
xbs->transportUnusable = 0;
xbs->inInIndex = 0;
xbs->inOutIndex = 0;
xbs->sourceRouteHops = -1;
xbs->sourceRouteChanged = 0;
int group;
for (group = 0; group < 3; group++) {
int index;
for (index = 0; index < 256; index++)
xbs->sequenceStatistics[group * 256 + index].sendTime.tv_sec = (time_t)0;
xbeeStatsReset(&xbs->groupSummary[group]);
}
}
#define xbeebootsession(fdp) (struct XBeeBootSession*)((fdp)->pfd)
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
static void xbeedev_setresetpin(const union filedescriptor *fdp, int xbeeResetPin)
{
struct XBeeBootSession *xbs = xbeebootsession(fdp);
xbs->xbeeResetPin = xbeeResetPin;
}
enum xbee_stat_is_retry_enum {XBEE_STATS_NOT_RETRY, XBEE_STATS_IS_RETRY};
typedef enum xbee_stat_is_retry_enum xbee_stat_is_retry;
static void xbeedev_stats_send(struct XBeeBootSession *xbs,
char const *detail,
int detailSequence,
unsigned int group, unsigned char sequence,
xbee_stat_is_retry retry,
struct timeval const *sendTime)
{
struct XBeeSequenceStatistics *stats =
&xbs->sequenceStatistics[group * 256 + sequence];
if (retry == XBEE_STATS_NOT_RETRY)
stats->sendTime = *sendTime;
if (detailSequence >= 0) {
pmsg_notice2("stats: send Group %s Sequence %u : "
"Send %lu.%06lu %s Sequence %d\n",
groupNames[group],
(unsigned int) sequence,
(unsigned long) sendTime->tv_sec,
(unsigned long) sendTime->tv_usec,
detail, detailSequence);
} else {
pmsg_notice2("stats: send Group %s Sequence %u : "
"Send %lu.%06lu %s\n",
groupNames[group],
(unsigned int) sequence,
(unsigned long) sendTime->tv_sec,
(unsigned long) sendTime->tv_usec,
detail);
}
}
static void xbeedev_stats_receive(struct XBeeBootSession *xbs,
char const *detail,
unsigned int group, unsigned char sequence,
struct timeval const *receiveTime)
{
struct XBeeSequenceStatistics *stats =
&xbs->sequenceStatistics[group * 256 + sequence];
struct timeval delay;
time_t secs;
long usecs;
secs = receiveTime->tv_sec - stats->sendTime.tv_sec;
usecs = receiveTime->tv_usec - stats->sendTime.tv_usec;
if (usecs < 0) {
usecs += 1000000;
secs--;
}
delay.tv_sec = secs;
delay.tv_usec = usecs;
pmsg_notice2("stats: receive Group %s Sequence %u : "
"Send %lu.%06lu Receive %lu.%06lu Delay %lu.%06lu %s\n",
groupNames[group],
(unsigned int) sequence,
(unsigned long) stats->sendTime.tv_sec,
(unsigned long) stats->sendTime.tv_usec,
(unsigned long) receiveTime->tv_sec,
(unsigned long) receiveTime->tv_usec,
(unsigned long) secs,
(unsigned long) usecs,
detail);
xbeeStatsAdd(&xbs->groupSummary[group], &delay);
}
static int sendAPIRequest(struct XBeeBootSession *xbs,
unsigned char apiType,
int txSequence,
int apiOption,
int prePayload1,
int prePayload2,
int packetType,
int sequence,
int appType,
char const *detail,
int detailSequence,
unsigned int frameGroup,
xbee_stat_is_retry retry,
unsigned int dataLength,
const unsigned char *data)
{
unsigned char frame[256];
unsigned char *fp = &frame[5];
unsigned char *dataStart = fp;
unsigned char checksum = 0xff;
unsigned char length = 0;
struct timeval time;
gettimeofday(&time, NULL);
pmsg_notice2("sendAPIRequest(): %lu.%06lu %d, %d, %d, %d %s\n",
(unsigned long) time.tv_sec,
(unsigned long) time.tv_usec,
(int) packetType, (int)sequence, appType,
data == NULL ? -1 : (int)*data, detail);
#define fpput(x) \
do { \
const unsigned char v = (x); \
if (v == 0x7d || v == 0x7e || v == 0x11 || v == 0x13) { \
*fp++ = 0x7d; \
*fp++ = v ^ 0x20; \
} else { \
*fp++ = v; \
} \
checksum -= v; \
length++; \
} while (0)
fpput(apiType); /* ZigBee Receive Packet or ZigBee Transmit Request */
if (apiOption >= 0)
fpput(apiOption); /* Receive options (RX) */
if (txSequence >= 0) {
fpput(txSequence); /* Delivery sequence (TX/AT) */
/*
* Record the frame send time. Note that frame sequences are
* never retries.
*/
xbeedev_stats_send(xbs, detail, detailSequence,
frameGroup, txSequence, 0, &time);
}
if (apiType != 0x08) {
/* Automatically inhibit addressing for local AT command requests. */
size_t index;
for (index = 0; index < 10; index++) {
const unsigned char val = xbs->xbee_address[index];
fpput(val);
}
/*
* If this is an API call with remote address, but is not a Create
* Source Route request, consider prefixing it with source routing
* instructions.
*/
if (apiType != 0x21 && xbs->sourceRouteChanged) {
pmsg_notice2("sendAPIRequest(): issuing Create Source Route request with %d hops\n", xbs->sourceRouteHops);
int rc = sendAPIRequest(xbs, 0x21, /* Create Source Route */
0, -1, 0, xbs->sourceRouteHops,
-1, -1, -1,
"Create Source Route for FRAME_REMOTE",
txSequence,
XBEE_STATS_FRAME_LOCAL, /* Local, no response */
0, /* Not a retry */
xbs->sourceRouteHops * 2,
xbs->sourceRoute);
if (rc != 0)
return rc;
xbs->sourceRouteChanged = 0;
}
}
if (prePayload1 >= 0)
fpput(prePayload1); /* Transmit broadcast radius */
if (prePayload2 >= 0)
fpput(prePayload2); /* Transmit options */
if (packetType >= 0)
fpput(packetType); /* XBEEBOOT_PACKET_TYPE_{ACK,REQUEST} */
if (sequence >= 0) {
fpput(sequence);
/* Record the send time */
if (packetType == XBEEBOOT_PACKET_TYPE_REQUEST)
xbeedev_stats_send(xbs, detail, sequence, XBEE_STATS_TRANSMIT,
sequence, retry, &time);
}
if (appType >= 0)
fpput(appType); /* FIRMWARE_DELIVER */
{
size_t index;
for (index = 0; index < dataLength; index++)
fpput(data[index]);
}
/* Length BEFORE checksum byte */
const unsigned char unescapedLength = length;
fpput(checksum);
/* Length AFTER checksum byte */
const unsigned int finalLength = fp - dataStart;
frame[0] = 0x7e;
fp = &frame[1];
fpput(0);
fpput(unescapedLength);
const unsigned int prefixLength = fp - frame;
unsigned char *frameStart = dataStart - prefixLength;
memmove(frameStart, frame, prefixLength);
return xbs->serialDevice->send(&xbs->serialDescriptor,
frameStart, finalLength + prefixLength);
}
static int sendPacket(struct XBeeBootSession *xbs,
const char *detail,
unsigned char packetType,
unsigned char sequence,
xbee_stat_is_retry retry,
int appType,
unsigned int dataLength,
const unsigned char *data)
{
unsigned char apiType;
int prePayload1;
int prePayload2;
if (xbs->directMode) {
/*
* In direct mode we are pretending to be an XBee device
* forwarding on data received from the transmitting XBee. We
* therefore format the data as a remote XBee would, encapsulated
* in a 0x90 packet.
*/
apiType = 0x90; /* ZigBee Receive Packet */
prePayload1 = -1;
prePayload2 = -1;
} else {
/*
* In normal mode we are requesting a payload delivery,
* encapsulated in a 0x10 packet.
*/
apiType = 0x10; /* ZigBee Transmit Request */
prePayload1 = 0;
prePayload2 = 0;
}
while ((++xbs->txSequence & 0xff) == 0);
return sendAPIRequest(xbs, apiType, xbs->txSequence, -1,
prePayload1, prePayload2, packetType,
sequence, appType,
detail, sequence,
XBEE_STATS_FRAME_REMOTE, retry,
dataLength, data);
}
#define XBEE_LENGTH_LEN 2
#define XBEE_CHECKSUM_LEN 1
#define XBEE_APITYPE_LEN 1
#define XBEE_APISEQUENCE_LEN 1
#define XBEE_ADDRESS_64BIT_LEN 8
#define XBEE_ADDRESS_16BIT_LEN 2
#define XBEE_RADIUS_LEN 1
#define XBEE_TXOPTIONS_LEN 1
#define XBEE_RXOPTIONS_LEN 1
static void xbeedev_record16Bit(struct XBeeBootSession *xbs,
const unsigned char *rx16Bit)
{
/*
* We don't start out knowing what the 16-bit device address is, but
* we should receive it on the return packets, and re-use it from
* that point on.
*/
unsigned char * const tx16Bit =
&xbs->xbee_address[XBEE_ADDRESS_64BIT_LEN];
if (memcmp(rx16Bit, tx16Bit, XBEE_ADDRESS_16BIT_LEN) != 0) {
pmsg_notice2("xbeedev_record16Bit(): new 16-bit address: %02x%02x\n",
(unsigned int)rx16Bit[0],
(unsigned int)rx16Bit[1]);
memcpy(tx16Bit, rx16Bit, XBEE_ADDRESS_16BIT_LEN);
}
}
/*
* Return 0 on success.
* Return -1 on generic error (normally serial timeout).
* Return -512 + XBee AT Response code
*/
#define XBEE_AT_RETURN_CODE(x) (((x) >= -512 && (x) <= -256) ? (x) + 512 : -1)
static int xbeedev_poll(struct XBeeBootSession *xbs,
unsigned char **buf, size_t *buflen,
int waitForAck,
int waitForSequence)
{
for (;;) {
unsigned char byte;
unsigned char frame[256];
unsigned int frameSize;
before_frame:
do {
const int rc = xbs->serialDevice->recv(&xbs->serialDescriptor, &byte, 1);
if (rc < 0)
return rc;
} while (byte != 0x7e);
start_of_frame:
{
size_t index = 0;
int escaped = 0;
frameSize = XBEE_LENGTH_LEN;
do {
const int rc = xbs->serialDevice->recv(&xbs->serialDescriptor,
&byte, 1);
if (rc < 0)
return rc;
if (byte == 0x7e)
/*
* No matter when we receive a frame start byte, we should
* abort parsing and start a fresh frame.
*/
goto start_of_frame;
if (escaped) {
byte ^= 0x20;
escaped = 0;
} else if (byte == 0x7d) {
escaped = 1;
continue;
}
if (index >= sizeof(frame))
goto before_frame;
frame[index++] = byte;
if (index == XBEE_LENGTH_LEN) {
/* Length plus the two length bytes, plus the checksum byte */
frameSize = (frame[0] << 8 | frame[1]) +
XBEE_LENGTH_LEN + XBEE_CHECKSUM_LEN;
if (frameSize >= sizeof(frame))
/* Too long - immediately give up on this frame */
goto before_frame;
}
} while (index < frameSize);
/* End of frame */
unsigned char checksum = 1;
size_t cIndex;
for (cIndex = 2; cIndex < index; cIndex++) {
checksum += frame[cIndex];
}
if (checksum) {
/* Checksum didn't match */
pmsg_notice2("xbeedev_poll(): bad checksum %d\n", (int) checksum);
continue;
}
}
const unsigned char frameType = frame[2];
struct timeval receiveTime;
gettimeofday(&receiveTime, NULL);
pmsg_notice2("xbeedev_poll(): %lu.%06lu Received frame type %x\n",
(unsigned long) receiveTime.tv_sec,
(unsigned long) receiveTime.tv_usec,
(unsigned int) frameType);
if (frameType == 0x97 && frameSize > 16) {
/* Remote command response */
unsigned char txSequence = frame[3];
unsigned char resultCode = frame[16];
xbeedev_stats_receive(xbs, "Remote AT command response",
XBEE_STATS_FRAME_REMOTE, txSequence, &receiveTime);
pmsg_notice("xbeedev_poll(): remote command %d result code %d\n",
(int) txSequence, (int) resultCode);
if (waitForSequence >= 0 && waitForSequence == frame[3])
/* Received result for our sequence numbered request */
return -512 + resultCode;
} else if (frameType == 0x88 && frameSize > 6) {
/* Local command response */
unsigned char txSequence = frame[3];
xbeedev_stats_receive(xbs, "Local AT command response",
XBEE_STATS_FRAME_LOCAL, txSequence, &receiveTime);
pmsg_notice("xbeedev_poll(): local command %c%c result code %d\n",
frame[4], frame[5], (int)frame[6]);
if (waitForSequence >= 0 && waitForSequence == txSequence)
/* Received result for our sequence numbered request */
return 0;
} else if (frameType == 0x8b && frameSize > 7) {
/* Transmit status */
unsigned char txSequence = frame[3];
xbeedev_stats_receive(xbs, "Transmit status", XBEE_STATS_FRAME_REMOTE,
txSequence, &receiveTime);
pmsg_notice2("xbeedev_poll(): transmit status %d result code %d\n",
(int) frame[3], (int) frame[7]);
} else if (frameType == 0xa1 &&
frameSize >= XBEE_LENGTH_LEN + XBEE_APITYPE_LEN +
XBEE_ADDRESS_64BIT_LEN +
XBEE_ADDRESS_16BIT_LEN + 2 + XBEE_CHECKSUM_LEN) {
/* Route Record Indicator */
if (memcmp(&frame[XBEE_LENGTH_LEN + XBEE_APITYPE_LEN],
xbs->xbee_address, XBEE_ADDRESS_64BIT_LEN) != 0) {
/* Not from our target device */
pmsg_notice2("xbeedev_poll(): route Record Indicator from other XBee\n");
continue;
}
/*
* We don't start out knowing what the 16-bit device address is,
* but we should receive it on the return packets, and re-use it
* from that point on.
*/
{
const unsigned char *rx16Bit =
&frame[XBEE_LENGTH_LEN + XBEE_APITYPE_LEN +
XBEE_ADDRESS_64BIT_LEN];
xbeedev_record16Bit(xbs, rx16Bit);
}
const unsigned int header = XBEE_LENGTH_LEN + XBEE_APITYPE_LEN +
XBEE_ADDRESS_64BIT_LEN +
XBEE_ADDRESS_16BIT_LEN;
const unsigned char receiveOptions = frame[header];
const unsigned char hops = frame[header + 1];
pmsg_notice2("xbeedev_poll(): "
"Route Record Indicator from target XBee: "
"hops=%d options=%d\n", (int)hops, (int)receiveOptions);
if (frameSize < header + 2 + hops * 2 + XBEE_CHECKSUM_LEN)
/* Bounds check: Frame is too small */
continue;
const unsigned int tableOffset = header + 2;
unsigned char index;
for (index = 0; index < hops; index++) {
pmsg_notice2("xbeedev_poll(): "
"Route Intermediate Hop %d : %02x%02x\n", (int)index,
(int)frame[tableOffset + index * 2],
(int)frame[tableOffset + index * 2 + 1]);
}
if (hops <= XBEE_MAX_INTERMEDIATE_HOPS) {
if (xbs->sourceRouteHops != (int)hops ||
memcmp(&frame[tableOffset], xbs->sourceRoute, hops * 2) != 0) {
memcpy(xbs->sourceRoute, &frame[tableOffset], hops * 2);
xbs->sourceRouteHops = hops;
xbs->sourceRouteChanged = 1;
pmsg_notice2("xbeedev_poll(): route has changed\n");
}
}
} else if (frameType == 0x10 || frameType == 0x90) {
unsigned char *dataStart;
unsigned int dataLength;
if (frameType == 0x10) {
/* Direct mode frame */
const unsigned int header = XBEE_LENGTH_LEN +
XBEE_APITYPE_LEN + XBEE_APISEQUENCE_LEN +
XBEE_ADDRESS_64BIT_LEN + XBEE_ADDRESS_16BIT_LEN +
XBEE_RADIUS_LEN + XBEE_TXOPTIONS_LEN;
if (frameSize <= header + XBEE_CHECKSUM_LEN)
/* Bounds check: Frame is too small */
continue;
dataLength = frameSize - header - XBEE_CHECKSUM_LEN;
dataStart = &frame[header];
} else {
/* Remote reply frame */
const unsigned int header = XBEE_LENGTH_LEN +
XBEE_APITYPE_LEN + XBEE_ADDRESS_64BIT_LEN + XBEE_ADDRESS_16BIT_LEN +
XBEE_RXOPTIONS_LEN;
if (frameSize <= header + XBEE_CHECKSUM_LEN)
/* Bounds check: Frame is too small */
continue;
dataLength = frameSize - header - XBEE_CHECKSUM_LEN;
dataStart = &frame[header];
if (memcmp(&frame[XBEE_LENGTH_LEN + XBEE_APITYPE_LEN],
xbs->xbee_address, XBEE_ADDRESS_64BIT_LEN) != 0) {
/*
* This packet is not from our target device. Unlikely
* to ever happen, but if it does we have to ignore
* it.
*/
continue;
}
/*
* We don't start out knowing what the 16-bit device address
* is, but we should receive it on the return packets, and
* re-use it from that point on.
*/
{
const unsigned char *rx16Bit =
&frame[XBEE_LENGTH_LEN + XBEE_APITYPE_LEN +
XBEE_ADDRESS_64BIT_LEN];
xbeedev_record16Bit(xbs, rx16Bit);
}
}
if (dataLength >= 2) {
const unsigned char protocolType = dataStart[0];
const unsigned char sequence = dataStart[1];
pmsg_notice2("xbeedev_poll(): "
"%lu.%06lu Packet %d #%d\n", (unsigned long)receiveTime.tv_sec,
(unsigned long)receiveTime.tv_usec,
(int)protocolType, (int)sequence);
if (protocolType == XBEEBOOT_PACKET_TYPE_ACK) {
/* ACK */
xbeedev_stats_receive(xbs, "XBeeBoot ACK",
XBEE_STATS_TRANSMIT, sequence,
&receiveTime);
/*
* We can't update outSequence here, we already do that
* somewhere else.
*/
if (waitForAck >= 0 && waitForAck == sequence)
return 0;
} else if (protocolType == XBEEBOOT_PACKET_TYPE_REQUEST &&
dataLength >= 4 && dataStart[2] == 24) {
/* REQUEST FRAME_REPLY */
xbeedev_stats_receive(xbs, "XBeeBoot Receive", XBEE_STATS_RECEIVE,
sequence, &receiveTime);
unsigned char nextSequence = xbs->inSequence;
while ((++nextSequence & 0xff) == 0);
if (sequence == nextSequence) {
xbs->inSequence = nextSequence;
const size_t textLength = dataLength - 3;
size_t index;
for (index = 0; index < textLength; index++) {
const unsigned char data = dataStart[3 + index];
if (buflen != NULL && *buflen > 0) {
/* If we are receiving right now, and have a buffer ... */
*(*buf)++ = data;
(*buflen)--;
} else {
xbs->inBuffer[xbs->inInIndex++] = data;
if (xbs->inInIndex == sizeof(xbs->inBuffer))
xbs->inInIndex = 0;
if (xbs->inInIndex == xbs->inOutIndex) {
/* Should be impossible */
pmsg_error("buffer overrun\n");
xbs->transportUnusable = 1;
return -1;
}
}
}
/*msg_error("ACK %x\n", (unsigned int)sequence);*/
sendPacket(xbs, "Transmit Request ACK for RECEIVE",
XBEEBOOT_PACKET_TYPE_ACK, sequence,
XBEE_STATS_NOT_RETRY,
-1, 0, NULL);
if (buf != NULL && *buflen == 0)
/* Input buffer has been filled */
return 0;
/*
* Input buffer has NOT been filled, we are still in a
* receive. Not a retry, this is the first point we know
* for sure for this sequence number.
*/
while ((++nextSequence & 0xff) == 0);
xbeedev_stats_send(xbs, "poll() implies pending RECEIVE",
nextSequence,
XBEE_STATS_RECEIVE,
nextSequence, XBEE_STATS_NOT_RETRY,
&receiveTime);
}
}
}
}
}
}
/*
* @return
* 0 on success, a negative value on failure, or a positive
* value indicating the sequence number associated with the
* request.
*/
static int localAsyncAT(struct XBeeBootSession *xbs, char const *detail,
unsigned char at1, unsigned char at2, int value)
{
if (xbs->directMode)
/*
* Remote XBee AT commands make no sense in direct mode - there is
* no XBee device to communicate with.
*
* Return success, no sequence number.
*/
return 0;
while ((++xbs->txSequence & 0xff) == 0);
const unsigned char sequence = xbs->txSequence;
unsigned char buf[3];
size_t length = 0;
buf[length++] = at1;
buf[length++] = at2;
if (value >= 0)
buf[length++] = (unsigned char)value;
pmsg_notice("local AT command: %c%c\n", at1, at2);
/* Local AT command 0x08 */
int rc = sendAPIRequest(xbs, 0x08, sequence, -1, -1, -1, -1, -1, -1,
detail, -1, XBEE_STATS_FRAME_LOCAL,
XBEE_STATS_NOT_RETRY,
length, buf);
if (rc < 0)
/* Failed */
return rc;
/* Success, positive sequence number */
return (int)sequence;
}
static int localAT(struct XBeeBootSession *xbs, char const *detail,
unsigned char at1, unsigned char at2, int value)
{
int result = localAsyncAT(xbs, detail, at1, at2, value);
if (result <= 0)
/* Failure, or success without a sequence number */
return result;
unsigned char sequence = (unsigned char)result;
int retries;
for (retries = 0; retries < 5; retries++) {
const int rc = xbeedev_poll(xbs, NULL, NULL, -1, sequence);
if (rc == 0)
return 0;
}
return -1;
}
/*
* Return 0 on success.
* Return -1 on generic error (normally serial timeout).
* Return -512 + XBee AT Response code
*/
static int sendAT(struct XBeeBootSession *xbs, char const *detail,
unsigned char at1, unsigned char at2, int value)
{
if (xbs->directMode)
/*
* Remote XBee AT commands make no sense in direct mode - there is
* no XBee device to communicate with.
*/
return 0;
while ((++xbs->txSequence & 0xff) == 0);
const unsigned char sequence = xbs->txSequence;
unsigned char buf[3];
size_t length = 0;
buf[length++] = at1;
buf[length++] = at2;
if (value >= 0)
buf[length++] = (unsigned char)value;
pmsg_notice("remote AT command: %c%c\n", at1, at2);
/* Remote AT command 0x17 with Apply Changes 0x02 */
sendAPIRequest(xbs, 0x17, sequence, -1,
-1, -1, -1,
0x02, -1,
detail, -1, XBEE_STATS_FRAME_REMOTE,
XBEE_STATS_NOT_RETRY,
length, buf);
int retries;
for (retries = 0; retries < 30; retries++) {
const int rc = xbeedev_poll(xbs, NULL, NULL, -1, sequence);
const int xbeeRc = XBEE_AT_RETURN_CODE(rc);
if (xbeeRc == 0)
/* Translate to normal success code */
return 0;
if (rc != -1)
return rc;
}
return -1;
}
/*
* Return 0 on no error recognised, 1 if error was detected and reported
*/
static int xbeeATError(int rc) {
const int xbeeRc = XBEE_AT_RETURN_CODE(rc);
if (xbeeRc < 0)
return 0;
if (xbeeRc == 1) {
pmsg_error("unable to communicate with remote XBee\n");
} else if (xbeeRc == 2) {
pmsg_error("remote XBee: invalid command\n");
} else if (xbeeRc == 3) {
pmsg_error("remote XBee: invalid command parameter\n");
} else if (xbeeRc == 4) {
pmsg_error("remote XBee: transmission failure\n");
} else {
pmsg_error("unrecognised remote XBee error code %d\n", xbeeRc);
}
return 1;
}
static void xbeedev_free(struct XBeeBootSession *xbs)
{
xbs->serialDevice->close(&xbs->serialDescriptor);
free(xbs);
}
static void xbeedev_close(union filedescriptor *fdp)
{
struct XBeeBootSession *xbs = xbeebootsession(fdp);
xbeedev_free(xbs);
}
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
static int xbeedev_open(const char *port, union pinfo pinfo,
union filedescriptor *fdp)
{
/*
* The syntax for XBee devices is defined as:
*
* -P <XBeeAddress>@[serialdevice]
*
* ... or ...
*
* -P @[serialdevice]
*
* ... for a direct connection.
*/
char *ttySeparator = strchr(port, '@');
if (ttySeparator == NULL) {
pmsg_error("XBee: bad port syntax, require <xbee-address>@<serial-device>\n");
return -1;
}
struct XBeeBootSession *xbs = malloc(sizeof(struct XBeeBootSession));
if (xbs == NULL) {
pmsg_error("out of memory\n");
return -1;
}
XBeeBootSessionInit(xbs);
char *tty = &ttySeparator[1];
if (ttySeparator == port) {
/* Direct connection */
memset(xbs->xbee_address, 0, 8);
xbs->directMode = 1;
} else {
size_t addrIndex = 0;
int nybble = -1;
char const *address = port;
while (address != ttySeparator) {
char hex = *address++;
unsigned int val;
if (hex >= '0' && hex <= '9') {
val = hex - '0';
} else if (hex >= 'A' && hex <= 'F') {
val = hex - 'A' + 10;
} else if (hex >= 'a' && hex <= 'f') {
val = hex - 'a' + 10;
} else {
break;
}
if (nybble == -1) {
nybble = val;
} else {
xbs->xbee_address[addrIndex++] = (nybble * 16) | val;
nybble = -1;
if (addrIndex == 8)
break;
}
}
if (addrIndex != 8 || address != ttySeparator || nybble != -1) {
pmsg_error("XBee: bad XBee address, require 16-character hexadecimal address\n");
free(xbs);
return -1;
}
xbs->directMode = 0;
}
/* Unknown 16 bit address */
xbs->xbee_address[8] = 0xff;
xbs->xbee_address[9] = 0xfe;
pmsg_trace("XBee address: %02x%02x%02x%02x%02x%02x%02x%02x\n",
(unsigned int) xbs->xbee_address[0],
(unsigned int) xbs->xbee_address[1],
(unsigned int) xbs->xbee_address[2],
(unsigned int) xbs->xbee_address[3],
(unsigned int) xbs->xbee_address[4],
(unsigned int) xbs->xbee_address[5],
(unsigned int) xbs->xbee_address[6],
(unsigned int) xbs->xbee_address[7]);
if (pinfo.serialinfo.baud) {
/*
* User supplied the correct baud rate.
*/
} else if (xbs->directMode) {
/*
* In direct mode, default to 19200.
*
* Why?
*
* In this mode, we are NOT talking to an XBee, we are talking
* directly to an AVR device that thinks it is talking to an XBee
* itself.
*
* Because, an XBee is a 3.3V device defaulting to 9600baud, and
* the Atmel328P is only rated at a maximum clock rate of 8MHz
* with a 3.3V supply, so there's a high likelihood a remote
* Atmel328P will be clocked at 8MHz.
*
* With a direct connection, there's a good chance we're talking
* to an Arduino clocked at 16MHz with an XBee-enabled chip
* plugged in. The doubled clock rate means a doubled serial
* rate. Double 9600 baud == 19200 baud.
*/
pinfo.serialinfo.baud = 19200;
} else {
/*
* In normal mode, default to 9600.
*
* Why?
*
* XBee devices default to 9600 baud. In this mode we are talking
* to the XBee device, not the far-end device, so it's the local
* XBee baud rate we should select. The baud rate of the AVR
* device is irrelevant.
*/
pinfo.serialinfo.baud = 9600;
}
pinfo.serialinfo.cflags = SERIAL_8N1;
pmsg_notice("baud %ld\n", (long)pinfo.serialinfo.baud);
{
const int rc = xbs->serialDevice->open(tty, pinfo,
&xbs->serialDescriptor);
if (rc < 0) {
free(xbs);
return rc;
}
}
if (!xbs->directMode) {
/* Attempt to ensure the local XBee is in API mode 2 */
{
const int rc = localAT(xbs, "AT AP=2", 'A', 'P', 2);
if (rc < 0) {
pmsg_error("local XBee is not responding\n");
xbeedev_free(xbs);
return rc;
}
}
/*
* At this point we want to set the remote XBee parameters as
* required for talking to XBeeBoot. Ideally we would start with
* an "FR" full reset, but because that causes the XBee to
* disappear off the mesh for a significant period and become
* unresponsive, we don't do that.
*/
/*
* Issue an "Aggregate Routing Notification" to enable many-to-one
* routing to this device. This has two effects:
*
* - Establishes a route from the remote XBee attached to the CPU
* being programmed back to the local XBee.
*
* - Enables the 0xa1 Route frames so that we can make use of
* Source Routing to deliver packets directly to the remote
* XBee.
*
* Under "RF packet routing" subsection "Many-to-One routing", the
* XBee S2C manual states "Applications that require multiple data
* collectors can also use many-to-one routing. If more than one
* data collector device sends a many-to-one broadcast, devices
* create one reverse routing table entry for each collector."
*
* Under "RF packet routing" subsection "Source routing", the XBee
* S2C manual states "To use source routing, a device must use the
* API mode, and it must send periodic many-to-one route request
* broadcasts (AR command) to create a many-to-one route to it on
* all devices".
*/
{
const int rc = localAT(xbs, "AT AR=0", 'A', 'R', 0);
if (rc < 0) {
pmsg_error("local XBee is not responding\n");
xbeedev_free(xbs);
return rc;
}
}
/*
* Disable RTS input on the remote XBee, just in case it is
* enabled by default. XBeeBoot doesn't attempt to support flow
* control, and so it may not correctly drive this pin if RTS mode
* is the default configuration.
*
* XBee IO port 6 is the only pin that supports RTS mode, so there
* is no need to support any alternative pin.
*/
const int rc = sendAT(xbs, "AT D6=0", 'D', '6', 0);
if (rc < 0) {
xbeedev_free(xbs);
if (xbeeATError(rc))
return -1;
pmsg_error("remote XBee is not responding\n");
return rc;
}
}
fdp->pfd = xbs;
return 0;
}
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
static int xbeedev_send(const union filedescriptor *fdp,
const unsigned char *buf, size_t buflen)
{
struct XBeeBootSession *xbs = xbeebootsession(fdp);
if (xbs->transportUnusable)
/* Don't attempt to continue on an unusable transport layer */
return -1;
while (buflen > 0) {
unsigned char sequence = xbs->outSequence;
while ((++sequence & 0xff) == 0);
xbs->outSequence = sequence;
/*
* We are about to send some data, and that might lead potentially
* to received data before we see the ACK for this transmission.
* As this might be the trigger seen before the next "recv"
* operation, record that we have delivered this potential
* trigger.
*/
{
unsigned char nextSequence = xbs->inSequence;
while ((++nextSequence & 0xff) == 0);
struct timeval sendTime;
gettimeofday(&sendTime, NULL);
/*
* Optimistic records should never be treated as retries,
* because they might simply be guessing too optimistically.
*/
xbeedev_stats_send(xbs, "send() hints possible triggered RECEIVE",
nextSequence,
XBEE_STATS_RECEIVE,
nextSequence, 0, &sendTime);
}
/*
* Chunk the data into chunks of up to XBEEBOOT_MAX_CHUNK bytes.
*/
unsigned char maximum_chunk = XBEEBOOT_MAX_CHUNK;
/*
* Source routing incurs a two byte fixed overhead, plus a two
* byte additional cost per intermediate hop.
*
* We are attempting to avoid fragmentation here, so resize our
* maximum size to anticipate the overhead of the current number
* of hops. If our maximum chunk would be less than one, just
* give up and hope fragmentation will somehow save us.
*/
const int hops = xbs->sourceRouteHops;
if (hops > 0 && (hops * 2 + 2) < XBEEBOOT_MAX_CHUNK)
maximum_chunk -= hops * 2 + 2;
const unsigned char blockLength =
(buflen > maximum_chunk) ? maximum_chunk : buflen;
int pollRc = 0;
/* Repeatedly send whilst timing out waiting for ACK responses. */
int retries;
for (retries = 0; retries < XBEE_MAX_RETRIES; retries++) {
int sendRc =
sendPacket(xbs,
"Transmit Request Data, expect ACK for TRANSMIT",
XBEEBOOT_PACKET_TYPE_REQUEST, sequence,
retries > 0 ? XBEE_STATS_IS_RETRY : XBEE_STATS_NOT_RETRY,
23 /* FIRMWARE_DELIVER */,
blockLength, buf);
if (sendRc < 0) {
/* There is no way to recover from a failure mid-send */
xbs->transportUnusable = 1;
return sendRc;
}
pollRc = xbeedev_poll(xbs, NULL, NULL, sequence, -1);
if (pollRc == 0) {
/* Send was ACK'd */
buflen -= blockLength;
buf += blockLength;
break;
}
/*
* Test the connection to the local XBee by repeatedly
* requesting local configuration details. This functionally
* has no effect, but will allow us to measure any reliability
* issues on this link.
*/
localAsyncAT(xbs, "Local XBee ping [send]", 'A', 'P', -1);
/*
* If we don't receive an ACK it might be because the chip
* missed an ACK from us. Resend that too after a timeout,
* unless it's zero which is an illegal sequence number.
*/
if (xbs->inSequence != 0) {
int ackRc = sendPacket(xbs,
"Transmit Request ACK [Retry in send] "
"for RECEIVE",
XBEEBOOT_PACKET_TYPE_ACK,
xbs->inSequence,
XBEE_STATS_IS_RETRY,
-1, 0, NULL);
if (ackRc < 0) {
/* There is no way to recover from a failure mid-send */
xbs->transportUnusable = 1;
return ackRc;
}
}
}
if (pollRc < 0) {
/* There is no way to recover from a failure mid-send */
xbs->transportUnusable = 1;
return pollRc;
}
}
return 0;
}
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
static int xbeedev_recv(const union filedescriptor *fdp,
unsigned char *buf, size_t buflen)
{
struct XBeeBootSession *xbs = xbeebootsession(fdp);
/*
* First de-buffer anything previously received in a chunk that
* couldn't be immediately delievered.
*/
while (xbs->inInIndex != xbs->inOutIndex) {
*buf++ = xbs->inBuffer[xbs->inOutIndex++];
if (xbs->inOutIndex == sizeof(xbs->inBuffer))
xbs->inOutIndex = 0;
if (--buflen == 0)
return 0;
}
if (xbs->transportUnusable)
/* Don't attempt to continue on an unusable transport layer */
return -1;
/*
* When we expect to receive data, that is the time to start the
* clock.
*/
{
unsigned char nextSequence = xbs->inSequence;
while ((++nextSequence & 0xff) == 0);
struct timeval sendTime;
gettimeofday(&sendTime, NULL);
/*
* Not a retry - in fact this is the first stage we know for sure
* a RECEIVE is due.
*/
xbeedev_stats_send(xbs, "recv() implies pending RECEIVE",
nextSequence,
XBEE_STATS_RECEIVE,
nextSequence,
XBEE_STATS_NOT_RETRY,
&sendTime);
}
int retries;
for (retries = 0; retries < XBEE_MAX_RETRIES; retries++) {
const int rc = xbeedev_poll(xbs, &buf, &buflen, -1, -1);
if (rc == 0)
return 0;
if (xbs->transportUnusable)
/* Don't attempt to continue on an unusable transport layer */
return -1;
/*
* Test the connection to the local XBee by repeatedly
* requesting local configuration details. This functionally
* has no effect, but will allow us to measure any reliability
* issues on this link.
*/
localAsyncAT(xbs, "Local XBee ping [recv]", 'A', 'P', -1);
/*
* The chip may have missed an ACK from us. Resend after a
* timeout.
*/
if (xbs->inSequence != 0)
sendPacket(xbs, "Transmit Request ACK [Retry in recv] for RECEIVE",
XBEEBOOT_PACKET_TYPE_ACK, xbs->inSequence,
XBEE_STATS_IS_RETRY,
-1, 0, NULL);
}
return -1;
}
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
static int xbeedev_drain(const union filedescriptor *fdp, int display)
{
struct XBeeBootSession *xbs = xbeebootsession(fdp);
if (xbs->transportUnusable)
/* Don't attempt to continue on an unusable transport layer */
return -1;
/*
* Flushing the local serial buffer is unhelpful under this protocol
*/
do {
xbs->inOutIndex = xbs->inInIndex = 0;
} while (xbeedev_poll(xbs, NULL, NULL, -1, -1) == 0);
return 0;
}
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
static int xbeedev_set_dtr_rts(const union filedescriptor *fdp, int is_on)
{
struct XBeeBootSession *xbs = xbeebootsession(fdp);
if (xbs->directMode)
/* Correct for direct mode */
return xbs->serialDevice->set_dtr_rts(&xbs->serialDescriptor, is_on);
/*
* For non-direct mode (Over-The-Air) we need to issue XBee commands
* to the remote XBee in order to reset the AVR CPU and initiate the
* XBeeBoot bootloader.
*/
const int rc = sendAT(xbs, is_on ? "AT [DTR]=low" : "AT [DTR]=high",
'D', '0' + xbs->xbeeResetPin, is_on ? 5 : 4);
if (rc < 0) {
if (xbeeATError(rc))
return -1;
pmsg_error("remote XBee is not responding\n");
return rc;
}
return 0;
}
/*
* Device descriptor for XBee framing.
*/
static struct serial_device xbee_serdev_frame = {
.open = xbeedev_open,
.close = xbeedev_close,
.send = xbeedev_send,
.recv = xbeedev_recv,
.drain = xbeedev_drain,
.set_dtr_rts = xbeedev_set_dtr_rts,
.flags = SERDEV_FL_NONE,
};
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
static int xbee_getsync(const PROGRAMMER *pgm) {
unsigned char buf[2], resp[2];
/*
* Issue sync request as per STK500. Unlike stk500_getsync(), don't
* retry here - the underlying protocol will deal with retries for
* us in xbeedev_send() and should be reliable.
*/
buf[0] = Cmnd_STK_GET_SYNC;
buf[1] = Sync_CRC_EOP;
int sendRc = serial_send(&pgm->fd, buf, 2);
if (sendRc < 0) {
pmsg_error("unable to deliver STK_GET_SYNC to the remote XBeeBoot bootloader\n");
return sendRc;
}
/*
* The same is true of the receive - it will retry on timeouts until
* the response buffer is full.
*/
int recvRc = serial_recv(&pgm->fd, resp, 2);
if (recvRc < 0) {
pmsg_error("no response to STK_GET_SYNC from the remote XBeeBoot bootloader\n");
return recvRc;
}
if (resp[0] != Resp_STK_INSYNC) {
pmsg_error("not in sync, resp=0x%02x\n", (unsigned int) resp[0]);
return -1;
}
if (resp[1] != Resp_STK_OK) {
pmsg_error("in sync, not OK, resp=0x%02x\n", (unsigned int) resp[1]);
return -1;
}
return 0;
}
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
static int xbee_open(PROGRAMMER *pgm, const char *port) {
union pinfo pinfo;
strcpy(pgm->port, port);
pinfo.serialinfo.baud = pgm->baudrate;
pinfo.serialinfo.cflags = SERIAL_8N1;
/* Wireless is lossier than normal serial */
serial_recv_timeout = 1000;
serdev = &xbee_serdev_frame;
if (serial_open(port, pinfo, &pgm->fd) == -1) {
return -1;
}
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
xbeedev_setresetpin(&pgm->fd, PDATA(pgm)->xbeeResetPin);
/* Clear DTR and RTS */
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);
/*
* At this point stk500_drain() and stk500_getsync() calls would
* normally be made. But given that we have a transport layer over
* the serial command stream, the drain and repeated STK_GET_SYNC
* requests are not very helpful. Instead, skip the draining
* entirely, and issue the STK_GET_SYNC ourselves.
*/
if (xbee_getsync(pgm) < 0)
return -1;
return 0;
}
static void xbee_close(PROGRAMMER *pgm)
{
struct XBeeBootSession *xbs = xbeebootsession(&pgm->fd);
/*
* NB: This request is for the target device, not the locally
* connected serial device.
*/
serial_set_dtr_rts(&pgm->fd, 0);
/*
* We have tweaked a few settings on the XBee, including the RTS
* mode and the reset pin's configuration. Do a soft full reset,
* restoring the device to its normal power-on settings.
*
* Note that this DOES mean that the remote XBee will be
* uncontactable until it has restarted and re-established
* communications on the mesh.
*/
if (!xbs->directMode) {
const int rc = sendAT(xbs, "AT FR", 'F', 'R', -1);
xbeeATError(rc);
}
pmsg_notice("statistics for FRAME_LOCAL requests - %s->XBee(local)\n", progname);
xbeeStatsSummarise(&xbs->groupSummary[XBEE_STATS_FRAME_LOCAL]);
pmsg_notice("statistics for FRAME_REMOTE requests - %s->XBee(local)->XBee(target)\n", progname);
xbeeStatsSummarise(&xbs->groupSummary[XBEE_STATS_FRAME_REMOTE]);
pmsg_notice("statistics for TRANSMIT requests - %s->XBee(local)->XBee(target)->XBeeBoot\n", progname);
xbeeStatsSummarise(&xbs->groupSummary[XBEE_STATS_TRANSMIT]);
pmsg_notice("statistics for RECEIVE requests - XBeeBoot->XBee(target)->XBee(local)->%s\n", progname);
xbeeStatsSummarise(&xbs->groupSummary[XBEE_STATS_RECEIVE]);
xbeedev_free(xbs);
pgm->fd.pfd = NULL;
}
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
static int xbee_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
LNODEID ln;
const char *extended_param;
int rc = 0;
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
if (strncmp(extended_param,
"xbeeresetpin=", 13 /*strlen("xbeeresetpin=")*/) == 0) {
int resetpin;
if (sscanf(extended_param, "xbeeresetpin=%i", &resetpin) != 1 ||
resetpin <= 0 || resetpin > 7) {
pmsg_error("invalid xbeeresetpin '%s'\n", extended_param);
rc = -1;
continue;
}
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
PDATA(pgm)->xbeeResetPin = resetpin;
continue;
}
pmsg_error("invalid extended parameter '%s'\n", extended_param);
rc = -1;
}
return rc;
}
const char xbee_desc[] = "XBee Series 2 Over-The-Air (XBeeBoot)";
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
void xbee_initpgm(PROGRAMMER *pgm) {
/*
* This behaves like an Arduino, but with packet encapsulation of
* the serial streams, XBee device management, and XBee GPIO for the
Use const in PROGRAMMER function arguments where appropriate In order to get meaningful const properties for the PROGRAMMER, AVRPART and AVRMEM arguments, some code needed to be moved around, otherwise a network of "tainted" assignments risked rendering nothing const: - Change void (*enable)(PROGRAMMER *pgm) to void (*enable)(PROGRAMMER *pgm, const AVRPART *p); this allows changes in the PROGRAMMER structure after the part is known. For example, use TPI, UPDI, PDI functions in that programmer appropriate to the part. This used to be done later in the process, eg, in the initialize() function, which "taints" all other programmer functions wrt const and sometimes requires other finessing with flags etc. Much clearer with the modified enable() interface. - Move TPI initpgm-type code from initialize() to enable() --- note that initpgm() does not have the info at the time when it is called whether or not TPI is required - buspirate.c: move pgm->flag to PDATA(pgm)->flag (so legitimate modification of the flag does not change PROGRAMMER structure) - Move AVRPART_INIT_SMC and AVRPART_WRITE bits from the flags field in AVRPART to jtagmkII.c's private data flags32 fiels as FLAGS32_INIT_SMC and FLAGS32_WRITE bits - Move the xbeeResetPin component to private data in stk500.c as this is needed by xbee when it saddles on the stk500 code (previously, the flags component of the part was re-dedicated to this) - Change the way the "chained" private data are used in jtag3.c whilst keeping the PROGRAMMER structure read-only otherwise - In stk500v2.c move the STK600 pgm update from stk500v2_initialize() to stk500v2_enable() so the former keeps the PROGRAMMER structure read-only (for const assertion). - In usbasp change the code from changing PROGRAMMER functions late to dispatching to TPI or regular SPI protocol functions at runtime; reason being the decision whether to use TPI protocol is done at run-time depending on the capability of the attached programmer Also fixes Issue #1071, the treatment of default eecr value.
2022-08-17 15:05:28 +00:00
* Auto-Reset feature. stk500.c sets PDATA(pgm)->xbeeResetPin
*/
stk500_initpgm(pgm);
strncpy(pgm->type, "XBee", sizeof(pgm->type));
pgm->read_sig_bytes = xbee_read_sig_bytes;
pgm->open = xbee_open;
pgm->close = xbee_close;
pgm->parseextparams = xbee_parseextparms;
}