avrdude: ser_posix: Add timeout in ser_send(), refactoring
This commit is contained in:
parent
7a38d83d03
commit
a2ce4c00de
@ -44,7 +44,7 @@
|
|||||||
#include "avrdude.h"
|
#include "avrdude.h"
|
||||||
#include "libavrdude.h"
|
#include "libavrdude.h"
|
||||||
|
|
||||||
long serial_recv_timeout = 5000; /* ms */
|
long serial_recv_timeout = 4000; /* ms */
|
||||||
#define MAX_ZERO_READS 512
|
#define MAX_ZERO_READS 512
|
||||||
|
|
||||||
struct baud_mapping {
|
struct baud_mapping {
|
||||||
@ -150,6 +150,68 @@ static int ser_setspeed(union filedescriptor *fd, long baud)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Timeout read & write variants
|
||||||
|
// Additionally to the regular -1 on I/O error, they return -2 on timeout
|
||||||
|
ssize_t read_timeout(int fd, void *buf, size_t count, long timeout)
|
||||||
|
{
|
||||||
|
struct timeval tm, tm2;
|
||||||
|
fd_set rfds;
|
||||||
|
int nfds;
|
||||||
|
|
||||||
|
tm.tv_sec = timeout / 1000L;
|
||||||
|
tm.tv_usec = (timeout % 1000L) * 1000;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(fd, &rfds);
|
||||||
|
tm2 = tm;
|
||||||
|
nfds = select(fd + 1, &rfds, NULL, NULL, &tm2);
|
||||||
|
|
||||||
|
if (nfds == 0) {
|
||||||
|
return -2;
|
||||||
|
} else if (nfds == -1) {
|
||||||
|
if (errno == EINTR || errno == EAGAIN) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return read(fd, buf, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t write_timeout(int fd, const void *buf, size_t count, long timeout)
|
||||||
|
{
|
||||||
|
struct timeval tm, tm2;
|
||||||
|
fd_set wfds;
|
||||||
|
int nfds;
|
||||||
|
|
||||||
|
tm.tv_sec = timeout / 1000L;
|
||||||
|
tm.tv_usec = (timeout % 1000L) * 1000;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
FD_ZERO(&wfds);
|
||||||
|
FD_SET(fd, &wfds);
|
||||||
|
tm2 = tm;
|
||||||
|
nfds = select(fd + 1, NULL, &wfds, NULL, &tm2);
|
||||||
|
|
||||||
|
if (nfds == 0) {
|
||||||
|
return -2;
|
||||||
|
} else if (nfds == -1) {
|
||||||
|
if (errno == EINTR || errno == EAGAIN) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return write(fd, buf, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a port description of the form <host>:<port>, open a TCP
|
* Given a port description of the form <host>:<port>, open a TCP
|
||||||
* connection to the specified destination, which is assumed to be a
|
* connection to the specified destination, which is assumed to be a
|
||||||
@ -314,6 +376,7 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t
|
|||||||
int rc;
|
int rc;
|
||||||
const unsigned char * p = buf;
|
const unsigned char * p = buf;
|
||||||
size_t len = buflen;
|
size_t len = buflen;
|
||||||
|
unsigned zero_writes = 0;
|
||||||
|
|
||||||
if (!len)
|
if (!len)
|
||||||
return 0;
|
return 0;
|
||||||
@ -341,14 +404,25 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t
|
|||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
RETURN_IF_CANCEL();
|
RETURN_IF_CANCEL();
|
||||||
rc = write(fd->ifd, p, (len > 1024) ? 1024 : len);
|
rc = write_timeout(fd->ifd, p, (len > 1024) ? 1024 : len, serial_recv_timeout);
|
||||||
if (rc < 0) {
|
if (rc == -2) {
|
||||||
avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n",
|
avrdude_message(MSG_NOTICE2, "%s: ser_send(): programmer is not responding\n", progname);
|
||||||
progname, strerror(errno));
|
|
||||||
return -1;
|
return -1;
|
||||||
|
} else if (rc == -1) {
|
||||||
|
avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", progname, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
} else if (rc == 0) {
|
||||||
|
zero_writes++;
|
||||||
|
if (zero_writes > MAX_ZERO_READS) {
|
||||||
|
avrdude_message(MSG_NOTICE2, "%s: ser_send(): programmer is not responding (too many zero writes)\n",
|
||||||
|
progname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zero_writes = 0;
|
||||||
|
p += rc;
|
||||||
|
len -= rc;
|
||||||
}
|
}
|
||||||
p += rc;
|
|
||||||
len -= rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -357,51 +431,21 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t
|
|||||||
|
|
||||||
static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen)
|
static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen)
|
||||||
{
|
{
|
||||||
struct timeval timeout, to2;
|
|
||||||
fd_set rfds;
|
|
||||||
int nfds;
|
|
||||||
int rc;
|
int rc;
|
||||||
unsigned char * p = buf;
|
unsigned char * p = buf;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
unsigned zero_reads = 0;
|
unsigned zero_reads = 0;
|
||||||
|
|
||||||
timeout.tv_sec = serial_recv_timeout / 1000L;
|
|
||||||
timeout.tv_usec = (serial_recv_timeout % 1000L) * 1000;
|
|
||||||
to2 = timeout;
|
|
||||||
|
|
||||||
while (len < buflen) {
|
while (len < buflen) {
|
||||||
reselect:
|
|
||||||
RETURN_IF_CANCEL();
|
RETURN_IF_CANCEL();
|
||||||
FD_ZERO(&rfds);
|
|
||||||
FD_SET(fd->ifd, &rfds);
|
|
||||||
|
|
||||||
nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &to2);
|
rc = read_timeout(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len, serial_recv_timeout);
|
||||||
// FIXME: The timeout has different behaviour on Linux vs other Unices
|
|
||||||
// On Linux, the timeout is modified by subtracting the time spent,
|
if (rc == -2) {
|
||||||
// on OS X (for example), it is not modified.
|
avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n", progname);
|
||||||
// POSIX recommends re-initializing it before selecting.
|
|
||||||
if (nfds == 0) {
|
|
||||||
avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n",
|
|
||||||
progname);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else if (rc == -1) {
|
||||||
else if (nfds == -1) {
|
avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, strerror(errno));
|
||||||
if (errno == EINTR || errno == EAGAIN) {
|
|
||||||
avrdude_message(MSG_INFO, "%s: ser_recv(): programmer is not responding,reselecting\n",
|
|
||||||
progname);
|
|
||||||
goto reselect;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
avrdude_message(MSG_INFO, "%s: ser_recv(): select(): %s\n",
|
|
||||||
progname, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = read(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len);
|
|
||||||
if (rc < 0) {
|
|
||||||
avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n",
|
|
||||||
progname, strerror(errno));
|
|
||||||
return -1;
|
return -1;
|
||||||
} else if (rc == 0) {
|
} else if (rc == 0) {
|
||||||
zero_reads++;
|
zero_reads++;
|
||||||
@ -445,49 +489,26 @@ static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen
|
|||||||
|
|
||||||
static int ser_drain(union filedescriptor *fd, int display)
|
static int ser_drain(union filedescriptor *fd, int display)
|
||||||
{
|
{
|
||||||
struct timeval timeout;
|
|
||||||
fd_set rfds;
|
|
||||||
int nfds;
|
|
||||||
int rc;
|
int rc;
|
||||||
unsigned char buf;
|
unsigned char buf;
|
||||||
unsigned zero_reads = 0;
|
unsigned zero_reads = 0;
|
||||||
|
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = 250000;
|
|
||||||
|
|
||||||
if (display) {
|
if (display) {
|
||||||
avrdude_message(MSG_INFO, "drain>");
|
avrdude_message(MSG_INFO, "drain>");
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
FD_ZERO(&rfds);
|
|
||||||
FD_SET(fd->ifd, &rfds);
|
|
||||||
|
|
||||||
reselect:
|
|
||||||
RETURN_IF_CANCEL();
|
RETURN_IF_CANCEL();
|
||||||
nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &timeout);
|
|
||||||
if (nfds == 0) {
|
rc = read_timeout(fd->ifd, &buf, 1, 250); // Note: timeout needs to be kept low to not timeout in programmers
|
||||||
|
if (rc == -2) {
|
||||||
if (display) {
|
if (display) {
|
||||||
avrdude_message(MSG_INFO, "<drain\n");
|
avrdude_message(MSG_INFO, "<drain\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (nfds == -1) {
|
|
||||||
if (errno == EINTR) {
|
|
||||||
goto reselect;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
avrdude_message(MSG_INFO, "%s: ser_drain(): select(): %s\n",
|
|
||||||
progname, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = read(fd->ifd, &buf, 1);
|
break;
|
||||||
if (rc < 0) {
|
} else if (rc == -1) {
|
||||||
avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n",
|
avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", progname, strerror(errno));
|
||||||
progname, strerror(errno));
|
|
||||||
return -1;
|
return -1;
|
||||||
} else if (rc == 0) {
|
} else if (rc == 0) {
|
||||||
zero_reads++;
|
zero_reads++;
|
||||||
|
@ -722,7 +722,7 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) :
|
|||||||
panel->SetSizer(vsizer);
|
panel->SetSizer(vsizer);
|
||||||
|
|
||||||
auto *label_hex_picker = new wxStaticText(panel, wxID_ANY, _(L("Firmware image:")));
|
auto *label_hex_picker = new wxStaticText(panel, wxID_ANY, _(L("Firmware image:")));
|
||||||
p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY, wxEmptyString, wxFileSelectorPromptStr,
|
p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY, wxEmptyString, wxFileSelectorPromptStr,
|
||||||
"Hex files (*.hex)|*.hex|All files|*.*");
|
"Hex files (*.hex)|*.hex|All files|*.*");
|
||||||
|
|
||||||
auto *label_port_picker = new wxStaticText(panel, wxID_ANY, _(L("Serial port:")));
|
auto *label_port_picker = new wxStaticText(panel, wxID_ANY, _(L("Serial port:")));
|
||||||
|
Loading…
Reference in New Issue
Block a user