Hi All

I've attached a patch implementing RLE support in the OLS driver.
This also corrects a problem where repeated data was read if if a
sample count exceeding the hardware buffer was requested.
In this case the returned data is just clipped at the hardware buffer size.

This fixes the problems I was observing with the repeated USB packets.
The RLE support allows me to capture multiple USB frames in one acquisition.

Please try this out and let me know if you have any problems.
You'll need to enable RLE mode with '-d 0:rle=on' on the command line.

Thanks to all the help from everyone on IRC.

Regards,
Gareth

-- 
Black Sphere Technologies Ltd.

Web: www.blacksphere.co.nz
Mobile: +64 27 777 2182
Tel: +64 9 478 8885
Skype: gareth.mcmullin
LinkedIn: http://nz.linkedin.com/in/gsmcmullin
diff --git a/libsigrok/hardware/openbench-logic-sniffer/ols.c b/libsigrok/hardware/openbench-logic-sniffer/ols.c
index e7daa01..f928ed6 100644
--- a/libsigrok/hardware/openbench-logic-sniffer/ols.c
+++ b/libsigrok/hardware/openbench-logic-sniffer/ols.c
@@ -51,6 +51,7 @@ static int capabilities[] = {
 	SR_HWCAP_SAMPLERATE,
 	SR_HWCAP_CAPTURE_RATIO,
 	SR_HWCAP_LIMIT_SAMPLES,
+	SR_HWCAP_RLE,
 	0,
 };
 
@@ -592,6 +593,9 @@ static int hw_set_configuration(int device_index, int capability, void *value)
 		tmp_u64 = value;
 		if (*tmp_u64 < MIN_NUM_SAMPLES)
 			return SR_ERR;
+		if (*tmp_u64 > ols->max_samples) 
+			sr_warn("ols: sample limit exceeds hw max");
+
 		ols->limit_samples = *tmp_u64;
 		sr_info("ols: sample limit %" PRIu64, ols->limit_samples);
 		ret = SR_OK;
@@ -605,6 +609,13 @@ static int hw_set_configuration(int device_index, int capability, void *value)
 		} else
 			ret = SR_OK;
 		break;
+	case SR_HWCAP_RLE:
+		if(strcmp(value, "on") == 0) {
+			sr_info("ols: enabling RLE");
+			ols->flag_reg |= FLAG_RLE;
+		}
+		ret = SR_OK;
+		break;
 	default:
 		ret = SR_ERR;
 	}
@@ -619,8 +630,8 @@ static int receive_data(int fd, int revents, void *session_data)
 	struct sr_device_instance *sdi;
 	struct ols_device *ols;
 	GSList *l;
-	int count, buflen, num_channels, offset, i, j;
-	unsigned char byte, *buffer;
+	int num_channels, offset, i, j;
+	unsigned char byte;
 
 	/* find this device's ols_device struct by its fd */
 	ols = NULL;
@@ -660,52 +671,41 @@ static int receive_data(int fd, int revents, void *session_data)
 			num_channels++;
 	}
 
-	if (revents == G_IO_IN
-	    && ols->num_transfers / num_channels <= ols->limit_samples) {
+	if (revents == G_IO_IN) {
 		if (serial_read(fd, &byte, 1) != 1)
 			return FALSE;
 
+		/* Ignore it if we've read enough */
+	    	if(ols->num_samples >= ols->limit_samples) 
+			return TRUE; 
+
 		ols->sample[ols->num_bytes++] = byte;
 		sr_dbg("ols: received byte 0x%.2x", byte);
 		if (ols->num_bytes == num_channels) {
 			/* Got a full sample. */
 			sr_dbg("ols: received sample 0x%.*x",
-			       ols->num_bytes * 2, (int) *ols->sample);
+			       ols->num_bytes * 2, *(int*)ols->sample);
 			if (ols->flag_reg & FLAG_RLE) {
 				/*
 				 * In RLE mode -1 should never come in as a
 				 * sample, because bit 31 is the "count" flag.
-				 * TODO: Endianness may be wrong here, could be
-				 * sample[3].
 				 */
-				if (ols->sample[0] & 0x80
-				    && !(ols->last_sample[0] & 0x80)) {
-					count = (int)(*ols->sample) & 0x7fffffff;
-					if (!(buffer = g_try_malloc(count))) {
-						sr_err("ols: %s: buffer malloc "
-						       "failed", __func__);
-						return FALSE;
-					}
-
-					buflen = 0;
-					for (i = 0; i < count; i++) {
-						memcpy(buffer + buflen, ols->last_sample, 4);
-						buflen += 4;
-					}
-				} else {
-					/*
-					 * Just a single sample, next sample
-					 * will probably be a count referring
-					 * to this -- but this one is still a
-					 * part of the stream.
+				if (ols->sample[ols->num_bytes - 1] & 0x80) {
+					ols->sample[ols->num_bytes - 1] &= 0x7F;
+					/* FIXME: This will only work on 
+					 * little-endian systems 
 					 */
-					buffer = ols->sample;
-					buflen = 4;
-				}
-			} else {
-				/* No compression. */
-				buffer = ols->sample;
-				buflen = 4;
+					ols->rle_count = *(int*)(ols->sample);
+					sr_dbg("ols: RLE count = %d", ols->rle_count);
+					ols->num_bytes = 0;
+					return TRUE;
+				} 
+			}
+			ols->num_samples += ols->rle_count + 1;
+			if(ols->num_samples > ols->limit_samples) {
+				/* Save us from overrunning the buffer */
+				ols->rle_count -= ols->num_samples - ols->limit_samples;
+				ols->num_samples = ols->limit_samples;
 			}
 
 			if (num_channels < 4) {
@@ -731,23 +731,20 @@ static int receive_data(int fd, int revents, void *session_data)
 					}
 				}
 				memcpy(ols->sample, ols->tmp_sample, 4);
-				sr_dbg("ols: full sample 0x%.8x", (int) *ols->sample);
+				sr_dbg("ols: full sample 0x%.8x", *(int*)ols->sample);
 			}
 
 			/* the OLS sends its sample buffer backwards.
 			 * store it in reverse order here, so we can dump
 			 * this on the session bus later.
 			 */
-			offset = (ols->limit_samples - ols->num_transfers / num_channels) * 4;
-			memcpy(ols->raw_sample_buf + offset, ols->sample, 4);
-
-			if (buffer == ols->sample)
-				memcpy(ols->last_sample, buffer, num_channels);
-			else
-				g_free(buffer);
+			offset = (ols->limit_samples - ols->num_samples) * 4;
+			for(i = 0; i <= ols->rle_count; i++)
+				memcpy(ols->raw_sample_buf + offset + (i*4), ols->sample, 4);
 
 			memset(ols->sample, 0, 4);
 			ols->num_bytes = 0;
+			ols->rle_count = 0;
 		}
 	} else {
 		/*
@@ -767,7 +764,8 @@ static int receive_data(int fd, int revents, void *session_data)
 				packet.payload = &logic;
 				logic.length = ols->trigger_at * 4;
 				logic.unitsize = 4;
-				logic.data = ols->raw_sample_buf;
+				logic.data = ols->raw_sample_buf + 
+					(ols->limit_samples - ols->num_samples) * 4;
 				sr_session_bus(session_data, &packet);
 			}
 
@@ -780,21 +778,23 @@ static int receive_data(int fd, int revents, void *session_data)
 			/* send post-trigger samples */
 			packet.type = SR_DF_LOGIC;
 			packet.timeoffset = ols->trigger_at * ols->period_ps;
-			packet.duration = (ols->limit_samples - ols->trigger_at) * ols->period_ps;
+			packet.duration = (ols->num_samples - ols->trigger_at) * ols->period_ps;
 			packet.payload = &logic;
-			logic.length = (ols->limit_samples * 4) - (ols->trigger_at * 4);
+			logic.length = (ols->num_samples * 4) - (ols->trigger_at * 4);
 			logic.unitsize = 4;
-			logic.data = ols->raw_sample_buf + ols->trigger_at * 4;
+			logic.data = ols->raw_sample_buf + ols->trigger_at * 4 +
+					(ols->limit_samples - ols->num_samples) * 4;
 			sr_session_bus(session_data, &packet);
 		} else {
 			/* no trigger was used */
 			packet.type = SR_DF_LOGIC;
 			packet.timeoffset = 0;
-			packet.duration = ols->limit_samples * ols->period_ps;
+			packet.duration = ols->num_samples * ols->period_ps;
 			packet.payload = &logic;
-			logic.length = ols->limit_samples * 4;
+			logic.length = ols->num_samples * 4;
 			logic.unitsize = 4;
-			logic.data = ols->raw_sample_buf;
+			logic.data = ols->raw_sample_buf +
+					(ols->limit_samples - ols->num_samples) * 4;
 			sr_session_bus(session_data, &packet);
 		}
 		g_free(ols->raw_sample_buf);
@@ -802,7 +802,7 @@ static int receive_data(int fd, int revents, void *session_data)
 		serial_flush(fd);
 		serial_close(fd);
 		packet.type = SR_DF_END;
-		packet.timeoffset = ols->limit_samples * ols->period_ps;
+		packet.timeoffset = ols->num_samples * ols->period_ps;
 		packet.duration = 0;
 		sr_session_bus(session_data, &packet);
 	}
@@ -820,6 +820,7 @@ static int hw_start_acquisition(int device_index, gpointer session_data)
 	uint32_t data;
 	uint16_t readcount, delaycount;
 	uint8_t changrp_mask;
+	int num_channels;
 	int i;
 
 	if (!(sdi = sr_get_device_instance(device_instances, device_index)))
@@ -830,7 +831,20 @@ static int hw_start_acquisition(int device_index, gpointer session_data)
 	if (sdi->status != SR_ST_ACTIVE)
 		return SR_ERR;
 
-	readcount = ols->limit_samples / 4;
+	/*
+	 * Enable/disable channel groups in the flag register according to the
+	 * probe mask.
+	 */
+	changrp_mask = 0;
+	num_channels = 0;
+	for (i = 0; i < 4; i++) {
+		if (ols->probe_mask & (0xff << (i * 8))) {
+			changrp_mask |= (1 << i);
+			num_channels++;
+		}
+	}
+
+	readcount = MIN(ols->max_samples / num_channels, ols->limit_samples) / 4;
 
 	memset(trigger_config, 0, 16);
 	trigger_config[ols->num_stages - 1] |= 0x08;
@@ -903,20 +917,11 @@ static int hw_start_acquisition(int device_index, gpointer session_data)
 	if (send_longcommand(sdi->serial->fd, CMD_CAPTURE_SIZE, reverse16(data)) != SR_OK)
 		return SR_ERR;
 
-	/*
-	 * Enable/disable channel groups in the flag register according to the
-	 * probe mask.
-	 */
-	changrp_mask = 0;
-	for (i = 0; i < 4; i++) {
-		if (ols->probe_mask & (0xff << (i * 8)))
-			changrp_mask |= (1 << i);
-	}
-
 	/* The flag register wants them here, and 1 means "disable channel". */
 	ols->flag_reg |= ~(changrp_mask << 2) & 0x3c;
 	ols->flag_reg |= FLAG_FILTER;
-	data = ols->flag_reg << 24;
+	ols->rle_count = 0;
+	data = (ols->flag_reg << 24) | ((ols->flag_reg << 8) & 0xff0000);
 	if (send_longcommand(sdi->serial->fd, CMD_SET_FLAGS, data) != SR_OK)
 		return SR_ERR;
 
diff --git a/libsigrok/hardware/openbench-logic-sniffer/ols.h b/libsigrok/hardware/openbench-logic-sniffer/ols.h
index e6afd0e..a954605 100644
--- a/libsigrok/hardware/openbench-logic-sniffer/ols.h
+++ b/libsigrok/hardware/openbench-logic-sniffer/ols.h
@@ -82,8 +82,9 @@ struct ols_device {
 	int num_stages;
 
 	unsigned int num_transfers;
+	unsigned int num_samples;
+	int rle_count;
 	int num_bytes;
-	char last_sample[4];
 	unsigned char sample[4];
 	unsigned char tmp_sample[4];
 	unsigned char *raw_sample_buf;
diff --git a/libsigrok/hwplugin.c b/libsigrok/hwplugin.c
index 33ff79d..f3401dc 100644
--- a/libsigrok/hwplugin.c
+++ b/libsigrok/hwplugin.c
@@ -39,6 +39,7 @@ struct sr_hwcap_option sr_hwcap_options[] = {
 	{SR_HWCAP_SAMPLERATE, SR_T_UINT64, "Sample rate", "samplerate"},
 	{SR_HWCAP_CAPTURE_RATIO, SR_T_UINT64, "Pre-trigger capture ratio", "captureratio"},
 	{SR_HWCAP_PATTERN_MODE, SR_T_CHAR, "Pattern generator mode", "patternmode"},
+	{SR_HWCAP_RLE, SR_T_CHAR, "Run Length Encoding", "rle"},
 	{0, 0, NULL, NULL},
 };
 
diff --git a/libsigrok/sigrok.h b/libsigrok/sigrok.h
index c362983..b3ca41a 100644
--- a/libsigrok/sigrok.h
+++ b/libsigrok/sigrok.h
@@ -255,6 +255,9 @@ enum {
 	/** The device supports setting a pattern (pattern generator mode). */
 	SR_HWCAP_PATTERN_MODE,
 
+	/** The device supports Run Length Encoding. */
+	SR_HWCAP_RLE,
+
 	/*--- Special stuff -------------------------------------------------*/
 
 	/* TODO: Better description. */
------------------------------------------------------------------------------
Get your Android app more play: Bring it to the BlackBerry PlayBook 
in minutes. BlackBerry App World&#153; now supports Android&#153; Apps 
for the BlackBerry&reg; PlayBook&#153;. Discover just how easy and simple 
it is! http://p.sf.net/sfu/android-dev2dev
_______________________________________________
sigrok-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sigrok-devel

Reply via email to