1452 lines
41 KiB
Diff
1452 lines
41 KiB
Diff
From 0d3ea13a45b88fc6cd78aa13f253c25d24ed9b59 Mon Sep 17 00:00:00 2001
|
|
From: taorye <taorye@outlook.com>
|
|
Date: Sun, 29 Jan 2023 18:19:49 +0800
|
|
Subject: [PATCH 1/4] sipeed-slogic-analyzer: Initial driver skeleton.
|
|
|
|
---
|
|
Makefile.am | 6 +
|
|
configure.ac | 1 +
|
|
src/hardware/sipeed-slogic-analyzer/api.c | 154 ++++++++++++++++++
|
|
.../sipeed-slogic-analyzer/protocol.c | 43 +++++
|
|
.../sipeed-slogic-analyzer/protocol.h | 35 ++++
|
|
5 files changed, 239 insertions(+)
|
|
create mode 100644 src/hardware/sipeed-slogic-analyzer/api.c
|
|
create mode 100644 src/hardware/sipeed-slogic-analyzer/protocol.c
|
|
create mode 100644 src/hardware/sipeed-slogic-analyzer/protocol.h
|
|
|
|
diff --git a/Makefile.am b/Makefile.am
|
|
index 280cf64d2..54332ae73 100644
|
|
--- a/Makefile.am
|
|
+++ b/Makefile.am
|
|
@@ -628,6 +628,12 @@ src_libdrivers_la_SOURCES += \
|
|
src/hardware/siglent-sds/protocol.c \
|
|
src/hardware/siglent-sds/api.c
|
|
endif
|
|
+if HW_SIPEED_SLOGIC_ANALYZER
|
|
+src_libdrivers_la_SOURCES += \
|
|
+ src/hardware/sipeed-slogic-analyzer/protocol.h \
|
|
+ src/hardware/sipeed-slogic-analyzer/protocol.c \
|
|
+ src/hardware/sipeed-slogic-analyzer/api.c
|
|
+endif
|
|
if HW_SYSCLK_LWLA
|
|
src_libdrivers_la_SOURCES += \
|
|
src/hardware/sysclk-lwla/lwla.h \
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 3ba6c8c5d..16ec2f63b 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -356,6 +356,7 @@ SR_DRIVER([SCPI PPS], [scpi-pps])
|
|
SR_DRIVER([serial DMM], [serial-dmm], [serial_comm])
|
|
SR_DRIVER([serial LCR], [serial-lcr], [serial_comm])
|
|
SR_DRIVER([Siglent SDS], [siglent-sds])
|
|
+SR_DRIVER([Sipeed Slogic Analyzer], [sipeed-slogic-analyzer])
|
|
SR_DRIVER([Sysclk LWLA], [sysclk-lwla], [libusb])
|
|
SR_DRIVER([Sysclk SLA5032], [sysclk-sla5032], [libusb])
|
|
SR_DRIVER([Teleinfo], [teleinfo], [serial_comm])
|
|
diff --git a/src/hardware/sipeed-slogic-analyzer/api.c b/src/hardware/sipeed-slogic-analyzer/api.c
|
|
new file mode 100644
|
|
index 000000000..365e85920
|
|
--- /dev/null
|
|
+++ b/src/hardware/sipeed-slogic-analyzer/api.c
|
|
@@ -0,0 +1,154 @@
|
|
+/*
|
|
+ * This file is part of the libsigrok project.
|
|
+ *
|
|
+ * Copyright (C) 2023 taorye <taorye@outlook.com>
|
|
+ *
|
|
+ * This program is free software: you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation, either version 3 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/>.
|
|
+ */
|
|
+
|
|
+#include <config.h>
|
|
+#include "protocol.h"
|
|
+
|
|
+static struct sr_dev_driver sipeed_slogic_analyzer_driver_info;
|
|
+
|
|
+static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|
+{
|
|
+ struct drv_context *drvc;
|
|
+ GSList *devices;
|
|
+
|
|
+ (void)options;
|
|
+
|
|
+ devices = NULL;
|
|
+ drvc = di->context;
|
|
+ drvc->instances = NULL;
|
|
+
|
|
+ /* TODO: scan for devices, either based on a SR_CONF_CONN option
|
|
+ * or on a USB scan. */
|
|
+
|
|
+ return devices;
|
|
+}
|
|
+
|
|
+static int dev_open(struct sr_dev_inst *sdi)
|
|
+{
|
|
+ (void)sdi;
|
|
+
|
|
+ /* TODO: get handle from sdi->conn and open it. */
|
|
+
|
|
+ return SR_OK;
|
|
+}
|
|
+
|
|
+static int dev_close(struct sr_dev_inst *sdi)
|
|
+{
|
|
+ (void)sdi;
|
|
+
|
|
+ /* TODO: get handle from sdi->conn and close it. */
|
|
+
|
|
+ return SR_OK;
|
|
+}
|
|
+
|
|
+static int config_get(uint32_t key, GVariant **data,
|
|
+ const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ (void)sdi;
|
|
+ (void)data;
|
|
+ (void)cg;
|
|
+
|
|
+ ret = SR_OK;
|
|
+ switch (key) {
|
|
+ /* TODO */
|
|
+ default:
|
|
+ return SR_ERR_NA;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int config_set(uint32_t key, GVariant *data,
|
|
+ const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ (void)sdi;
|
|
+ (void)data;
|
|
+ (void)cg;
|
|
+
|
|
+ ret = SR_OK;
|
|
+ switch (key) {
|
|
+ /* TODO */
|
|
+ default:
|
|
+ ret = SR_ERR_NA;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int config_list(uint32_t key, GVariant **data,
|
|
+ const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ (void)sdi;
|
|
+ (void)data;
|
|
+ (void)cg;
|
|
+
|
|
+ ret = SR_OK;
|
|
+ switch (key) {
|
|
+ /* TODO */
|
|
+ default:
|
|
+ return SR_ERR_NA;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|
+{
|
|
+ /* TODO: configure hardware, reset acquisition state, set up
|
|
+ * callbacks and send header packet. */
|
|
+
|
|
+ (void)sdi;
|
|
+
|
|
+ return SR_OK;
|
|
+}
|
|
+
|
|
+static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
|
+{
|
|
+ /* TODO: stop acquisition. */
|
|
+
|
|
+ (void)sdi;
|
|
+
|
|
+ return SR_OK;
|
|
+}
|
|
+
|
|
+static struct sr_dev_driver sipeed_slogic_analyzer_driver_info = {
|
|
+ .name = "sipeed-slogic-analyzer",
|
|
+ .longname = "Sipeed Slogic Analyzer",
|
|
+ .api_version = 1,
|
|
+ .init = std_init,
|
|
+ .cleanup = std_cleanup,
|
|
+ .scan = scan,
|
|
+ .dev_list = std_dev_list,
|
|
+ .dev_clear = std_dev_clear,
|
|
+ .config_get = config_get,
|
|
+ .config_set = config_set,
|
|
+ .config_list = config_list,
|
|
+ .dev_open = dev_open,
|
|
+ .dev_close = dev_close,
|
|
+ .dev_acquisition_start = dev_acquisition_start,
|
|
+ .dev_acquisition_stop = dev_acquisition_stop,
|
|
+ .context = NULL,
|
|
+};
|
|
+SR_REGISTER_DEV_DRIVER(sipeed_slogic_analyzer_driver_info);
|
|
diff --git a/src/hardware/sipeed-slogic-analyzer/protocol.c b/src/hardware/sipeed-slogic-analyzer/protocol.c
|
|
new file mode 100644
|
|
index 000000000..7b01e9812
|
|
--- /dev/null
|
|
+++ b/src/hardware/sipeed-slogic-analyzer/protocol.c
|
|
@@ -0,0 +1,43 @@
|
|
+/*
|
|
+ * This file is part of the libsigrok project.
|
|
+ *
|
|
+ * Copyright (C) 2023 taorye <taorye@outlook.com>
|
|
+ *
|
|
+ * This program is free software: you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation, either version 3 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/>.
|
|
+ */
|
|
+
|
|
+#include <config.h>
|
|
+#include "protocol.h"
|
|
+
|
|
+SR_PRIV int sipeed_slogic_analyzer_receive_data(int fd, int revents, void *cb_data)
|
|
+{
|
|
+ const struct sr_dev_inst *sdi;
|
|
+ struct dev_context *devc;
|
|
+
|
|
+ (void)fd;
|
|
+
|
|
+ sdi = cb_data;
|
|
+ if (!sdi)
|
|
+ return TRUE;
|
|
+
|
|
+ devc = sdi->priv;
|
|
+ if (!devc)
|
|
+ return TRUE;
|
|
+
|
|
+ if (revents == G_IO_IN) {
|
|
+ /* TODO */
|
|
+ }
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
diff --git a/src/hardware/sipeed-slogic-analyzer/protocol.h b/src/hardware/sipeed-slogic-analyzer/protocol.h
|
|
new file mode 100644
|
|
index 000000000..fab48d9aa
|
|
--- /dev/null
|
|
+++ b/src/hardware/sipeed-slogic-analyzer/protocol.h
|
|
@@ -0,0 +1,35 @@
|
|
+/*
|
|
+ * This file is part of the libsigrok project.
|
|
+ *
|
|
+ * Copyright (C) 2023 taorye <taorye@outlook.com>
|
|
+ *
|
|
+ * This program is free software: you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation, either version 3 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/>.
|
|
+ */
|
|
+
|
|
+#ifndef LIBSIGROK_HARDWARE_SIPEED_SLOGIC_ANALYZER_PROTOCOL_H
|
|
+#define LIBSIGROK_HARDWARE_SIPEED_SLOGIC_ANALYZER_PROTOCOL_H
|
|
+
|
|
+#include <stdint.h>
|
|
+#include <glib.h>
|
|
+#include <libsigrok/libsigrok.h>
|
|
+#include "libsigrok-internal.h"
|
|
+
|
|
+#define LOG_PREFIX "sipeed-slogic-analyzer"
|
|
+
|
|
+struct dev_context {
|
|
+};
|
|
+
|
|
+SR_PRIV int sipeed_slogic_analyzer_receive_data(int fd, int revents, void *cb_data);
|
|
+
|
|
+#endif
|
|
|
|
From bfe4a0d975df021f90d7ccc92dafc90e87ee5068 Mon Sep 17 00:00:00 2001
|
|
From: taorye <taorye@outlook.com>
|
|
Date: Mon, 20 Feb 2023 09:43:04 +0800
|
|
Subject: [PATCH 2/4] feat: use pattern to control active channels
|
|
|
|
---
|
|
src/hardware/sipeed-slogic-analyzer/api.c | 306 +++++++++++++++++-
|
|
.../sipeed-slogic-analyzer/protocol.h | 14 +
|
|
2 files changed, 312 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/src/hardware/sipeed-slogic-analyzer/api.c b/src/hardware/sipeed-slogic-analyzer/api.c
|
|
index 365e85920..4023d236b 100644
|
|
--- a/src/hardware/sipeed-slogic-analyzer/api.c
|
|
+++ b/src/hardware/sipeed-slogic-analyzer/api.c
|
|
@@ -20,8 +20,78 @@
|
|
#include <config.h>
|
|
#include "protocol.h"
|
|
|
|
+/* Note: No spaces allowed because of sigrok-cli. */
|
|
+static const char *logic_pattern_str[] = {
|
|
+ "1ch",
|
|
+ "2ch",
|
|
+ "4ch",
|
|
+ "8ch",
|
|
+ // "16ch",
|
|
+};
|
|
+
|
|
+static const uint32_t scanopts[] = {
|
|
+ SR_CONF_NUM_LOGIC_CHANNELS,
|
|
+ SR_CONF_CONN,
|
|
+};
|
|
+
|
|
+static const uint32_t drvopts[] = {
|
|
+ SR_CONF_LOGIC_ANALYZER,
|
|
+};
|
|
+
|
|
+static const uint32_t devopts[] = {
|
|
+ SR_CONF_CONTINUOUS,
|
|
+ SR_CONF_CONN | SR_CONF_GET,
|
|
+ SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
|
+ SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
|
+ SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
|
|
+ SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
|
|
+};
|
|
+
|
|
+static const uint32_t devopts_cg_logic[] = {
|
|
+ SR_CONF_PATTERN_MODE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
|
+};
|
|
+
|
|
+static const int32_t trigger_matches[] = {
|
|
+ SR_TRIGGER_ZERO,
|
|
+ SR_TRIGGER_ONE,
|
|
+ SR_TRIGGER_RISING,
|
|
+ SR_TRIGGER_FALLING,
|
|
+ SR_TRIGGER_EDGE,
|
|
+};
|
|
+
|
|
+static const uint64_t samplerates[] = {
|
|
+ SR_KHZ(20),
|
|
+ SR_KHZ(25),
|
|
+ SR_KHZ(50),
|
|
+ SR_KHZ(100),
|
|
+ SR_KHZ(200),
|
|
+ SR_KHZ(250),
|
|
+ SR_KHZ(500),
|
|
+ /* 160M = 2*2*2*2*2*5M */
|
|
+ SR_MHZ(1),
|
|
+ SR_MHZ(2),
|
|
+ SR_MHZ(4),
|
|
+ SR_MHZ(5),
|
|
+ SR_MHZ(8),
|
|
+ SR_MHZ(10),
|
|
+ SR_MHZ(16),
|
|
+ SR_MHZ(20),
|
|
+ SR_MHZ(32),
|
|
+ SR_MHZ(40),
|
|
+ /* must less than 47MHZ */
|
|
+};
|
|
+
|
|
static struct sr_dev_driver sipeed_slogic_analyzer_driver_info;
|
|
|
|
+#define DBG_VAL(expr) do {\
|
|
+ __typeof((expr)) _expr = (expr);\
|
|
+ sr_warn("[%u]%s<"#expr"> i:%d\tu:%u\tf:%f\th:%x", __LINE__, __func__, \
|
|
+ *(long*)(&_expr), \
|
|
+ *(unsigned long*)(&_expr), \
|
|
+ *(float*)(&_expr), \
|
|
+ *(unsigned long*)(&_expr)); \
|
|
+}while(0)
|
|
+
|
|
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|
{
|
|
struct drv_context *drvc;
|
|
@@ -35,8 +105,77 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|
|
|
/* TODO: scan for devices, either based on a SR_CONF_CONN option
|
|
* or on a USB scan. */
|
|
+ const char *conn = NULL;
|
|
+ int num_logic_channels = 8;
|
|
+ for (GSList *l = options; l; l = l->next) {
|
|
+ struct sr_config *src = l->data;DBG_VAL(src->key);
|
|
+ switch (src->key) {
|
|
+ case SR_CONF_NUM_LOGIC_CHANNELS:
|
|
+ num_logic_channels = g_variant_get_int32(src->data);
|
|
+ break;
|
|
+ case SR_CONF_CONN:
|
|
+ conn = g_variant_get_string(src->data, NULL);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if(!conn) {
|
|
+ conn = "359f.0300";
|
|
+ }
|
|
|
|
- return devices;
|
|
+ /* Find all slogic compatible devices. */
|
|
+ GSList * conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
|
|
+ for(GSList *l = conn_devices; l; l = l->next) {
|
|
+ struct sr_usb_dev_inst *usb = l->data;
|
|
+ if (SR_OK != sr_usb_open(drvc->sr_ctx->libusb_ctx, usb))
|
|
+ continue;
|
|
+
|
|
+ unsigned char iManufacturer[64], iProduct[64], iSerialNumber[64];
|
|
+ unsigned char connection_id[64];
|
|
+ struct libusb_device_descriptor des;
|
|
+ libusb_get_device_descriptor(libusb_get_device(usb->devhdl), &des);
|
|
+ if (libusb_get_string_descriptor_ascii(usb->devhdl,
|
|
+ des.iManufacturer, iManufacturer, sizeof(iManufacturer)) < 0)
|
|
+ continue;
|
|
+ if (libusb_get_string_descriptor_ascii(usb->devhdl,
|
|
+ des.iProduct, iProduct, sizeof(iProduct)) < 0)
|
|
+ continue;
|
|
+ if (libusb_get_string_descriptor_ascii(usb->devhdl,
|
|
+ des.iSerialNumber, iSerialNumber, sizeof(iSerialNumber)) < 0)
|
|
+ continue;
|
|
+ if (usb_get_port_path(libusb_get_device(usb->devhdl),
|
|
+ connection_id, sizeof(connection_id)) < 0)
|
|
+ continue;
|
|
+ sr_usb_close(usb);
|
|
+
|
|
+ struct sr_dev_inst *sdi = sr_dev_inst_user_new(iManufacturer, iProduct, NULL);
|
|
+ sdi->serial_num = g_strdup(iSerialNumber);
|
|
+ sdi->connection_id = g_strdup(connection_id);
|
|
+
|
|
+ sdi->inst_type = SR_INST_USB;
|
|
+ sdi->status = SR_ST_INACTIVE;
|
|
+ sdi->conn = usb;
|
|
+
|
|
+ struct dev_context *devc = g_malloc0(sizeof(struct dev_context));
|
|
+ sdi->priv = devc;
|
|
+ devc->profile = NULL;
|
|
+
|
|
+ if (num_logic_channels > 0) {
|
|
+ /* Logic channels, all in one channel group. */
|
|
+ struct sr_channel_group *cg = sr_channel_group_new(sdi, "Logic", NULL);
|
|
+ for (int i = 0; i < num_logic_channels; i++) {
|
|
+ char channel_name[16];
|
|
+ sprintf(channel_name, "D%d", i);
|
|
+ struct sr_channel *ch = sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, channel_name);
|
|
+ cg->channels = g_slist_append(cg->channels, ch);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ devices = g_slist_append(devices, sdi);
|
|
+ }
|
|
+ // g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
|
|
+
|
|
+ return std_scan_complete(di, devices);
|
|
}
|
|
|
|
static int dev_open(struct sr_dev_inst *sdi)
|
|
@@ -44,8 +183,37 @@ static int dev_open(struct sr_dev_inst *sdi)
|
|
(void)sdi;
|
|
|
|
/* TODO: get handle from sdi->conn and open it. */
|
|
+ int ret;
|
|
+ struct sr_usb_dev_inst *usb= sdi->conn;
|
|
+ struct dev_context *devc= sdi->priv;
|
|
+ struct sr_dev_driver *di = sdi->driver;
|
|
+ struct drv_context *drvc = di->context;
|
|
+
|
|
+ ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb);DBG_VAL(ret);
|
|
+ if (ret != SR_OK)
|
|
+ return ret;
|
|
+
|
|
+ ret = libusb_claim_interface(usb->devhdl, 0);DBG_VAL(ret);
|
|
+ if (ret != LIBUSB_SUCCESS) {
|
|
+ switch (ret) {
|
|
+ case LIBUSB_ERROR_BUSY:
|
|
+ sr_err("Unable to claim USB interface. Another "
|
|
+ "program or driver has already claimed it.");
|
|
+ break;
|
|
+ case LIBUSB_ERROR_NO_DEVICE:
|
|
+ sr_err("Device has been disconnected.");
|
|
+ break;
|
|
+ default:
|
|
+ sr_err("Unable to claim interface: %s.",
|
|
+ libusb_error_name(ret));
|
|
+ break;
|
|
+ }
|
|
+ return SR_ERR;
|
|
+ }
|
|
|
|
- return SR_OK;
|
|
+ devc->logic_pattern = 3; /* 2^3 = 8 default */
|
|
+
|
|
+ return std_dummy_dev_open(sdi);
|
|
}
|
|
|
|
static int dev_close(struct sr_dev_inst *sdi)
|
|
@@ -53,8 +221,20 @@ static int dev_close(struct sr_dev_inst *sdi)
|
|
(void)sdi;
|
|
|
|
/* TODO: get handle from sdi->conn and close it. */
|
|
+ int ret;
|
|
+ struct sr_usb_dev_inst *usb = sdi->conn;
|
|
+ struct dev_context *devc= sdi->priv;
|
|
+
|
|
+ ret = libusb_release_interface(usb->devhdl, 0);DBG_VAL(ret);
|
|
+ if (ret != LIBUSB_SUCCESS) {
|
|
+ sr_err("Unable to release Interface for %s.",
|
|
+ libusb_error_name(ret));
|
|
+ return SR_ERR;
|
|
+ }
|
|
|
|
- return SR_OK;
|
|
+ sr_usb_close(usb);
|
|
+
|
|
+ return std_dummy_dev_close(sdi);
|
|
}
|
|
|
|
static int config_get(uint32_t key, GVariant **data,
|
|
@@ -66,9 +246,42 @@ static int config_get(uint32_t key, GVariant **data,
|
|
(void)data;
|
|
(void)cg;
|
|
|
|
- ret = SR_OK;
|
|
+ struct sr_usb_dev_inst *usb = sdi->conn;
|
|
+ struct dev_context *devc= sdi->priv;
|
|
+ struct sr_channel *ch;
|
|
+ ret = SR_OK;DBG_VAL(key);
|
|
switch (key) {
|
|
/* TODO */
|
|
+ case SR_CONF_CONN:
|
|
+ if (usb->address == 0xff)
|
|
+ /* Device still needs to re-enumerate after firmware
|
|
+ * upload, so we don't know its (future) address. */
|
|
+ return SR_ERR;
|
|
+ *data = g_variant_new_printf("%d.%d", usb->bus, usb->address);
|
|
+ break;
|
|
+ case SR_CONF_SAMPLERATE:
|
|
+ *data = g_variant_new_uint64(devc->cur_samplerate);
|
|
+ break;
|
|
+ case SR_CONF_LIMIT_SAMPLES:
|
|
+ *data = g_variant_new_uint64(devc->limit_samples);
|
|
+ break;
|
|
+ case SR_CONF_PATTERN_MODE:
|
|
+ if (!cg)
|
|
+ return SR_ERR_CHANNEL_GROUP;
|
|
+ /* Any channel in the group will do. */
|
|
+ ch = cg->channels->data;
|
|
+ if (ch->type == SR_CHANNEL_LOGIC) {
|
|
+ int pattern = devc->logic_pattern;
|
|
+ *data = g_variant_new_string(logic_pattern_str[pattern]);
|
|
+ } else
|
|
+ return SR_ERR_BUG;
|
|
+ break;
|
|
+ case SR_CONF_CAPTURE_RATIO:
|
|
+ *data = g_variant_new_uint64(devc->capture_ratio);
|
|
+ break;
|
|
+ case SR_CONF_VOLTAGE_THRESHOLD:
|
|
+ *data = std_gvar_tuple_double(devc->voltage_threshold[0], devc->voltage_threshold[1]);
|
|
+ break;
|
|
default:
|
|
return SR_ERR_NA;
|
|
}
|
|
@@ -85,9 +298,60 @@ static int config_set(uint32_t key, GVariant *data,
|
|
(void)data;
|
|
(void)cg;
|
|
|
|
- ret = SR_OK;
|
|
+ struct dev_context *devc= sdi->priv;
|
|
+ int logic_pattern;
|
|
+ ret = SR_OK;DBG_VAL(key);
|
|
switch (key) {
|
|
/* TODO */
|
|
+ case SR_CONF_SAMPLERATE:
|
|
+ if (std_u64_idx(data, ARRAY_AND_SIZE(samplerates)) < 0)
|
|
+ return SR_ERR_ARG;
|
|
+ devc->cur_samplerate = g_variant_get_uint64(data);
|
|
+ break;
|
|
+ case SR_CONF_LIMIT_SAMPLES:
|
|
+ devc->limit_samples = g_variant_get_uint64(data);
|
|
+ break;
|
|
+ case SR_CONF_PATTERN_MODE:
|
|
+ if (!cg)
|
|
+ return SR_ERR_CHANNEL_GROUP;
|
|
+ logic_pattern = std_str_idx(data, ARRAY_AND_SIZE(logic_pattern_str));
|
|
+ if (logic_pattern < 0)
|
|
+ return SR_ERR_ARG;
|
|
+ if (((struct sr_channel *)cg->channels->data)->type == SR_CHANNEL_LOGIC) {
|
|
+ sr_dbg("Setting logic pattern to %s",
|
|
+ logic_pattern_str[logic_pattern]);
|
|
+ devc->logic_pattern = logic_pattern;
|
|
+ /* Might as well do this now, these are static. */
|
|
+ }
|
|
+ {
|
|
+
|
|
+ size_t idx = 0;
|
|
+ for (GSList *l = cg->channels; l; l = l->next, idx += 1) {
|
|
+ struct sr_channel *ch = l->data;
|
|
+ if (ch->type == SR_CHANNEL_LOGIC) {
|
|
+ /* Might as well do this now, these are static. */
|
|
+ switch (devc->logic_pattern)
|
|
+ {
|
|
+ case 0/* 2^0 = 1 */:
|
|
+ case 1/* 2^1 = 2 */:
|
|
+ case 2/* 2^2 = 4 */:
|
|
+ case 3/* 2^3 = 8 */:
|
|
+ sr_dev_channel_enable(ch, (idx >= (1 << (devc->logic_pattern))) ? FALSE : TRUE);
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ } else
|
|
+ return SR_ERR_BUG;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ case SR_CONF_CAPTURE_RATIO:
|
|
+ devc->capture_ratio = g_variant_get_uint64(data);
|
|
+ break;
|
|
+ case SR_CONF_VOLTAGE_THRESHOLD:
|
|
+ g_variant_get(data, "(dd)", &devc->voltage_threshold[0], &devc->voltage_threshold[1]);
|
|
+ break;
|
|
default:
|
|
ret = SR_ERR_NA;
|
|
}
|
|
@@ -104,9 +368,35 @@ static int config_list(uint32_t key, GVariant **data,
|
|
(void)data;
|
|
(void)cg;
|
|
|
|
- ret = SR_OK;
|
|
+ struct sr_channel *ch;
|
|
+ ret = SR_OK;DBG_VAL(key);
|
|
switch (key) {
|
|
/* TODO */
|
|
+ case SR_CONF_SCAN_OPTIONS:
|
|
+ case SR_CONF_DEVICE_OPTIONS:
|
|
+ if (!cg)
|
|
+ return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
|
+ ch = cg->channels->data;
|
|
+ if (ch->type == SR_CHANNEL_LOGIC)
|
|
+ *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_logic));
|
|
+ else
|
|
+ return SR_ERR_BUG;
|
|
+ break;
|
|
+ case SR_CONF_SAMPLERATE:
|
|
+ *data = std_gvar_samplerates(ARRAY_AND_SIZE(samplerates));
|
|
+ break;
|
|
+ case SR_CONF_TRIGGER_MATCH:
|
|
+ *data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
|
|
+ break;
|
|
+ case SR_CONF_PATTERN_MODE:
|
|
+ if (!cg)
|
|
+ return SR_ERR_NA;
|
|
+ ch = cg->channels->data;
|
|
+ if (ch->type == SR_CHANNEL_LOGIC)
|
|
+ *data = g_variant_new_strv(ARRAY_AND_SIZE(logic_pattern_str));
|
|
+ else
|
|
+ return SR_ERR_BUG;
|
|
+ break;
|
|
default:
|
|
return SR_ERR_NA;
|
|
}
|
|
@@ -119,7 +409,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|
/* TODO: configure hardware, reset acquisition state, set up
|
|
* callbacks and send header packet. */
|
|
|
|
- (void)sdi;
|
|
+ (void)sdi;DBG_VAL(sdi);
|
|
|
|
return SR_OK;
|
|
}
|
|
@@ -128,7 +418,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
|
{
|
|
/* TODO: stop acquisition. */
|
|
|
|
- (void)sdi;
|
|
+ (void)sdi;DBG_VAL(sdi);
|
|
|
|
return SR_OK;
|
|
}
|
|
diff --git a/src/hardware/sipeed-slogic-analyzer/protocol.h b/src/hardware/sipeed-slogic-analyzer/protocol.h
|
|
index fab48d9aa..84e310870 100644
|
|
--- a/src/hardware/sipeed-slogic-analyzer/protocol.h
|
|
+++ b/src/hardware/sipeed-slogic-analyzer/protocol.h
|
|
@@ -22,12 +22,26 @@
|
|
|
|
#include <stdint.h>
|
|
#include <glib.h>
|
|
+#include <libusb.h>
|
|
#include <libsigrok/libsigrok.h>
|
|
#include "libsigrok-internal.h"
|
|
|
|
#define LOG_PREFIX "sipeed-slogic-analyzer"
|
|
|
|
+struct slogic_profile {
|
|
+ uint16_t vid;
|
|
+ uint16_t pid;
|
|
+};
|
|
+
|
|
struct dev_context {
|
|
+ struct slogic_profile *profile;
|
|
+
|
|
+ uint64_t cur_samplerate;
|
|
+ uint64_t limit_samples;
|
|
+ int logic_pattern;
|
|
+ double voltage_threshold[2];
|
|
+ /* Triggers */
|
|
+ uint64_t capture_ratio;
|
|
};
|
|
|
|
SR_PRIV int sipeed_slogic_analyzer_receive_data(int fd, int revents, void *cb_data);
|
|
|
|
From ab2d673508fd652b5f93792d458a78f522f17c4c Mon Sep 17 00:00:00 2001
|
|
From: taorye <taorye@outlook.com>
|
|
Date: Tue, 21 Feb 2023 12:00:58 +0800
|
|
Subject: [PATCH 3/4] feat: capture data and regroup channels
|
|
|
|
---
|
|
src/hardware/sipeed-slogic-analyzer/api.c | 52 +--
|
|
.../sipeed-slogic-analyzer/protocol.c | 356 +++++++++++++++++-
|
|
.../sipeed-slogic-analyzer/protocol.h | 76 +++-
|
|
3 files changed, 435 insertions(+), 49 deletions(-)
|
|
|
|
diff --git a/src/hardware/sipeed-slogic-analyzer/api.c b/src/hardware/sipeed-slogic-analyzer/api.c
|
|
index 4023d236b..4038a6e28 100644
|
|
--- a/src/hardware/sipeed-slogic-analyzer/api.c
|
|
+++ b/src/hardware/sipeed-slogic-analyzer/api.c
|
|
@@ -83,15 +83,6 @@ static const uint64_t samplerates[] = {
|
|
|
|
static struct sr_dev_driver sipeed_slogic_analyzer_driver_info;
|
|
|
|
-#define DBG_VAL(expr) do {\
|
|
- __typeof((expr)) _expr = (expr);\
|
|
- sr_warn("[%u]%s<"#expr"> i:%d\tu:%u\tf:%f\th:%x", __LINE__, __func__, \
|
|
- *(long*)(&_expr), \
|
|
- *(unsigned long*)(&_expr), \
|
|
- *(float*)(&_expr), \
|
|
- *(unsigned long*)(&_expr)); \
|
|
-}while(0)
|
|
-
|
|
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|
{
|
|
struct drv_context *drvc;
|
|
@@ -212,6 +203,11 @@ static int dev_open(struct sr_dev_inst *sdi)
|
|
}
|
|
|
|
devc->logic_pattern = 3; /* 2^3 = 8 default */
|
|
+ devc->cur_samplerate = samplerates[0];
|
|
+ devc->limit_samples = 0;
|
|
+ devc->num_frames = 0;
|
|
+ devc->limit_frames = 1;
|
|
+ devc->capture_ratio = 0;
|
|
|
|
return std_dummy_dev_open(sdi);
|
|
}
|
|
@@ -322,25 +318,12 @@ static int config_set(uint32_t key, GVariant *data,
|
|
logic_pattern_str[logic_pattern]);
|
|
devc->logic_pattern = logic_pattern;
|
|
/* Might as well do this now, these are static. */
|
|
- }
|
|
- {
|
|
-
|
|
size_t idx = 0;
|
|
for (GSList *l = cg->channels; l; l = l->next, idx += 1) {
|
|
struct sr_channel *ch = l->data;
|
|
if (ch->type == SR_CHANNEL_LOGIC) {
|
|
/* Might as well do this now, these are static. */
|
|
- switch (devc->logic_pattern)
|
|
- {
|
|
- case 0/* 2^0 = 1 */:
|
|
- case 1/* 2^1 = 2 */:
|
|
- case 2/* 2^2 = 4 */:
|
|
- case 3/* 2^3 = 8 */:
|
|
- sr_dev_channel_enable(ch, (idx >= (1 << (devc->logic_pattern))) ? FALSE : TRUE);
|
|
- break;
|
|
- default:
|
|
- break;
|
|
- }
|
|
+ sr_dev_channel_enable(ch, (idx >= (1 << (devc->logic_pattern))) ? FALSE : TRUE);
|
|
} else
|
|
return SR_ERR_BUG;
|
|
}
|
|
@@ -404,25 +387,6 @@ static int config_list(uint32_t key, GVariant **data,
|
|
return ret;
|
|
}
|
|
|
|
-static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|
-{
|
|
- /* TODO: configure hardware, reset acquisition state, set up
|
|
- * callbacks and send header packet. */
|
|
-
|
|
- (void)sdi;DBG_VAL(sdi);
|
|
-
|
|
- return SR_OK;
|
|
-}
|
|
-
|
|
-static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
|
-{
|
|
- /* TODO: stop acquisition. */
|
|
-
|
|
- (void)sdi;DBG_VAL(sdi);
|
|
-
|
|
- return SR_OK;
|
|
-}
|
|
-
|
|
static struct sr_dev_driver sipeed_slogic_analyzer_driver_info = {
|
|
.name = "sipeed-slogic-analyzer",
|
|
.longname = "Sipeed Slogic Analyzer",
|
|
@@ -437,8 +401,8 @@ static struct sr_dev_driver sipeed_slogic_analyzer_driver_info = {
|
|
.config_list = config_list,
|
|
.dev_open = dev_open,
|
|
.dev_close = dev_close,
|
|
- .dev_acquisition_start = dev_acquisition_start,
|
|
- .dev_acquisition_stop = dev_acquisition_stop,
|
|
+ .dev_acquisition_start = sipeed_slogic_acquisition_start,
|
|
+ .dev_acquisition_stop = sipeed_slogic_acquisition_stop,
|
|
.context = NULL,
|
|
};
|
|
SR_REGISTER_DEV_DRIVER(sipeed_slogic_analyzer_driver_info);
|
|
diff --git a/src/hardware/sipeed-slogic-analyzer/protocol.c b/src/hardware/sipeed-slogic-analyzer/protocol.c
|
|
index 7b01e9812..f232c25f6 100644
|
|
--- a/src/hardware/sipeed-slogic-analyzer/protocol.c
|
|
+++ b/src/hardware/sipeed-slogic-analyzer/protocol.c
|
|
@@ -20,12 +20,17 @@
|
|
#include <config.h>
|
|
#include "protocol.h"
|
|
|
|
+static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer);
|
|
+static int command_start_acquisition(const struct sr_dev_inst *sdi);
|
|
+
|
|
SR_PRIV int sipeed_slogic_analyzer_receive_data(int fd, int revents, void *cb_data)
|
|
{
|
|
const struct sr_dev_inst *sdi;
|
|
struct dev_context *devc;
|
|
+ struct drv_context *drvc;
|
|
|
|
(void)fd;
|
|
+ (void)revents;
|
|
|
|
sdi = cb_data;
|
|
if (!sdi)
|
|
@@ -35,9 +40,354 @@ SR_PRIV int sipeed_slogic_analyzer_receive_data(int fd, int revents, void *cb_da
|
|
if (!devc)
|
|
return TRUE;
|
|
|
|
- if (revents == G_IO_IN) {
|
|
- /* TODO */
|
|
- }
|
|
+ drvc = sdi->driver->context;
|
|
+ if (!drvc)
|
|
+ return TRUE;
|
|
+
|
|
+ struct timeval tv = {
|
|
+ .tv_sec = 0,
|
|
+ .tv_usec = 0,
|
|
+ };
|
|
+ libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
|
|
|
|
return TRUE;
|
|
}
|
|
+
|
|
+SR_PRIV int sipeed_slogic_acquisition_start(const struct sr_dev_inst *sdi)
|
|
+{
|
|
+ /* TODO: configure hardware, reset acquisition state, set up
|
|
+ * callbacks and send header packet. */
|
|
+
|
|
+ (void)sdi;DBG_VAL(sdi);
|
|
+ struct dev_context *devc = sdi->priv;
|
|
+
|
|
+ int timeout = get_timeout(devc);
|
|
+ usb_source_add(sdi->session, sdi->session->ctx, timeout, sipeed_slogic_analyzer_receive_data, sdi);
|
|
+
|
|
+ struct sr_usb_dev_inst *usb = sdi->conn;
|
|
+ devc->sent_samples = 0;
|
|
+ devc->acq_aborted = FALSE;
|
|
+ devc->empty_transfer_count = 0;
|
|
+
|
|
+ struct sr_trigger *trigger;
|
|
+ if ((trigger = sr_session_trigger_get(sdi->session))) {
|
|
+ int pre_trigger_samples = 0;
|
|
+ if (devc->limit_samples > 0)
|
|
+ pre_trigger_samples = (devc->capture_ratio * devc->limit_samples) / 100;
|
|
+ devc->stl = soft_trigger_logic_new(sdi, trigger, pre_trigger_samples);
|
|
+ if (!devc->stl)
|
|
+ return SR_ERR_MALLOC;
|
|
+ devc->trigger_fired = FALSE;
|
|
+ } else {
|
|
+ std_session_send_df_frame_begin(sdi);
|
|
+ devc->trigger_fired = TRUE;
|
|
+ }
|
|
+
|
|
+ devc->submitted_transfers = 0;
|
|
+ size_t num_transfers = get_number_of_transfers(devc);
|
|
+ devc->num_transfers = num_transfers;
|
|
+ devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * devc->num_transfers);
|
|
+ if (!devc->transfers) {
|
|
+ sr_err("USB transfers malloc failed.");
|
|
+ return SR_ERR_MALLOC;
|
|
+ }
|
|
+ size_t size = get_buffer_size(devc);
|
|
+ for (int i = 0; i < devc->num_transfers; i++) {
|
|
+ uint8_t *buf = g_try_malloc(size * 8); /* max 8xu1 */
|
|
+ if (!buf) {
|
|
+ sr_err("USB transfer buffer malloc failed.");
|
|
+ return SR_ERR_MALLOC;
|
|
+ }
|
|
+ struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
|
+ libusb_fill_bulk_transfer(transfer, usb->devhdl,
|
|
+ 1 | LIBUSB_ENDPOINT_IN, buf, size,
|
|
+ receive_transfer, (void *)sdi, timeout);
|
|
+ sr_info("submitting transfer: %d", i);
|
|
+ int ret = 0;
|
|
+ if ((ret = libusb_submit_transfer(transfer)) != 0) {
|
|
+ sr_err("Failed to submit transfer: %s.",
|
|
+ libusb_error_name(ret));
|
|
+ libusb_free_transfer(transfer);
|
|
+ g_free(buf);
|
|
+ sipeed_slogic_acquisition_stop(sdi);
|
|
+ return SR_ERR;
|
|
+ }
|
|
+ devc->transfers[i] = transfer;
|
|
+ devc->submitted_transfers++;
|
|
+ }
|
|
+
|
|
+ std_session_send_df_header(sdi);
|
|
+
|
|
+ int ret = SR_OK;
|
|
+ if ((ret = command_start_acquisition(sdi)) != SR_OK) {
|
|
+ sipeed_slogic_acquisition_stop(sdi);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return SR_OK;
|
|
+}
|
|
+
|
|
+SR_PRIV int sipeed_slogic_acquisition_stop(struct sr_dev_inst *sdi)
|
|
+{
|
|
+ /* TODO: stop acquisition. */
|
|
+
|
|
+ (void)sdi;DBG_VAL(sdi);
|
|
+ struct dev_context *devc = sdi->priv;
|
|
+
|
|
+ devc->acq_aborted = TRUE;
|
|
+ for (int i = devc->num_transfers - 1; i >= 0; i--) {
|
|
+ if (devc->transfers[i])
|
|
+ libusb_cancel_transfer(devc->transfers[i]);
|
|
+ }
|
|
+ return SR_OK;
|
|
+}
|
|
+
|
|
+static void finish_acquisition(struct sr_dev_inst *sdi)
|
|
+{
|
|
+ struct dev_context *devc;
|
|
+
|
|
+ devc = sdi->priv;
|
|
+
|
|
+ std_session_send_df_end(sdi);
|
|
+
|
|
+ usb_source_remove(sdi->session, sdi->session->ctx);
|
|
+
|
|
+ devc->num_transfers = 0;
|
|
+ g_free(devc->transfers);
|
|
+
|
|
+ if (devc->stl) {
|
|
+ soft_trigger_logic_free(devc->stl);
|
|
+ devc->stl = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void free_transfer(struct libusb_transfer *transfer)
|
|
+{
|
|
+ struct sr_dev_inst *sdi;
|
|
+ struct dev_context *devc;
|
|
+ unsigned int i;
|
|
+
|
|
+ sdi = transfer->user_data;
|
|
+ devc = sdi->priv;
|
|
+
|
|
+ g_free(transfer->buffer);
|
|
+ transfer->buffer = NULL;
|
|
+ libusb_free_transfer(transfer);
|
|
+
|
|
+ for (i = 0; i < devc->num_transfers; i++) {
|
|
+ if (devc->transfers[i] == transfer) {
|
|
+ devc->transfers[i] = NULL;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ devc->submitted_transfers--;
|
|
+ if (devc->submitted_transfers == 0)
|
|
+ finish_acquisition(sdi);
|
|
+}
|
|
+
|
|
+static void resubmit_transfer(struct libusb_transfer *transfer)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ if ((ret = libusb_submit_transfer(transfer)) == LIBUSB_SUCCESS)
|
|
+ return;
|
|
+
|
|
+ sr_err("%s: %s", __func__, libusb_error_name(ret));
|
|
+ free_transfer(transfer);
|
|
+}
|
|
+
|
|
+static void la_send_data_proc(struct sr_dev_inst *sdi,
|
|
+ uint8_t *data, size_t length, size_t sample_width)
|
|
+{
|
|
+ const struct sr_datafeed_logic logic = {
|
|
+ .length = length,
|
|
+ .unitsize = sample_width,
|
|
+ .data = data
|
|
+ };
|
|
+
|
|
+ const struct sr_datafeed_packet packet = {
|
|
+ .type = SR_DF_LOGIC,
|
|
+ .payload = &logic
|
|
+ };
|
|
+
|
|
+ sr_session_send(sdi, &packet);
|
|
+}
|
|
+
|
|
+static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer)
|
|
+{
|
|
+ struct sr_dev_inst *sdi = transfer->user_data;
|
|
+ struct dev_context *devc = sdi->priv;
|
|
+ gboolean packet_has_error = FALSE;
|
|
+ unsigned int num_samples;
|
|
+ int trigger_offset, cur_sample_count, unitsize, processed_samples;
|
|
+ int pre_trigger_samples;
|
|
+
|
|
+ /*
|
|
+ * If acquisition has already ended, just free any queued up
|
|
+ * transfer that come in.
|
|
+ */
|
|
+ if (devc->acq_aborted) {
|
|
+ free_transfer(transfer);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ sr_dbg("receive_transfer(): status %s received %d bytes.",
|
|
+ libusb_error_name(transfer->status), transfer->actual_length);
|
|
+
|
|
+ /* Save incoming transfer before reusing the transfer struct. */
|
|
+ unitsize = 1+(((1<<devc->logic_pattern)-1)>>3);
|
|
+ cur_sample_count = transfer->actual_length * 8 / (1<<devc->logic_pattern);
|
|
+ processed_samples = 0;
|
|
+
|
|
+ switch (transfer->status) {
|
|
+ case LIBUSB_TRANSFER_NO_DEVICE:
|
|
+ sipeed_slogic_acquisition_stop(sdi);
|
|
+ free_transfer(transfer);
|
|
+ return;
|
|
+ case LIBUSB_TRANSFER_COMPLETED:
|
|
+ case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */
|
|
+ break;
|
|
+ default:
|
|
+ packet_has_error = TRUE;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (transfer->actual_length == 0 || packet_has_error) {
|
|
+ devc->empty_transfer_count++;
|
|
+ if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) {
|
|
+ /*
|
|
+ * The FX2 gave up. End the acquisition, the frontend
|
|
+ * will work out that the samplecount is short.
|
|
+ */
|
|
+ sipeed_slogic_acquisition_stop(sdi);
|
|
+ free_transfer(transfer);
|
|
+ } else {
|
|
+ resubmit_transfer(transfer);
|
|
+ }
|
|
+ return;
|
|
+ } else {
|
|
+ devc->empty_transfer_count = 0;
|
|
+ }
|
|
+
|
|
+ uint8_t real_bits = 1<<devc->logic_pattern;
|
|
+check_trigger:
|
|
+ if (real_bits < 8) {
|
|
+ for (int i = cur_sample_count-1; i>=0; i--) {
|
|
+ ((uint8_t *)transfer->buffer)[i] =
|
|
+ (((uint8_t *)transfer->buffer)[i/real_bits] >> (real_bits-1-i%real_bits))
|
|
+ & ((1<<real_bits)-1);
|
|
+ }
|
|
+ }
|
|
+ if (devc->trigger_fired) {
|
|
+ if (!devc->limit_samples || devc->sent_samples < devc->limit_samples) {
|
|
+ /* Send the incoming transfer to the session bus. */
|
|
+ num_samples = cur_sample_count - processed_samples;
|
|
+ if (devc->limit_samples && devc->sent_samples + num_samples > devc->limit_samples)
|
|
+ num_samples = devc->limit_samples - devc->sent_samples;
|
|
+
|
|
+ la_send_data_proc(sdi, (uint8_t *)transfer->buffer
|
|
+ + processed_samples * unitsize,
|
|
+ num_samples * unitsize, unitsize);
|
|
+ devc->sent_samples += num_samples;
|
|
+ processed_samples += num_samples;
|
|
+ }
|
|
+ } else {
|
|
+ trigger_offset = soft_trigger_logic_check(devc->stl,
|
|
+ transfer->buffer + processed_samples * unitsize,
|
|
+ transfer->actual_length - processed_samples * unitsize,
|
|
+ &pre_trigger_samples);
|
|
+ if (trigger_offset > -1) {
|
|
+ std_session_send_df_frame_begin(sdi);
|
|
+ devc->sent_samples += pre_trigger_samples;
|
|
+ num_samples = cur_sample_count - processed_samples - trigger_offset;
|
|
+ if (devc->limit_samples &&
|
|
+ devc->sent_samples + num_samples > devc->limit_samples)
|
|
+ num_samples = devc->limit_samples - devc->sent_samples;
|
|
+
|
|
+ la_send_data_proc(sdi, (uint8_t *)transfer->buffer
|
|
+ + processed_samples * unitsize
|
|
+ + trigger_offset * unitsize,
|
|
+ num_samples * unitsize, unitsize);
|
|
+ devc->sent_samples += num_samples;
|
|
+ processed_samples += trigger_offset + num_samples;
|
|
+
|
|
+ devc->trigger_fired = TRUE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ const int frame_ended = devc->limit_samples && (devc->sent_samples >= devc->limit_samples);
|
|
+ const int final_frame = devc->limit_frames && (devc->num_frames >= (devc->limit_frames - 1));
|
|
+
|
|
+ if (frame_ended) {
|
|
+ devc->num_frames++;
|
|
+ devc->sent_samples = 0;
|
|
+ devc->trigger_fired = FALSE;
|
|
+ std_session_send_df_frame_end(sdi);
|
|
+
|
|
+ /* There may be another trigger in the remaining data, go back and check for it */
|
|
+ if (processed_samples < cur_sample_count) {
|
|
+ /* Reset the trigger stage */
|
|
+ if (devc->stl)
|
|
+ devc->stl->cur_stage = 0;
|
|
+ else {
|
|
+ std_session_send_df_frame_begin(sdi);
|
|
+ devc->trigger_fired = TRUE;
|
|
+ }
|
|
+ if (!final_frame)
|
|
+ goto check_trigger;
|
|
+ }
|
|
+ }
|
|
+ if (frame_ended && final_frame) {
|
|
+ sipeed_slogic_acquisition_stop(sdi);
|
|
+ free_transfer(transfer);
|
|
+ } else
|
|
+ resubmit_transfer(transfer);
|
|
+}
|
|
+
|
|
+#define USB_TIMEOUT 100
|
|
+
|
|
+static int command_start_acquisition(const struct sr_dev_inst *sdi)
|
|
+{
|
|
+ struct dev_context *devc;
|
|
+ struct sr_usb_dev_inst *usb;
|
|
+ uint64_t samplerate;
|
|
+ struct cmd_start_acquisition cmd;
|
|
+ int ret;
|
|
+
|
|
+ devc = sdi->priv;
|
|
+ usb = sdi->conn;
|
|
+ samplerate = devc->cur_samplerate;
|
|
+
|
|
+ /* Compute the sample rate. */
|
|
+ if (0) {
|
|
+ sr_err("Unable to sample at %" PRIu64 "Hz "
|
|
+ "when collecting 16-bit samples.", samplerate);
|
|
+ return SR_ERR;
|
|
+ }
|
|
+
|
|
+ cmd.sample_rate_h = cmd.sample_rate_l = 0;
|
|
+
|
|
+ if ((SR_MHZ(160) % samplerate) != 0) {
|
|
+ sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate);
|
|
+ return SR_ERR;
|
|
+ }
|
|
+
|
|
+ sr_dbg("SLogic samplerate = %d, clocksource = %sMHz.", samplerate, "160");
|
|
+
|
|
+ samplerate /= SR_KHZ(1);
|
|
+ cmd.sample_rate_h = (samplerate >> 8) & 0xff;
|
|
+ cmd.sample_rate_l = samplerate & 0xff;
|
|
+
|
|
+ /* Send the control message. */
|
|
+ ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
|
|
+ LIBUSB_ENDPOINT_OUT, CMD_START, 0x0000, 0x0000,
|
|
+ (unsigned char *)&cmd, sizeof(cmd), USB_TIMEOUT);
|
|
+ if (ret < 0) {
|
|
+ sr_err("Unable to send start command: %s.",
|
|
+ libusb_error_name(ret));
|
|
+ return SR_ERR;
|
|
+ }
|
|
+
|
|
+ return SR_OK;
|
|
+}
|
|
diff --git a/src/hardware/sipeed-slogic-analyzer/protocol.h b/src/hardware/sipeed-slogic-analyzer/protocol.h
|
|
index 84e310870..12f063963 100644
|
|
--- a/src/hardware/sipeed-slogic-analyzer/protocol.h
|
|
+++ b/src/hardware/sipeed-slogic-analyzer/protocol.h
|
|
@@ -28,6 +28,18 @@
|
|
|
|
#define LOG_PREFIX "sipeed-slogic-analyzer"
|
|
|
|
+#define NUM_SIMUL_TRANSFERS 32
|
|
+#define MAX_EMPTY_TRANSFERS (NUM_SIMUL_TRANSFERS * 2)
|
|
+
|
|
+#define DBG_VAL(expr) do {\
|
|
+ __typeof((expr)) _expr = (expr);\
|
|
+ sr_warn("[%u]%s<"#expr"> i:%d\tu:%u\tf:%f\th:%x", __LINE__, __func__, \
|
|
+ *(long*)(&_expr), \
|
|
+ *(unsigned long*)(&_expr), \
|
|
+ *(float*)(&_expr), \
|
|
+ *(unsigned long*)(&_expr)); \
|
|
+}while(0)
|
|
+
|
|
struct slogic_profile {
|
|
uint16_t vid;
|
|
uint16_t pid;
|
|
@@ -36,14 +48,74 @@ struct slogic_profile {
|
|
struct dev_context {
|
|
struct slogic_profile *profile;
|
|
|
|
- uint64_t cur_samplerate;
|
|
uint64_t limit_samples;
|
|
- int logic_pattern;
|
|
+ uint64_t limit_frames;
|
|
+
|
|
+ gboolean acq_aborted;
|
|
+ gboolean trigger_fired;
|
|
+ struct soft_trigger_logic *stl;
|
|
+
|
|
+ uint64_t num_frames;
|
|
+ uint64_t sent_samples;
|
|
+ int submitted_transfers;
|
|
+ int empty_transfer_count;
|
|
+
|
|
+ uint64_t num_transfers;
|
|
+ struct libusb_transfer **transfers;
|
|
+
|
|
+ uint64_t cur_samplerate;
|
|
+ int logic_pattern;
|
|
double voltage_threshold[2];
|
|
/* Triggers */
|
|
uint64_t capture_ratio;
|
|
};
|
|
|
|
+#pragma pack(push, 1)
|
|
+struct cmd_start_acquisition {
|
|
+ uint8_t sample_rate_l;
|
|
+ uint8_t sample_rate_h;
|
|
+};
|
|
+#pragma pack(pop)
|
|
+
|
|
+/* Protocol commands */
|
|
+#define CMD_START 0xb1
|
|
+
|
|
SR_PRIV int sipeed_slogic_analyzer_receive_data(int fd, int revents, void *cb_data);
|
|
+SR_PRIV int sipeed_slogic_acquisition_start(const struct sr_dev_inst *sdi);
|
|
+SR_PRIV int sipeed_slogic_acquisition_stop(struct sr_dev_inst *sdi);
|
|
+
|
|
+static inline size_t to_bytes_per_ms(struct dev_context *devc)
|
|
+{
|
|
+ size_t channel_counts = 1 << (devc->logic_pattern);
|
|
+ return (devc->cur_samplerate * channel_counts)/8/1000;
|
|
+}
|
|
+
|
|
+static inline size_t get_buffer_size(struct dev_context *devc)
|
|
+{
|
|
+ /**
|
|
+ * The buffer should be large enough to hold 10ms of data and
|
|
+ * a multiple of 512.
|
|
+ */
|
|
+ size_t s = 10 * to_bytes_per_ms(devc);
|
|
+ size_t pack_size = 512;
|
|
+ return (s + (pack_size-1)) & ~(pack_size-1);
|
|
+}
|
|
+
|
|
+static inline size_t get_number_of_transfers(struct dev_context *devc)
|
|
+{
|
|
+ /* Total buffer size should be able to hold about 500ms of data. */
|
|
+ size_t n = (500 * to_bytes_per_ms(devc) / get_buffer_size(devc));
|
|
+ if (n > NUM_SIMUL_TRANSFERS)
|
|
+ return NUM_SIMUL_TRANSFERS;
|
|
+ return n;
|
|
+}
|
|
+
|
|
+static inline size_t get_timeout(struct dev_context *devc)
|
|
+{
|
|
+ size_t total_size = get_buffer_size(devc) *
|
|
+ get_number_of_transfers(devc);
|
|
+ size_t timeout = total_size / to_bytes_per_ms(devc);
|
|
+ return timeout + timeout / 4; /* Leave a headroom of 25% percent. */
|
|
+}
|
|
|
|
#endif
|
|
|
|
From 0edddf171de8abb1e662bf5eb9197af34123f098 Mon Sep 17 00:00:00 2001
|
|
From: taorye <taorye@outlook.com>
|
|
Date: Wed, 22 Feb 2023 10:14:24 +0800
|
|
Subject: [PATCH 4/4] feat: now support max 160Msps(2ch)
|
|
|
|
---
|
|
src/hardware/sipeed-slogic-analyzer/api.c | 16 ++++++------
|
|
.../sipeed-slogic-analyzer/protocol.c | 25 ++++++++++---------
|
|
.../sipeed-slogic-analyzer/protocol.h | 1 +
|
|
3 files changed, 23 insertions(+), 19 deletions(-)
|
|
|
|
diff --git a/src/hardware/sipeed-slogic-analyzer/api.c b/src/hardware/sipeed-slogic-analyzer/api.c
|
|
index 4038a6e28..a0aefd962 100644
|
|
--- a/src/hardware/sipeed-slogic-analyzer/api.c
|
|
+++ b/src/hardware/sipeed-slogic-analyzer/api.c
|
|
@@ -60,13 +60,13 @@ static const int32_t trigger_matches[] = {
|
|
};
|
|
|
|
static const uint64_t samplerates[] = {
|
|
- SR_KHZ(20),
|
|
- SR_KHZ(25),
|
|
- SR_KHZ(50),
|
|
- SR_KHZ(100),
|
|
- SR_KHZ(200),
|
|
- SR_KHZ(250),
|
|
- SR_KHZ(500),
|
|
+ // SR_KHZ(20),
|
|
+ // SR_KHZ(25),
|
|
+ // SR_KHZ(50),
|
|
+ // SR_KHZ(100),
|
|
+ // SR_KHZ(200),
|
|
+ // SR_KHZ(250),
|
|
+ // SR_KHZ(500),
|
|
/* 160M = 2*2*2*2*2*5M */
|
|
SR_MHZ(1),
|
|
SR_MHZ(2),
|
|
@@ -79,6 +79,8 @@ static const uint64_t samplerates[] = {
|
|
SR_MHZ(32),
|
|
SR_MHZ(40),
|
|
/* must less than 47MHZ */
|
|
+ SR_MHZ(80),
|
|
+ SR_MHZ(160),
|
|
};
|
|
|
|
static struct sr_dev_driver sipeed_slogic_analyzer_driver_info;
|
|
diff --git a/src/hardware/sipeed-slogic-analyzer/protocol.c b/src/hardware/sipeed-slogic-analyzer/protocol.c
|
|
index f232c25f6..434e3bc5b 100644
|
|
--- a/src/hardware/sipeed-slogic-analyzer/protocol.c
|
|
+++ b/src/hardware/sipeed-slogic-analyzer/protocol.c
|
|
@@ -93,7 +93,7 @@ SR_PRIV int sipeed_slogic_acquisition_start(const struct sr_dev_inst *sdi)
|
|
}
|
|
size_t size = get_buffer_size(devc);
|
|
for (int i = 0; i < devc->num_transfers; i++) {
|
|
- uint8_t *buf = g_try_malloc(size * 8); /* max 8xu1 */
|
|
+ uint8_t *buf = g_try_malloc(size * (8+1)); /* max 8xu1 */
|
|
if (!buf) {
|
|
sr_err("USB transfer buffer malloc failed.");
|
|
return SR_ERR_MALLOC;
|
|
@@ -274,9 +274,10 @@ static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer)
|
|
check_trigger:
|
|
if (real_bits < 8) {
|
|
for (int i = cur_sample_count-1; i>=0; i--) {
|
|
- ((uint8_t *)transfer->buffer)[i] =
|
|
- (((uint8_t *)transfer->buffer)[i/real_bits] >> (real_bits-1-i%real_bits))
|
|
- & ((1<<real_bits)-1);
|
|
+
|
|
+ ((uint8_t *)transfer->buffer+get_buffer_size(devc))[i] =
|
|
+ (((uint8_t *)transfer->buffer)[i/(8/real_bits)] >> (real_bits*(i%(8/real_bits))))
|
|
+ &((1<<real_bits)-1);
|
|
}
|
|
}
|
|
if (devc->trigger_fired) {
|
|
@@ -286,7 +287,7 @@ static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer)
|
|
if (devc->limit_samples && devc->sent_samples + num_samples > devc->limit_samples)
|
|
num_samples = devc->limit_samples - devc->sent_samples;
|
|
|
|
- la_send_data_proc(sdi, (uint8_t *)transfer->buffer
|
|
+ la_send_data_proc(sdi, (uint8_t *)transfer->buffer + (real_bits<8?get_buffer_size(devc):0)
|
|
+ processed_samples * unitsize,
|
|
num_samples * unitsize, unitsize);
|
|
devc->sent_samples += num_samples;
|
|
@@ -305,7 +306,7 @@ static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer)
|
|
devc->sent_samples + num_samples > devc->limit_samples)
|
|
num_samples = devc->limit_samples - devc->sent_samples;
|
|
|
|
- la_send_data_proc(sdi, (uint8_t *)transfer->buffer
|
|
+ la_send_data_proc(sdi, (uint8_t *)transfer->buffer + (real_bits<8?get_buffer_size(devc):0)
|
|
+ processed_samples * unitsize
|
|
+ trigger_offset * unitsize,
|
|
num_samples * unitsize, unitsize);
|
|
@@ -351,13 +352,14 @@ static int command_start_acquisition(const struct sr_dev_inst *sdi)
|
|
{
|
|
struct dev_context *devc;
|
|
struct sr_usb_dev_inst *usb;
|
|
- uint64_t samplerate;
|
|
+ uint64_t samplerate, samplechannel;
|
|
struct cmd_start_acquisition cmd;
|
|
int ret;
|
|
|
|
devc = sdi->priv;
|
|
usb = sdi->conn;
|
|
samplerate = devc->cur_samplerate;
|
|
+ samplechannel = 1<<devc->logic_pattern;
|
|
|
|
/* Compute the sample rate. */
|
|
if (0) {
|
|
@@ -366,18 +368,17 @@ static int command_start_acquisition(const struct sr_dev_inst *sdi)
|
|
return SR_ERR;
|
|
}
|
|
|
|
- cmd.sample_rate_h = cmd.sample_rate_l = 0;
|
|
-
|
|
- if ((SR_MHZ(160) % samplerate) != 0) {
|
|
+ if ((SR_MHZ(160) % samplerate) != 0 || samplechannel * samplerate > 40 * 8 * 1000 * 1000) {
|
|
sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate);
|
|
return SR_ERR;
|
|
}
|
|
|
|
- sr_dbg("SLogic samplerate = %d, clocksource = %sMHz.", samplerate, "160");
|
|
+ sr_dbg("SLogic samplerate(%dch) = %d, clocksource = %sMHz.", samplechannel, samplerate, "160");
|
|
|
|
- samplerate /= SR_KHZ(1);
|
|
+ samplerate /= SR_MHZ(1);
|
|
cmd.sample_rate_h = (samplerate >> 8) & 0xff;
|
|
cmd.sample_rate_l = samplerate & 0xff;
|
|
+ cmd.sample_channel = samplechannel;
|
|
|
|
/* Send the control message. */
|
|
ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
|
|
diff --git a/src/hardware/sipeed-slogic-analyzer/protocol.h b/src/hardware/sipeed-slogic-analyzer/protocol.h
|
|
index 12f063963..92da5f74d 100644
|
|
--- a/src/hardware/sipeed-slogic-analyzer/protocol.h
|
|
+++ b/src/hardware/sipeed-slogic-analyzer/protocol.h
|
|
@@ -74,6 +74,7 @@ struct dev_context {
|
|
struct cmd_start_acquisition {
|
|
uint8_t sample_rate_l;
|
|
uint8_t sample_rate_h;
|
|
+ uint8_t sample_channel;
|
|
};
|
|
#pragma pack(pop)
|
|
|