]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/ipdbg-la/protocol.c
scpi-pps: don't break SCPI devices when scanning for HP-IB devices
[libsigrok.git] / src / hardware / ipdbg-la / protocol.c
index 69c461ff6fa06d5f6995ef2f89b13cc135c324e7..b125f1efc8502aec362ed20be82393398c6e3bb9 100644 (file)
 #define _WIN32_WINNT 0x0501
 #include <winsock2.h>
 #include <ws2tcpip.h>
-#endif
-
-#include <string.h>
-#include <unistd.h>
-
-#ifndef _WIN32
+#else
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <sys/ioctl.h>
 #endif
-
+#include <string.h>
+#include <unistd.h>
 #include <errno.h>
 #include "protocol.h"
 
-#include <sys/ioctl.h>
-
 #define BUFFER_SIZE 4
 
 /* Top-level command opcodes */
 /* LA subfunction command opcodes */
 #define CMD_LA_DELAY               0x1F
 
-SR_PRIV gboolean data_available(struct ipdbg_la_tcp *tcp)
+static gboolean data_available(struct ipdbg_la_tcp *tcp)
 {
-#ifdef __WIN32__
-       ioctlsocket(tcp->socket, FIONREAD, &bytes_available);
+#ifdef _WIN32
+       u_long bytes_available;
+       if (ioctlsocket(tcp->socket, FIONREAD, &bytes_available) != 0) {
 #else
-       int status;
-
-       if (ioctl(tcp->socket, FIONREAD, &status) < 0) {        // TIOCMGET
+       int bytes_available;
+       if (ioctl(tcp->socket, FIONREAD, &bytes_available) < 0) { /* TIOCMGET */
+#endif
                sr_err("FIONREAD failed: %s\n", g_strerror(errno));
                return FALSE;
        }
-
-       return (status < 1) ? FALSE : TRUE;
-#endif  // __WIN32__
+       return (bytes_available > 0);
 }
 
 SR_PRIV struct ipdbg_la_tcp *ipdbg_la_tcp_new(void)
@@ -148,6 +142,14 @@ SR_PRIV int ipdbg_la_tcp_close(struct ipdbg_la_tcp *tcp)
 {
        int ret = SR_OK;
 
+#ifdef _WIN32
+       if (shutdown(tcp->socket, SD_SEND) != SOCKET_ERROR) {
+               char recvbuf[16];
+               int recvbuflen = 16;
+               /* Receive until the peer closes the connection. */
+               while (recv(tcp->socket, recvbuf, recvbuflen, 0) > 0);
+       }
+#endif
        if (close(tcp->socket) < 0)
                ret = SR_ERR;
 
@@ -156,11 +158,10 @@ SR_PRIV int ipdbg_la_tcp_close(struct ipdbg_la_tcp *tcp)
        return ret;
 }
 
-SR_PRIV int ipdbg_la_tcp_send(struct ipdbg_la_tcp *tcp,
-       const uint8_t *buf, size_t len)
+static int tcp_send(struct ipdbg_la_tcp *tcp, const uint8_t *buf, size_t len)
 {
        int out;
-       out = send(tcp->socket, (char*)buf, len, 0);
+       out = send(tcp->socket, (const char *)buf, len, 0);
 
        if (out < 0) {
                sr_err("Send error: %s", g_strerror(errno));
@@ -173,20 +174,22 @@ SR_PRIV int ipdbg_la_tcp_send(struct ipdbg_la_tcp *tcp,
        return SR_OK;
 }
 
-SR_PRIV int ipdbg_la_tcp_receive_blocking(struct ipdbg_la_tcp *tcp,
+static int tcp_receive_blocking(struct ipdbg_la_tcp *tcp,
        uint8_t *buf, int bufsize)
 {
        int received = 0;
        int error_count = 0;
 
-       /* Timeout after 500ms of not receiving data */
-       while ((received < bufsize) && (error_count < 500)) {
-               if (ipdbg_la_tcp_receive(tcp, buf) > 0) {
-                       buf++;
-                       received++;
+       /* Timeout after 2s of not receiving data. */
+       /* Increase timeout in case lab is not just beside the office. */
+       while ((received < bufsize) && (error_count < 2000)) {
+               int recd = ipdbg_la_tcp_receive(tcp, buf, bufsize - received);
+               if (recd > 0) {
+                       buf += recd;
+                       received += recd;
                } else {
                        error_count++;
-                       g_usleep(1000);  /* Sleep for 1ms */
+                       g_usleep(1000);
                }
        }
 
@@ -194,24 +197,16 @@ SR_PRIV int ipdbg_la_tcp_receive_blocking(struct ipdbg_la_tcp *tcp,
 }
 
 SR_PRIV int ipdbg_la_tcp_receive(struct ipdbg_la_tcp *tcp,
-       uint8_t *buf)
+       uint8_t *buf, size_t bufsize)
 {
        int received = 0;
-
-       if (data_available(tcp)) {
-               while (received < 1) {
-                       int len = recv(tcp->socket, buf, 1, 0);
-
-                       if (len < 0) {
-                               sr_err("Receive error: %s", g_strerror(errno));
-                               return SR_ERR;
-                       } else
-                               received += len;
-               }
-
-               return received;
-       } else
+       if (data_available(tcp))
+               received = recv(tcp->socket, (char *)buf, bufsize, 0);
+       if (received < 0) {
+               sr_err("Receive error: %s", g_strerror(errno));
                return -1;
+       } else
+               return received;
 }
 
 SR_PRIV int ipdbg_la_convert_trigger(const struct sr_dev_inst *sdi)
@@ -228,7 +223,7 @@ SR_PRIV int ipdbg_la_convert_trigger(const struct sr_dev_inst *sdi)
        devc->num_transfers = 0;
        devc->raw_sample_buf = NULL;
 
-       for (uint64_t i = 0; i < devc->DATA_WIDTH_BYTES; i++) {
+       for (uint64_t i = 0; i < devc->data_width_bytes; i++) {
                devc->trigger_mask[i] = 0;
                devc->trigger_value[i] = 0;
                devc->trigger_mask_last[i] = 0;
@@ -292,7 +287,7 @@ SR_PRIV int ipdbg_la_receive_data(int fd, int revents, void *cb_data)
        (void)fd;
        (void)revents;
 
-       sdi = (const struct sr_dev_inst *)cb_data;
+       sdi = cb_data;
        if (!sdi)
                return FALSE;
 
@@ -305,7 +300,7 @@ SR_PRIV int ipdbg_la_receive_data(int fd, int revents, void *cb_data)
 
        if (!devc->raw_sample_buf) {
                devc->raw_sample_buf =
-                       g_try_malloc(devc->limit_samples * devc->DATA_WIDTH_BYTES);
+                       g_try_malloc(devc->limit_samples * devc->data_width_bytes);
                if (!devc->raw_sample_buf) {
                        sr_err("Sample buffer malloc failed.");
                        return FALSE;
@@ -313,39 +308,46 @@ SR_PRIV int ipdbg_la_receive_data(int fd, int revents, void *cb_data)
        }
 
        if (devc->num_transfers <
-               (devc->limit_samples_max * devc->DATA_WIDTH_BYTES)) {
-               uint8_t byte;
-
-               if (ipdbg_la_tcp_receive(tcp, &byte) == 1) {
-                       if (devc->num_transfers <
-                               (devc->limit_samples * devc->DATA_WIDTH_BYTES))
-                               devc->raw_sample_buf[devc->num_transfers] = byte;
-
-                       devc->num_transfers++;
+               (devc->limit_samples_max * devc->data_width_bytes)) {
+               const size_t bufsize = 1024;
+               uint8_t buffer[bufsize];
+
+               const int recd = ipdbg_la_tcp_receive(tcp, buffer, bufsize);
+               if ( recd > 0) {
+                       int num_move = (((devc->num_transfers + recd) <=
+                                                        (devc->limit_samples * devc->data_width_bytes))
+                       ?
+                               recd
+                       :
+                               (int)((devc->limit_samples * devc->data_width_bytes) -
+                                               devc->num_transfers));
+                       if ( num_move > 0 )
+                               memcpy(&(devc->raw_sample_buf[devc->num_transfers]),
+                                               buffer, num_move);
+                       devc->num_transfers += recd;
                }
        } else {
                if (devc->delay_value > 0) {
                        /* There are pre-trigger samples, send those first. */
                        packet.type = SR_DF_LOGIC;
                        packet.payload = &logic;
-                       logic.length = devc->delay_value * devc->DATA_WIDTH_BYTES;
-                       logic.unitsize = devc->DATA_WIDTH_BYTES;
+                       logic.length = devc->delay_value * devc->data_width_bytes;
+                       logic.unitsize = devc->data_width_bytes;
                        logic.data = devc->raw_sample_buf;
                        sr_session_send(cb_data, &packet);
                }
 
                /* Send the trigger. */
-               packet.type = SR_DF_TRIGGER;
-               sr_session_send(cb_data, &packet);
+               std_session_send_df_trigger(cb_data);
 
                /* Send post-trigger samples. */
                packet.type = SR_DF_LOGIC;
                packet.payload = &logic;
                logic.length = (devc->limit_samples - devc->delay_value) *
-                       devc->DATA_WIDTH_BYTES;
-               logic.unitsize = devc->DATA_WIDTH_BYTES;
+                       devc->data_width_bytes;
+               logic.unitsize = devc->data_width_bytes;
                logic.data = devc->raw_sample_buf +
-                       (devc->delay_value * devc->DATA_WIDTH_BYTES);
+                       (devc->delay_value * devc->data_width_bytes);
                sr_session_send(cb_data, &packet);
 
                g_free(devc->raw_sample_buf);
@@ -357,16 +359,39 @@ SR_PRIV int ipdbg_la_receive_data(int fd, int revents, void *cb_data)
        return TRUE;
 }
 
+static int send_escaping(struct ipdbg_la_tcp *tcp, uint8_t *data_to_send,
+       uint32_t length)
+{
+       uint8_t escape = CMD_ESCAPE;
+
+       while (length--) {
+               uint8_t payload = *data_to_send++;
+
+               if (payload == CMD_RESET)
+                       if (tcp_send(tcp, &escape, 1) != SR_OK)
+                               sr_warn("Couldn't send escape");
+
+               if (payload == CMD_ESCAPE)
+                       if (tcp_send(tcp, &escape, 1) != SR_OK)
+                               sr_warn("Couldn't send escape");
+
+               if (tcp_send(tcp, &payload, 1) != SR_OK)
+                       sr_warn("Couldn't send data");
+       }
+
+       return SR_OK;
+}
+
 SR_PRIV int ipdbg_la_send_delay(struct dev_context *devc,
        struct ipdbg_la_tcp *tcp)
 {
-       devc->delay_value = (devc->limit_samples / 100.0) * devc->capture_ratio;
+       devc->delay_value = ((devc->limit_samples - 1) / 100.0) * devc->capture_ratio;
 
        uint8_t buf;
        buf = CMD_CFG_LA;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
        buf = CMD_LA_DELAY;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
 
        uint8_t delay_buf[4] = { devc->delay_value & 0x000000ff,
                (devc->delay_value >> 8) & 0x000000ff,
@@ -374,8 +399,8 @@ SR_PRIV int ipdbg_la_send_delay(struct dev_context *devc,
                (devc->delay_value >> 24) & 0x000000ff
        };
 
-       for (uint64_t i = 0; i < devc->ADDR_WIDTH_BYTES; i++)
-               send_escaping(tcp, &(delay_buf[devc->ADDR_WIDTH_BYTES - 1 - i]), 1);
+       for (uint64_t i = 0; i < devc->addr_width_bytes; i++)
+               send_escaping(tcp, &(delay_buf[devc->addr_width_bytes - 1 - i]), 1);
 
        return SR_OK;
 }
@@ -387,86 +412,63 @@ SR_PRIV int ipdbg_la_send_trigger(struct dev_context *devc,
 
        /* Mask */
        buf = CMD_CFG_TRIGGER;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
        buf = CMD_TRIG_MASKS;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
        buf = CMD_TRIG_MASK;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
 
-       for (size_t i = 0; i < devc->DATA_WIDTH_BYTES; i++)
+       for (size_t i = 0; i < devc->data_width_bytes; i++)
                send_escaping(tcp,
-                       devc->trigger_mask + devc->DATA_WIDTH_BYTES - 1 - i, 1);
+                       devc->trigger_mask + devc->data_width_bytes - 1 - i, 1);
 
        /* Value */
        buf = CMD_CFG_TRIGGER;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
        buf = CMD_TRIG_MASKS;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
        buf = CMD_TRIG_VALUE;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
 
-       for (size_t i = 0; i < devc->DATA_WIDTH_BYTES; i++)
+       for (size_t i = 0; i < devc->data_width_bytes; i++)
                send_escaping(tcp,
-                       devc->trigger_value + devc->DATA_WIDTH_BYTES - 1 - i, 1);
+                       devc->trigger_value + devc->data_width_bytes - 1 - i, 1);
 
        /* Mask_last */
        buf = CMD_CFG_TRIGGER;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
        buf = CMD_TRIG_MASKS_LAST;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
        buf = CMD_TRIG_MASK_LAST;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
 
-       for (size_t i = 0; i < devc->DATA_WIDTH_BYTES; i++)
+       for (size_t i = 0; i < devc->data_width_bytes; i++)
                send_escaping(tcp,
-                       devc->trigger_mask_last + devc->DATA_WIDTH_BYTES - 1 - i, 1);
+                       devc->trigger_mask_last + devc->data_width_bytes - 1 - i, 1);
 
        /* Value_last */
        buf = CMD_CFG_TRIGGER;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
        buf = CMD_TRIG_MASKS_LAST;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
        buf = CMD_TRIG_VALUE_LAST;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
 
-       for (size_t i = 0; i < devc->DATA_WIDTH_BYTES; i++)
+       for (size_t i = 0; i < devc->data_width_bytes; i++)
                send_escaping(tcp,
-                       devc->trigger_value_last + devc->DATA_WIDTH_BYTES - 1 - i, 1);
+                       devc->trigger_value_last + devc->data_width_bytes - 1 - i, 1);
 
        /* Edge_mask */
        buf = CMD_CFG_TRIGGER;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
        buf = CMD_TRIG_SELECT_EDGE_MASK;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
        buf = CMD_TRIG_SET_EDGE_MASK;
-       ipdbg_la_tcp_send(tcp, &buf, 1);
+       tcp_send(tcp, &buf, 1);
 
-       for (size_t i = 0; i < devc->DATA_WIDTH_BYTES; i++)
+       for (size_t i = 0; i < devc->data_width_bytes; i++)
                send_escaping(tcp,
-                       devc->trigger_edge_mask + devc->DATA_WIDTH_BYTES - 1 - i, 1);
-
-       return SR_OK;
-}
-
-SR_PRIV int send_escaping(struct ipdbg_la_tcp *tcp, uint8_t *dataToSend,
-       uint32_t length)
-{
-       uint8_t escape = CMD_ESCAPE;
-
-       while (length--) {
-               uint8_t payload = *dataToSend++;
-
-               if (payload == (uint8_t) CMD_RESET)
-                       if (ipdbg_la_tcp_send(tcp, &escape, 1) != SR_OK)
-                               sr_warn("Couldn't send escape");
-
-               if (payload == (uint8_t) CMD_ESCAPE)
-                       if (ipdbg_la_tcp_send(tcp, &escape, 1) != SR_OK)
-                               sr_warn("Couldn't send escape");
-
-               if (ipdbg_la_tcp_send(tcp, &payload, 1) != SR_OK)
-                       sr_warn("Couldn't send data");
-       }
+                       devc->trigger_edge_mask + devc->data_width_bytes - 1 - i, 1);
 
        return SR_OK;
 }
@@ -477,37 +479,37 @@ SR_PRIV void ipdbg_la_get_addrwidth_and_datawidth(
        uint8_t buf[8];
        uint8_t read_cmd = CMD_GET_BUS_WIDTHS;
 
-       if (ipdbg_la_tcp_send(tcp, &read_cmd, 1) != SR_OK)
+       if (tcp_send(tcp, &read_cmd, 1) != SR_OK)
                sr_warn("Can't send read command");
 
-       if (ipdbg_la_tcp_receive_blocking(tcp, buf, 8) != 8)
+       if (tcp_receive_blocking(tcp, buf, 8) != 8)
                sr_warn("Can't get address and data width from device");
 
-       devc->DATA_WIDTH = buf[0] & 0x000000FF;
-       devc->DATA_WIDTH |= (buf[1] << 8) & 0x0000FF00;
-       devc->DATA_WIDTH |= (buf[2] << 16) & 0x00FF0000;
-       devc->DATA_WIDTH |= (buf[3] << 24) & 0xFF000000;
+       devc->data_width = buf[0] & 0x000000FF;
+       devc->data_width |= (buf[1] << 8) & 0x0000FF00;
+       devc->data_width |= (buf[2] << 16) & 0x00FF0000;
+       devc->data_width |= (buf[3] << 24) & 0xFF000000;
 
-       devc->ADDR_WIDTH = buf[4] & 0x000000FF;
-       devc->ADDR_WIDTH |= (buf[5] << 8) & 0x0000FF00;
-       devc->ADDR_WIDTH |= (buf[6] << 16) & 0x00FF0000;
-       devc->ADDR_WIDTH |= (buf[7] << 24) & 0xFF000000;
+       devc->addr_width = buf[4] & 0x000000FF;
+       devc->addr_width |= (buf[5] << 8) & 0x0000FF00;
+       devc->addr_width |= (buf[6] << 16) & 0x00FF0000;
+       devc->addr_width |= (buf[7] << 24) & 0xFF000000;
 
-       uint8_t HOST_WORD_SIZE = 8;
+       const uint8_t host_word_size = 8;
 
-       devc->DATA_WIDTH_BYTES =
-               (devc->DATA_WIDTH + HOST_WORD_SIZE - 1) / HOST_WORD_SIZE;
-       devc->ADDR_WIDTH_BYTES =
-               (devc->ADDR_WIDTH + HOST_WORD_SIZE - 1) / HOST_WORD_SIZE;
+       devc->data_width_bytes =
+               (devc->data_width + host_word_size - 1) / host_word_size;
+       devc->addr_width_bytes =
+               (devc->addr_width + host_word_size - 1) / host_word_size;
 
-       devc->limit_samples_max = (0x01 << devc->ADDR_WIDTH);
+       devc->limit_samples_max = (0x01 << devc->addr_width);
        devc->limit_samples = devc->limit_samples_max;
 
-       devc->trigger_mask = g_malloc0(devc->DATA_WIDTH_BYTES);
-       devc->trigger_value = g_malloc0(devc->DATA_WIDTH_BYTES);
-       devc->trigger_mask_last = g_malloc0(devc->DATA_WIDTH_BYTES);
-       devc->trigger_value_last = g_malloc0(devc->DATA_WIDTH_BYTES);
-       devc->trigger_edge_mask = g_malloc0(devc->DATA_WIDTH_BYTES);
+       devc->trigger_mask = g_malloc0(devc->data_width_bytes);
+       devc->trigger_value = g_malloc0(devc->data_width_bytes);
+       devc->trigger_mask_last = g_malloc0(devc->data_width_bytes);
+       devc->trigger_value_last = g_malloc0(devc->data_width_bytes);
+       devc->trigger_edge_mask = g_malloc0(devc->data_width_bytes);
 }
 
 SR_PRIV struct dev_context *ipdbg_la_dev_new(void)
@@ -523,7 +525,7 @@ SR_PRIV struct dev_context *ipdbg_la_dev_new(void)
 SR_PRIV int ipdbg_la_send_reset(struct ipdbg_la_tcp *tcp)
 {
        uint8_t buf = CMD_RESET;
-       if (ipdbg_la_tcp_send(tcp, &buf, 1) != SR_OK)
+       if (tcp_send(tcp, &buf, 1) != SR_OK)
                sr_warn("Couldn't send reset");
 
        return SR_OK;
@@ -532,11 +534,11 @@ SR_PRIV int ipdbg_la_send_reset(struct ipdbg_la_tcp *tcp)
 SR_PRIV int ipdbg_la_request_id(struct ipdbg_la_tcp *tcp)
 {
        uint8_t buf = CMD_GET_LA_ID;
-       if (ipdbg_la_tcp_send(tcp, &buf, 1) != SR_OK)
+       if (tcp_send(tcp, &buf, 1) != SR_OK)
                sr_warn("Couldn't send ID request");
 
        char id[4];
-       if (ipdbg_la_tcp_receive_blocking(tcp, (uint8_t*)id, 4) != 4) {
+       if (tcp_receive_blocking(tcp, (uint8_t *)id, 4) != 4) {
                sr_err("Couldn't read device ID");
                return SR_ERR;
        }
@@ -563,7 +565,7 @@ SR_PRIV int ipdbg_la_send_start(struct ipdbg_la_tcp *tcp)
 {
        uint8_t buf = CMD_START;
 
-       if (ipdbg_la_tcp_send(tcp, &buf, 1) != SR_OK)
+       if (tcp_send(tcp, &buf, 1) != SR_OK)
                sr_warn("Couldn't send start");
 
        return SR_OK;