xvc_client: block until full reply received, fixes errors on a slow network

ll_write() can request more than 1.5K of data, but recv() call will
return right away as soon as one packet is received. This causes large
transfers to break as not enough data is received.

Fixed by adding rx_exact flag and enabled it for ll_write()

Tested with Zynq7010 on a slow WiFi. Before the patch all uploads were
silently failing with no error in the log.

Signed-off-by: Vadzim Dambrouski <pftbest@gmail.com>
This commit is contained in:
Vadzim Dambrouski 2026-06-19 20:32:20 +02:00
parent 77db4dae64
commit 4af13b96ab
2 changed files with 27 additions and 4 deletions

View File

@ -261,9 +261,26 @@ int sendall(int sock, const void* raw, size_t cnt, int flags)
return cnt; // success
}
static
ssize_t recvall(int sock, void* raw, size_t cnt, int flags)
{
char *buf = (char*)raw;
size_t remaining = cnt;
while (remaining) {
ssize_t ret = recv(sock, buf, remaining, flags);
if (ret < 0)
return ret;
if (ret == 0) // peer closed the connection mid-reply
break;
buf += ret;
remaining -= ret;
}
return cnt - remaining;
}
ssize_t XVC_client::xfer_pkt(const std::string &instr,
const uint8_t *tx, uint32_t tx_size,
uint8_t *rx, uint32_t rx_size)
uint8_t *rx, uint32_t rx_size, bool rx_exact)
{
ssize_t len = tx_size;
std::vector<uint8_t> buffer(instr.size() + ((tx) ? tx_size : 0));
@ -277,9 +294,14 @@ ssize_t XVC_client::xfer_pkt(const std::string &instr,
}
if (rx) {
if (rx_exact) {
len = recvall(_sock, rx, rx_size, 0);
} else {
len = recv(_sock, rx, rx_size, 0);
}
if (len < 0) {
printError("Receive error");
return len;
} else if (len == 0) {
fprintf(stderr, "Client orderly shut down the connection.\n");
}
@ -312,7 +334,7 @@ bool XVC_client::ll_write(uint8_t *tdo)
memcpy(_xfer_buf + 4 + numbytes, _tditdo, numbytes);
if ((ret = xfer_pkt("shift:\0", _xfer_buf, (2 * numbytes) + 4,
_tditdo, numbytes)) < 0)
_tditdo, numbytes, true)) < 0)
return false;
_num_bits = 0; // clear counter

View File

@ -95,11 +95,12 @@ class XVC_client: public JtagInterface {
* \param[in] tx_size: tx size (in Byte)
* \param[in] rx: server answer buffer (may be NULL)
* \param[in] rx_size: rx size (in Byte) or (0 when unused)
* \param[in] rx_exact: block until exactly rx_size bytes received
* \return -1 when error, 0 when disconnected or tx_size/rx_size
*/
ssize_t xfer_pkt(const std::string &instr,
const uint8_t *tx, uint32_t tx_size,
uint8_t *rx, uint32_t rx_size);
uint8_t *rx, uint32_t rx_size, bool rx_exact = false);
/*!
* \brief lowlevel write: EMU_CMD_HW_JTAGx implementation