Skip to content

Add Sipeed SLogic Analyzer Driver Support#275

Open
taorye wants to merge 22 commits intosigrokproject:masterfrom
sipeed:slogic-dev
Open

Add Sipeed SLogic Analyzer Driver Support#275
taorye wants to merge 22 commits intosigrokproject:masterfrom
sipeed:slogic-dev

Conversation

@taorye
Copy link

@taorye taorye commented Oct 13, 2025

This pull request adds support for the Sipeed SLogic series logic analyzers (SLogic Combo8, SLogic16U3) to libsigrok. Key changes include:

  • Integration of a new driver for Sipeed SLogic analyzers, with new source files: src/hardware/sipeed-slogic-analyzer/{api.c, protocol.c, protocol.h}.
  • Addition of udev rules for Sipeed devices in contrib/60-libsigrok.rules (vendor ID 0x359f, product IDs 0x0300 and 0x3031).
  • Driver supports device detection, configuration, sampling rates, channel selection, and acquisition control for SLogic Combo 8 and SLogic16U3 models.

This contribution enables libsigrok to work with Sipeed SLogic logic analyzers, broadening hardware compatibility.

@taorye
Copy link
Author

taorye commented Oct 13, 2025

This pull request is the third submission (see previous: #212, #262) for integrating support for the Sipeed SLogic series logic analyzers into libsigrok. The prior two PRs were interrupted before merging; this version has been fully refactored and thoroughly validated.

The driver has been thoroughly tested and confirmed to work correctly on Windows, Linux, and macOS platforms!

We sincerely invite everyone to pull and test this branch! Your feedback and suggestions are highly appreciated—we are committed to responding actively and working together to further improve this integration.

@PetteriAimonen
Copy link
Contributor

I'm not qualified to give a real OK for this code, but in reading it through it appears well designed and easy to understand.

@Krakonos
Copy link

Hi! @PetteriAimonen Thanks for looking at it. I'm actually surprised how short and easy the driver is. I've received SLogic Combo8 yesterday, I plan to have a look at the driver over the weekend.

@Krakonos Krakonos self-assigned this Nov 15, 2025
@weilking
Copy link

@Krakonos I manage to compile libsigrok with @taorye's pull request. Both PulseView and sigrok-cli can successfully detect the Slogic Combo8. However, there seems to be a limitation with the sampling rate. Using the default rate of 40M consistently results in a timeout error.
image
After lowering the sampling rate to 20M, data collection works correctly.
image

I haven’t encountered this issue with the PulseView version provided on Sipeed’s website.

@Krakonos
Copy link

@weilking Interesting. I've been using the SLogic Combo 8 for a bit here to work on a project and didn't find any issues so far. Just to be sure, i retested at 40MHz and can sample for pretty long runs without any issues (tested up to 1G at 40MHz). However, I'm running linux. I wonder if this relates to the issues discussed in PRs #242 and #235 ?

@Krakonos
Copy link

@weilking Just noticed the timeout is over a million seconds timeout. That is suspicious. Just to check, are you building a 64bit version of sigrok?

@Krakonos
Copy link

Ok, I'm now able to reproduce something. Maybe similar. I took some doing:

sr: [03:12.955130] hwdriver: sr_config_get(): key 30000 (samplerate) sdi 0x555cb61d81f0 cg NULL -> uint64 160000000
sr: [03:12.955199] session: Creating our own main context.
sr: [03:12.955230] session: Starting.
sr: [03:12.955254] hwdriver: sipeed-slogic-analyzer: Starting acquisition.
sr: [03:13.055603] sipeed-slogic-analyzer: Cleared EP: 0x81
sr: [03:13.055652] sipeed-slogic-analyzer: Need 100000000x 2ch@160MHz in 625ms.
sr: [03:13.055723] sipeed-slogic-analyzer: Train: receive 10027008 bytes per 250ms...
sr: [03:13.057805] sipeed-slogic-analyzer: Choose: receive 2506752 bytes per 62ms :)
sr: [03:13.063808] sipeed-slogic-analyzer: Submited 10 transfers
sr: [03:13.063839] session: bus: Received SR_DF_HEADER packet.
sr: [03:13.063864] session: bus: Received SR_DF_FRAME_BEGIN packet.
sr: [03:13.063905] sipeed-slogic-analyzer: slogic_usb_control_write: req:177 value:0 index:0 0x7fc086f87a45:3 in 500ms.
sr: [03:13.063926] sipeed-slogic-analyzer: slogic_usb_control_write: Align up to 4(from 3)!
sr: [03:13.219120] sipeed-slogic-analyzer: [1] Transfer #0 status: 2(LIBUSB_TRANSFER_TIMED_OUT).
sr: [03:13.219133] sipeed-slogic-analyzer: [1] Got 425472/25000000(1.70%) => speed: 2.75MBps, 2.75MBps(avg) => +154.586=154.586ms.
sr: [03:13.219359] sipeed-slogic-analyzer: Resubmit transfer: 0x7fc074bf57b0
sr: [03:13.223691] session: bus: Received SR_DF_LOGIC packet (1701888 bytes, unitsize = 1).
sr: [03:13.300203] sipeed-slogic-analyzer: [2] Transfer #1 status: 2(LIBUSB_TRANSFER_TIMED_OUT).
sr: [03:13.300217] sipeed-slogic-analyzer: [2] Got 425472/25000000(1.70%) => speed: 0.00MBps, 1.81MBps(avg) => +81.085=235.671ms.
sr: [03:13.300232] session: bus: Received SR_DF_LOGIC packet (0 bytes, unitsize = 1).
WARNING: Received logic packet with 0 samples.
sr: [03:13.300488] sipeed-slogic-analyzer: Resubmit transfer: 0x7fc0742656f0
sr: [03:13.381675] sipeed-slogic-analyzer: [3] Transfer #2 status: 2(LIBUSB_TRANSFER_TIMED_OUT).
sr: [03:13.381691] sipeed-slogic-analyzer: [3] Got 425472/25000000(1.70%) => speed: 0.00MBps, 1.34MBps(avg) => +81.471=317.142ms.
sr: [03:13.381880] session: bus: Received SR_DF_LOGIC packet (0 bytes, unitsize = 1).
WARNING: Received logic packet with 0 samples.

... And the last 5 lines basically repeat forever until I cancel manually the transfer (using pulseview).

I had to set up buffer size 2 and sample rate to 160MHz. Enough samples need to be taken. It work up to 1Msamples and a bit, 10Msamples reliably fails on my regular USB hub. However, it works fine plugged directly into the root hub. A classic.

Now, I think it's fine the transfer fails due to not enough bandwidth, however I think it should do so more gracefully.

@taorye Can you check this out? While I don't see this as a show stopper, since a lot of analyzers fail due to not enough bandwidth. However, what is weird (at least in my case above) is that the code still tries to read more data, it just doesn't receive any and loops forever.

@PetteriAimonen
Copy link
Contributor

Libusb has had performance issues on Windows for a long time now. At least at some point, sigrok was using a patched libusb for Windows builds.

It would be worth it to compare the libusb-1.0.dll versions between the working and not-working build. The Windows properties window should show the version information.

@Krakonos
Copy link

@PetteriAimonen I see. Do you mean the RAW_IO patch?

After looking into a chain of rejected patches, it seems this summer one was finally merged:

libusb/libusb#1512 , merged in commit:
libusb/libusb@3dac3f2

This would be a nice addition if somebody wanted to contribute to the windows support.

@weilking
Copy link

weilking commented Nov 30, 2025

@weilking Just noticed the timeout is over a million seconds timeout. That is suspicious. Just to check, are you building a 64bit version of sigrok?

Libsigrok was built with x86_64.
The issue disappears after switching usb driver from WinUSB to libusb-win 1.x
Could be related with the libusb1 version used in build tool chain. my docker was freshly built with latest mxe, which contains libusb 1.0.20-rc3-event-abstraction-v4. The patch of libusb RAW_IO patch is included.

@tykosa
Copy link

tykosa commented Dec 9, 2025

I received my Slogic16U3 today and have built this version of libsigrok to use with it.
If there are any testing steps needed to help get this PR merged I am happy to assist.

I primarilly run on Linux Mint, but also have access to Fedora and Windows 11.

I have been noticing on my inital tests that running the device at higher sample rates and higher numbers of samples is causing data to get stretched, seems to only be a problem at 800 MHz and with multiple channels enabled. If I drop down to 1 channel from 2 it gets more reliable.

sr: sipeed-slogic-analyzer: Timeout 15.510ms!!! Reach duration limit: 9.100(7+30.0%), 2537.132 > 2111.200(1631+30.0%)(total) except first one. I am seeing some of these errors in the terminal logs.

Please let me know any ways I can help this project!

@Krakonos
Copy link

@tykosa I wonder if you tested with the last two fixed pushed by the author? Reading those I think they might be related.

@Mixaill
Copy link

Mixaill commented Dec 14, 2025

@taorye

Aside from a lot of GCC warnings (signed vs. unsigned comparisons, printf formatting), there’s one serious issue that prevents building on openSUSE OBS: slogic16U3_remote_test_mode() doesn’t return a value on all code paths.

Patch

diff --git a/src/hardware/sipeed-slogic-analyzer/api.c b/src/hardware/sipeed-slogic-analyzer/api.c
index 90224259f..a39681b43 100644
--- a/src/hardware/sipeed-slogic-analyzer/api.c
+++ b/src/hardware/sipeed-slogic-analyzer/api.c
@@ -903,6 +903,8 @@ static int slogic16U3_remote_test_mode(const struct sr_dev_inst *sdi, uint32_t m
 			sr_dbg("Succeed to configure test_mode.");
 		}
 	}
+
+	return SR_OK;
 }
 
 static int slogic16U3_remote_reset(const struct sr_dev_inst *sdi) {

@Mixaill
Copy link

Mixaill commented Dec 14, 2025

@taorye

  1. PATTERN_MODE_TEST_MAX_SPEED does not show anything, maybe just hide it?
image
  1. PATTERN_MODE_NOMAL contains a typo, it should be NORMAL.
    Also, probably, it is better to use human-readable names.

Patch

diff --git a/src/hardware/sipeed-slogic-analyzer/api.c b/src/hardware/sipeed-slogic-analyzer/api.c
index a39681b43..5b05c950a 100644
--- a/src/hardware/sipeed-slogic-analyzer/api.c
+++ b/src/hardware/sipeed-slogic-analyzer/api.c
@@ -123,10 +123,9 @@ static const uint64_t limit_samplerates_slogic16u3[] =
 #endif
 
 static const char *patterns[] = {
-	[PATTERN_MODE_NOMAL] = "PATTERN_MODE_NOMAL",
-	[PATTERN_MODE_TEST_MAX_SPEED] = "PATTERN_MODE_TEST_MAX_SPEED",
-	[PATTERN_MODE_TEST_HARDWARE_USB_MAX_SPEED] = "PATTERN_MODE_TEST_HARDWARE_USB_MAX_SPEED",
-	[PATTERN_MODE_TEST_HARDWARE_EMU_DATA] = "PATTERN_MODE_TEST_HARDWARE_EMU_DATA",
+	[PATTERN_MODE_NORMAL] = "Normal",
+	[PATTERN_MODE_TEST_HARDWARE_USB_MAX_SPEED] = "USB connection test",
+	[PATTERN_MODE_TEST_HARDWARE_EMU_DATA] = "Emulation",
 };
 
 static const int32_t trigger_matches[] = {
@@ -254,7 +253,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
 				devc->cur_samplechannel =
 					devc->limit_samplechannel;
 				devc->cur_samplerate = devc->limit_samplerate;
-				devc->cur_pattern_mode_idx = PATTERN_MODE_NOMAL;
+				devc->cur_pattern_mode_idx = PATTERN_MODE_NORMAL;
 				devc->voltage_threshold[0] =
 					devc->voltage_threshold[1] = 1.7f;
 
@@ -492,7 +491,7 @@ static int config_set(uint32_t key, GVariant *data,
 			sr_warn("unsupported model: %s.", devc->model->name);
 			break;
 		}
-		if (devc->cur_pattern_mode_idx == PATTERN_MODE_NOMAL) {
+		if (devc->cur_pattern_mode_idx == PATTERN_MODE_NORMAL) {
 			if (devc->model->operation.remote_reset)
 				devc->model->operation.remote_reset(sdi);
 			slogic16U3_remote_test_mode(sdi, 0x0);
diff --git a/src/hardware/sipeed-slogic-analyzer/protocol.c b/src/hardware/sipeed-slogic-analyzer/protocol.c
index f48b926b8..0ebb87145 100644
--- a/src/hardware/sipeed-slogic-analyzer/protocol.c
+++ b/src/hardware/sipeed-slogic-analyzer/protocol.c
@@ -91,8 +91,7 @@ static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer)
 		       (double)transfers_all_duration / SR_KHZ(1));
 
 		/* TODO: move out submit to ensure continuous transfers */
-		if (devc->raw_data_queue &&
-		    devc->cur_pattern_mode_idx != PATTERN_MODE_TEST_MAX_SPEED) {
+		if (devc->raw_data_queue) {
 			uint8_t *d = transfer->buffer;
 			size_t len = transfer->actual_length;
 			// sr_dbg("HEAD: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x
diff --git a/src/hardware/sipeed-slogic-analyzer/protocol.h b/src/hardware/sipeed-slogic-analyzer/protocol.h
index 6a5e279e3..9e8f387d4 100644
--- a/src/hardware/sipeed-slogic-analyzer/protocol.h
+++ b/src/hardware/sipeed-slogic-analyzer/protocol.h
@@ -36,8 +36,7 @@
 #define TRANSFERS_DURATION_TOLERANCE 0.3f
 
 enum {
-	PATTERN_MODE_NOMAL,
-	PATTERN_MODE_TEST_MAX_SPEED,
+	PATTERN_MODE_NORMAL,
 	PATTERN_MODE_TEST_HARDWARE_USB_MAX_SPEED,
 	PATTERN_MODE_TEST_HARDWARE_EMU_DATA,
 };

After
image

@Mixaill
Copy link

Mixaill commented Dec 14, 2025

@taorye

Buffer size SR_CONF_BUFFERSIZE probably should be SR_CONF_NUM_LOGIC_CHANNELS
image

Nevermind, Pulseview does not provide gui for SR_CONF_NUM_LOGIC_CHANNELS

@Mixaill
Copy link

Mixaill commented Dec 14, 2025

@taorye

the default 1.7V threshold does not display because of float accuracy (probably it is better to use integer millivolts inside?)

Before

image

Patch

diff --git a/src/hardware/sipeed-slogic-analyzer/api.c b/src/hardware/sipeed-slogic-analyzer/api.c
index 5b05c950a..737a53a17 100644
--- a/src/hardware/sipeed-slogic-analyzer/api.c
+++ b/src/hardware/sipeed-slogic-analyzer/api.c
@@ -255,7 +255,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
 				devc->cur_samplerate = devc->limit_samplerate;
 				devc->cur_pattern_mode_idx = PATTERN_MODE_NORMAL;
 				devc->voltage_threshold[0] =
-					devc->voltage_threshold[1] = 1.7f;
+					devc->voltage_threshold[1] = 1.7000000000000004;
 
 				devc->digital_group =
 					sr_channel_group_new(sdi, "LA", NULL);
@@ -334,7 +334,8 @@ static int dev_open(struct sr_dev_inst *sdi)
 	if (devc->model->operation.remote_reset)
 		devc->model->operation.remote_reset(sdi);
 
-	devc->voltage_threshold[0] = devc->voltage_threshold[1] = 1.6f;
+	devc->voltage_threshold[0] = devc->voltage_threshold[1] = 1.7000000000000004;
+
 	sr_config_set(sdi, NULL, SR_CONF_VOLTAGE_THRESHOLD,
 				g_variant_new("(dd)", &devc->voltage_threshold[0],
 			      &devc->voltage_threshold[1]));

After

image

@Mixaill
Copy link

Mixaill commented Dec 14, 2025

@taorye

The one big remaining issue is that you can enable more channels that specified in buffer_size and have garbage in channel_num >= buffer_size.

Patch

diff --git a/src/hardware/sipeed-slogic-analyzer/api.c b/src/hardware/sipeed-slogic-analyzer/api.c
index 737a53a17..798a0025d 100644
--- a/src/hardware/sipeed-slogic-analyzer/api.c
+++ b/src/hardware/sipeed-slogic-analyzer/api.c
@@ -465,14 +465,10 @@ static int config_set(uint32_t key, GVariant *data,
 			for (GSList *l = devc->digital_group->channels; l;
 			     l = l->next) {
 				struct sr_channel *ch = l->data;
-				if (ch->type ==
-				    SR_CHANNEL_LOGIC) { /* Might as well do this now, these
+				if (ch->type == 
+					SR_CHANNEL_LOGIC) { /* Might as well do this now, these
                                                are static. */
-					sr_dev_channel_enable(
-						ch, (ch->index >=
-						     devc->cur_samplechannel) ?
-							    FALSE :
-							    TRUE);
+					ch->enabled = ch->index >= devc->cur_samplechannel ? FALSE : TRUE;
 				} else {
 					sr_warn("devc->digital_group->channels[%u] is not Logic?",
 						ch->index);
@@ -517,6 +513,42 @@ static int config_set(uint32_t key, GVariant *data,
 	return ret;
 }
 
+int config_channel_set(const struct sr_dev_inst *sdi, struct sr_channel *ch, unsigned int changes) {
+	struct dev_context *devc = sdi ? (sdi->priv) : NULL;
+	if(!devc || !devc->model || !devc->model->samplechannel_table || !devc->model->limit_samplerate_table){
+		return SR_ERR;
+	}
+	
+	if(changes != SR_CHANNEL_SET_ENABLED){
+		return SR_OK;
+	}
+	
+	uint64_t new_samplechannel = devc->model->samplechannel_table[0];
+	for (GSList *l = devc->digital_group->channels; l;l = l->next) {
+		struct sr_channel *ch = l->data;
+		if(!ch->enabled || ch->index < new_samplechannel){
+			continue;
+		}
+		for(unsigned int i = 0; i < devc->model->samplerate_table_size; i++){
+			if(devc->model->samplechannel_table[i] > ch->index){
+				new_samplechannel = devc->model->samplechannel_table[i];
+				break;
+			}
+		}
+	}
+
+	if(new_samplechannel > devc->cur_samplechannel){
+		devc->cur_samplechannel = new_samplechannel;
+		devc->limit_samplerate = devc->model->limit_samplerate_table[
+				std_i32_idx(g_variant_new_int32(devc->cur_samplechannel),
+					devc->model->samplechannel_table, devc->model->samplechannel_table_size)
+			];
+		if (devc->cur_samplerate > devc->limit_samplerate)
+			devc->cur_samplerate = devc->limit_samplerate;
+	}
+	return SR_OK;
+}
+
 static int config_list(uint32_t key, GVariant **data,
 		       const struct sr_dev_inst *sdi,
 		       const struct sr_channel_group *cg)
@@ -572,6 +604,7 @@ static struct sr_dev_driver sipeed_slogic_analyzer_driver_info = {
 	.scan = scan,
 	.dev_list = std_dev_list,
 	.dev_clear = std_dev_clear,
+	.config_channel_set = config_channel_set,
 	.config_get = config_get,
 	.config_set = config_set,
 	.config_list = config_list,

So, now if you have buffersize==4 and trying to enable channel_idx=13 it automatically switches buffersize to 16.

@Mixaill
Copy link

Mixaill commented Dec 14, 2025

Buffer size SR_CONF_BUFFERSIZE probably should be SR_CONF_NUM_LOGIC_CHANNELS image

Nevermind, Pulseview does not provide gui for SR_CONF_NUM_LOGIC_CHANNELS

Okay, better we fix pulseview

Patch 1, fix int32_t support

diff --git a/src/libsigrok-internal.h b/src/libsigrok-internal.h
index 8d509eba6..7acd7557e 100644
--- a/src/libsigrok-internal.h
+++ b/src/libsigrok-internal.h
@@ -1958,6 +1958,7 @@ SR_PRIV GVariant *std_gvar_array_str(const char *a[], unsigned int n);
 SR_PRIV GVariant *std_gvar_thresholds(const double a[][2], unsigned int n);
 
 SR_PRIV int std_str_idx(GVariant *data, const char *a[], unsigned int n);
+SR_PRIV int std_i32_idx(GVariant *data, const int32_t a[], unsigned int n);
 SR_PRIV int std_u64_idx(GVariant *data, const uint64_t a[], unsigned int n);
 SR_PRIV int std_u8_idx(GVariant *data, const uint8_t a[], unsigned int n);
 
diff --git a/src/std.c b/src/std.c
index 959d00056..8917c7ebd 100644
--- a/src/std.c
+++ b/src/std.c
@@ -787,8 +787,10 @@ static int find_in_array(GVariant *data, const GVariantType *type,
 	const char *s;
 	const uint64_t *u64arr;
 	const uint8_t *u8arr;
+	const int32_t *i32arr;
 	uint64_t u64;
 	uint8_t u8;
+	int32_t i32;
 	unsigned int i;
 
 	if (!g_variant_is_of_type(data, type))
@@ -803,6 +805,14 @@ static int find_in_array(GVariant *data, const GVariantType *type,
 			if (!strcmp(s, sarr[i]))
 				return i;
 		break;
+	case G_VARIANT_CLASS_INT32:
+		i32 = g_variant_get_int32(data);
+		i32arr = arr;
+
+		for (i = 0; i < n; i++)
+			if (i32 == i32arr[i])
+				return i;
+		break;
 	case G_VARIANT_CLASS_UINT64:
 		u64 = g_variant_get_uint64(data);
 		u64arr = arr;
@@ -830,6 +840,11 @@ SR_PRIV int std_str_idx(GVariant *data, const char *a[], unsigned int n)
 	return find_in_array(data, G_VARIANT_TYPE_STRING, a, n);
 }
 
+SR_PRIV int std_i32_idx(GVariant *data, const int32_t a[], unsigned int n)
+{
+	return find_in_array(data, G_VARIANT_TYPE_INT32, a, n);
+}
+
 SR_PRIV int std_u64_idx(GVariant *data, const uint64_t a[], unsigned int n)
 {
 	return find_in_array(data, G_VARIANT_TYPE_UINT64, a, n);

Patch 2, switch to SR_CONF_NUM_LOGIC_CHANNELS

diff --git a/src/hardware/sipeed-slogic-analyzer/api.c b/src/hardware/sipeed-slogic-analyzer/api.c
index 798a0025d..d736e380f 100644
--- a/src/hardware/sipeed-slogic-analyzer/api.c
+++ b/src/hardware/sipeed-slogic-analyzer/api.c
@@ -34,12 +34,12 @@ static const uint32_t drvopts[] = {
 
 static const uint32_t devopts[] = {
 	SR_CONF_CONTINUOUS,
-	SR_CONF_BUFFERSIZE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
 	SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
 	SR_CONF_PATTERN_MODE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
 	SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
 	SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
 	SR_CONF_VOLTAGE_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+	SR_CONF_NUM_LOGIC_CHANNELS | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST
 };
 
 static const uint64_t samplerates_slogiccombo8[] = {
@@ -65,7 +65,7 @@ static const uint64_t samplerates_slogiccombo8[] = {
 	SR_MHZ(160),
 };
 
-static const uint64_t samplechannels_slogiccombo8[] = { 2, 4, 8 };
+static const int32_t samplechannels_slogiccombo8[] = { 2, 4, 8 };
 static const uint64_t limit_samplerates_slogiccombo8[] = { SR_MHZ(160), SR_MHZ(80), SR_MHZ(40) };
 
 static const uint64_t samplerates_slogic16u3[] = {
@@ -114,7 +114,7 @@ static const uint64_t samplerates_slogic16u3[] = {
 	// SR_MHZ(1500),
 };
 
-static const uint64_t samplechannels_slogic16u3[] = { /*2, */4, 8, 16 };
+static const int32_t samplechannels_slogic16u3[] = { /*2, */4, 8, 16 };
 static const uint64_t limit_samplerates_slogic16u3[] = 
 #ifdef _WIN32
 	{ /*SR_MHZ(1500), */SR_MHZ(400), SR_MHZ(200), SR_MHZ(100) };
@@ -246,7 +246,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
 				devc->limit_samplechannel = devc->model->samplechannel_table[
 					devc->model->samplechannel_table_size - 1];
 				devc->limit_samplerate = devc->model->limit_samplerate_table[
-					std_u64_idx(g_variant_new_uint64(devc->limit_samplechannel),
+					std_i32_idx(g_variant_new_int32(devc->limit_samplechannel),
 						devc->model->samplechannel_table, devc->model->samplechannel_table_size)
 				];
 
@@ -396,8 +396,8 @@ static int config_get(uint32_t key, GVariant **data,
 	case SR_CONF_SAMPLERATE:
 		*data = g_variant_new_uint64(devc->cur_samplerate);
 		break;
-	case SR_CONF_BUFFERSIZE:
-		*data = g_variant_new_uint64(devc->cur_samplechannel);
+	case SR_CONF_NUM_LOGIC_CHANNELS:
+		*data = g_variant_new_int32(devc->cur_samplechannel);
 		break;
 	case SR_CONF_PATTERN_MODE:
 		*data = g_variant_new_string(
@@ -444,16 +444,16 @@ static int config_set(uint32_t key, GVariant *data,
 		}
 
 		break;
-	case SR_CONF_BUFFERSIZE:
-		if (std_u64_idx(data, devc->model->samplechannel_table, devc->model->samplechannel_table_size) < 0) {
+	case SR_CONF_NUM_LOGIC_CHANNELS:
+		if (std_i32_idx(data, devc->model->samplechannel_table, devc->model->samplechannel_table_size) < 0) {
 			devc->cur_samplechannel = devc->limit_samplechannel;
 			sr_warn("Reach limit or not supported, wrap to %uch.",
 				devc->limit_samplechannel);
 		} else {
-			devc->cur_samplechannel = g_variant_get_uint64(data);
+			devc->cur_samplechannel = g_variant_get_int32(data);
 
 			devc->limit_samplerate = devc->model->limit_samplerate_table[
-				std_u64_idx(g_variant_new_uint64(devc->cur_samplechannel),
+				std_i32_idx(g_variant_new_int32(devc->cur_samplechannel),
 					devc->model->samplechannel_table, devc->model->samplechannel_table_size)
 			];
 
@@ -523,7 +523,7 @@ int config_channel_set(const struct sr_dev_inst *sdi, struct sr_channel *ch, uns
 		return SR_OK;
 	}
 	
-	uint64_t new_samplechannel = devc->model->samplechannel_table[0];
+	int32_t new_samplechannel = devc->model->samplechannel_table[0];
 	for (GSList *l = devc->digital_group->channels; l;l = l->next) {
 		struct sr_channel *ch = l->data;
 		if(!ch->enabled || ch->index < new_samplechannel){
@@ -576,8 +576,8 @@ static int config_list(uint32_t key, GVariant **data,
 		if (NULL == devc->model)
 			ret = SR_ERR_ARG;
 		break;
-	case SR_CONF_BUFFERSIZE:
-		*data = std_gvar_array_u64(devc->model->samplechannel_table, devc->model->samplechannel_table_size);
+	case SR_CONF_NUM_LOGIC_CHANNELS:
+		*data = std_gvar_array_i32(devc->model->samplechannel_table, devc->model->samplechannel_table_size);
 		break;
 	case SR_CONF_PATTERN_MODE:
 		*data = g_variant_new_strv(ARRAY_AND_SIZE(patterns));
diff --git a/src/hardware/sipeed-slogic-analyzer/protocol.h b/src/hardware/sipeed-slogic-analyzer/protocol.h
index 9e8f387d4..b39a75926 100644
--- a/src/hardware/sipeed-slogic-analyzer/protocol.h
+++ b/src/hardware/sipeed-slogic-analyzer/protocol.h
@@ -46,7 +46,7 @@ struct slogic_model {
 	const uint16_t pid;
 	const uint8_t ep_in;
 	const uint64_t max_bandwidth; // limit by hardware
-	const uint64_t *samplechannel_table;
+	const int32_t *samplechannel_table;
 	const uint64_t samplechannel_table_size;
 	const uint64_t *limit_samplerate_table;
 	const uint64_t *samplerate_table;
@@ -67,13 +67,13 @@ struct dev_context {
 
 	struct {
 		uint64_t limit_samplerate;
-		uint64_t limit_samplechannel;
+		int32_t limit_samplechannel;
 	};
 
 	struct {
 		uint64_t cur_limit_samples;
 		uint64_t cur_samplerate;
-		uint64_t cur_samplechannel;
+		int32_t cur_samplechannel;
 		int64_t cur_pattern_mode_idx;
 	}; // configuration

@Mixaill
Copy link

Mixaill commented Dec 14, 2025

@taorye

It should be working perfectly fine with the following PulseView changes ( sigrokproject/pulseview#111 )

  • It fixes interface lags on configuration change
  • and also enables logic channels selector (which is not really needed because it is enough to enable only first 4/8 channels to switch the mode)
image

you can grab commits here (should be equal to comments in this PR, but prefer git version anyway):

sipeed-slogic-analyzer: Add support for SlogicCombo8

feat: use pattern to control active channels

feat: capture data and regroup channels

feat: now support max 160Msps(2ch)

continous and multi channel

sipeed-slogic-analyzer: Add support for SlogicBasic16U3

sipeed-slogic-analyzer: feat: use SR_CONF_BUFFERSIZE to configurate the channel

sipeed-slogic-analyzer: feat: at least 2 transfers are pending in parallel, and evaluate transfer latency, also fix cancel_transfer must be handled

sipeed-slogic-analyzer: feat: attempt to use function pointers to maintain compatibility with Lite 8

sipeed-slogic-analyzer: fix: slogic lite 8 use ep(0x81)

sipeed-slogic-analyzer: fix: stop while has no transfers submitted

sipeed-slogic-analyzer: fix: skip sending real stop command for slogic lite 8

sipeed-slogic-analyzer: fix: libusb_handle_events at right time,  use `%%` and start from 125ms

sipeed-slogic-analyzer: fix: transfers not consumed from the end, so just use NUM_MAX_TRANSFERS instead of num_transfers_used

sipeed-slogic-analyzer: chore: add udev rules for slogic

sipeed-slogic-analyzer: feat: support sample rate and channel configuration

sipeed-slogic-analyzer: feat: separate sr_session_send(sdi, &packet) from receive_transfer handler to ensure usb work continuously

sipeed-slogic-analyzer: feat: switch back to 5% tolerance and use a continuous count to determine real timeout

sipeed-slogic-analyzer: refactor: simplify and reuse data packet format

sipeed-slogic-analyzer: perf: use GThread for raw_data_handle to not distrub handle_events

sipeed-slogic-analyzer: fix: aux length starts from bit9 and try to split control write in 4 bytes

sipeed-slogic-analyzer: feat: add samplerate configuration support

sipeed-slogic-analyzer: fix: select updated samplerate base

sipeed-slogic-analyzer: fix: use 4MiB size transfers default to clear previously generated EP data

sipeed-slogic-analyzer: refactor: consolidate data submission logic by using `slogic_submit_raw_data`

Replace multiple data submission implementations with the common
`slogic_submit_raw_data` function to maintain consistency and reduce
code duplication.

sipeed-slogic-analyzer: Prepare for upstream submission

* Implement USB streaming thread isolation
  - Decouples raw data processing from libusb transfers callback
  - Enables stable 200MHz sampling (16ch) on SlogicBasic16U3 (max bandwidth: up to 430 MiB/s on test)

* Windows-specific enhancements
  - Resolves USB scheduling bottleneck
  - Support stable 40MHz sampling (8ch) on SlogicCombo8
  - Verified on Win10/Win11 platforms (VMs included)

Co-authored-by: Shenzhen Sipeed Team <support@sipeed.com>
Co-authored-by: taorye <hongtao@sipeed.com, taorye@outlook.com>

sipeed-slogic-analyzer: fix: standardize product name to "SLogic16U3"

sipeed-slogic-analyzer: refactor: lift per_transfer_nbytes enumeration into a separate function

fix: use libusb_handle_events after to free transfer that submitted in `train_bulk_in_transfer`

feat: support to set vref

feat: support adjust vref

fix: handle libusb_event in a dedicated thread after opening usb device, and set LIBUSB_TRANSFER_FREE_BUFFER. Ensure all transfers can be freed.

feat: support test on patten selected

tmp: stop sampling after all transfers are freed

fix: update samplerates and voltage threshold calculations; handle acquisition abort correctly

fix: implement soft trigger logic and manage trigger state in acquisition
@taorye
Copy link
Author

taorye commented Dec 17, 2025

@Mixaill

Thank you for your contribution! Your patch has been merged into our fork, and we truly appreciate the time and effort you put into improving the project. Great work!

@taorye
Copy link
Author

taorye commented Dec 17, 2025

I received my Slogic16U3 today and have built this version of libsigrok to use with it. If there are any testing steps needed to help get this PR merged I am happy to assist.

I primarilly run on Linux Mint, but also have access to Fedora and Windows 11.

I have been noticing on my inital tests that running the device at higher sample rates and higher numbers of samples is causing data to get stretched, seems to only be a problem at 800 MHz and with multiple channels enabled. If I drop down to 1 channel from 2 it gets more reliable.

sr: sipeed-slogic-analyzer: Timeout 15.510ms!!! Reach duration limit: 9.100(7+30.0%), 2537.132 > 2111.200(1631+30.0%)(total) except first one. I am seeing some of these errors in the terminal logs.

Please let me know any ways I can help this project!

@tykosa

When operating at the full bandwidth of 3.2 Gbps, data loss may occur due to certain USB SuperSpeed host drivers failing to retrieve data in a timely manner, resulting in insufficient effective bandwidth. Therefore:

  1. Use a host machine that has been verified to stably operate at lower bandwidths.
  2. Reduce or avoid usage scenarios that saturate the full bandwidth.

@PetteriAimonen
Copy link
Contributor

Regarding bandwidths and data loss, the real constraint is probably the amount of buffer space available and host latency spikes. Even if the host could transfer e.g. 3 Gbps from a disk drive just fine, it may be unable to do the same with SLogic.

I think SLogic has about 64 kB of buffer memory? Therefore to operate at 3.2 Gbps, the host must start new transfers within 160 µs. If the host has larger latency peaks, for example 1 ms, the available bandwidth drops to 0.5 Gbps. It's unfortunate that the available bandwidth drops very quicky for even small amounts of extra latency.

fix: add a timeout mechanism that stops acquisition if no data is received for several consecutive transfers
@taorye
Copy link
Author

taorye commented Dec 17, 2025

Ok, I'm now able to reproduce something. Maybe similar. I took some doing:

sr: [03:12.955130] hwdriver: sr_config_get(): key 30000 (samplerate) sdi 0x555cb61d81f0 cg NULL -> uint64 160000000
sr: [03:12.955199] session: Creating our own main context.
sr: [03:12.955230] session: Starting.
sr: [03:12.955254] hwdriver: sipeed-slogic-analyzer: Starting acquisition.
sr: [03:13.055603] sipeed-slogic-analyzer: Cleared EP: 0x81
sr: [03:13.055652] sipeed-slogic-analyzer: Need 100000000x 2ch@160MHz in 625ms.
sr: [03:13.055723] sipeed-slogic-analyzer: Train: receive 10027008 bytes per 250ms...
sr: [03:13.057805] sipeed-slogic-analyzer: Choose: receive 2506752 bytes per 62ms :)
sr: [03:13.063808] sipeed-slogic-analyzer: Submited 10 transfers
sr: [03:13.063839] session: bus: Received SR_DF_HEADER packet.
sr: [03:13.063864] session: bus: Received SR_DF_FRAME_BEGIN packet.
sr: [03:13.063905] sipeed-slogic-analyzer: slogic_usb_control_write: req:177 value:0 index:0 0x7fc086f87a45:3 in 500ms.
sr: [03:13.063926] sipeed-slogic-analyzer: slogic_usb_control_write: Align up to 4(from 3)!
sr: [03:13.219120] sipeed-slogic-analyzer: [1] Transfer #0 status: 2(LIBUSB_TRANSFER_TIMED_OUT).
sr: [03:13.219133] sipeed-slogic-analyzer: [1] Got 425472/25000000(1.70%) => speed: 2.75MBps, 2.75MBps(avg) => +154.586=154.586ms.
sr: [03:13.219359] sipeed-slogic-analyzer: Resubmit transfer: 0x7fc074bf57b0
sr: [03:13.223691] session: bus: Received SR_DF_LOGIC packet (1701888 bytes, unitsize = 1).
sr: [03:13.300203] sipeed-slogic-analyzer: [2] Transfer #1 status: 2(LIBUSB_TRANSFER_TIMED_OUT).
sr: [03:13.300217] sipeed-slogic-analyzer: [2] Got 425472/25000000(1.70%) => speed: 0.00MBps, 1.81MBps(avg) => +81.085=235.671ms.
sr: [03:13.300232] session: bus: Received SR_DF_LOGIC packet (0 bytes, unitsize = 1).
WARNING: Received logic packet with 0 samples.
sr: [03:13.300488] sipeed-slogic-analyzer: Resubmit transfer: 0x7fc0742656f0
sr: [03:13.381675] sipeed-slogic-analyzer: [3] Transfer #2 status: 2(LIBUSB_TRANSFER_TIMED_OUT).
sr: [03:13.381691] sipeed-slogic-analyzer: [3] Got 425472/25000000(1.70%) => speed: 0.00MBps, 1.34MBps(avg) => +81.471=317.142ms.
sr: [03:13.381880] session: bus: Received SR_DF_LOGIC packet (0 bytes, unitsize = 1).
WARNING: Received logic packet with 0 samples.

... And the last 5 lines basically repeat forever until I cancel manually the transfer (using pulseview).

I had to set up buffer size 2 and sample rate to 160MHz. Enough samples need to be taken. It work up to 1Msamples and a bit, 10Msamples reliably fails on my regular USB hub. However, it works fine plugged directly into the root hub. A classic.

Now, I think it's fine the transfer fails due to not enough bandwidth, however I think it should do so more gracefully.

@taorye Can you check this out? While I don't see this as a show stopper, since a lot of analyzers fail due to not enough bandwidth. However, what is weird (at least in my case above) is that the code still tries to read more data, it just doesn't receive any and loops forever.

@Krakonos

The infinite loop bug has been fixed in this PR. Thanks for testing!

@Krakonos
Copy link

Hi All,

thanks for all the work done in this PR (and especially to @weilking and @taorye). I'll do a second pass sometime during the holidays. In the meantime, I wonder if you have the protocol documented somewhere? It's all in the code, but it is somewhat hard to extract the exact protocol and impossible to fully check if the code implements it well.


static const struct slogic_model support_models[] = {
{
.name = "Sogic Combo 8",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@taorye Thank's for your work getting the support upstreamed.

I think there is a small typo here. I don't know whether this warrants a separate commit though.

Suggested change
.name = "Sogic Combo 8",
.name = "SLogic Combo 8",

@Krakonos
Copy link

Hi!

I've done more testing on the PR and found it seems to fix the main issues. I have a couple of reservations:

  • sigrok-cli cannot use higher sample frequencies, even when only one or two channels are specificed. This seems to work with pulseview (using the patched branch). I don't see a way to propagate the NUM_LOGIC_CHANNELS through the CLI.
  • The driver claims support for voltage thresholds, but they seem to be not supported. I'm not sure if anything can be done there, since the driver is shared. Perhaps we could at least send a single-element list for the Combo8?
  • On startup, there are some warning messages printed:
sr: hwdriver: sipeed-slogic-analyzer: Device instance not active, can't set config.
sr: std: sipeed-slogic-analyzer: std_opts_config_list: sdi/cg != NULL: not handling.
sr: std: sipeed-slogic-analyzer: std_opts_config_list: sdi/cg != NULL: not handling.

I don't see an issue with these, but if this is expected and handled properly, I suggest those to be dropped to dbg level.

  • slogic_usb_control_write triggers the up-alignment path, but this sends up to 3 uninitialized (potentially junk) bytes to the device. This may or may not be problem for the device, depending on how it parses the data. Perhaps we should make this an error and pad all the command bytes in the struct definition?
  • The Sogic typo should be fixed.

Overall, I don't see any more issues. I will reiterate it would be nice to have more documentation besides the code itself on how the communication protocol works if possible. Even if it's couple of comments in the driver.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants