sysclk-lwla: Streamline packet output logic.

(process_sample_data): When expanding run-length samples into
session packets, calculate the number of samples to write in
advance while honoring all constraints.  This is cleaner than
checking constraints within the expansion loop.  Also, the new
logic always fills up packets exactly to whatever limit applies
first, thereby removing the need for truncation after the fact.
This commit is contained in:
Daniel Elstner 2014-01-18 17:36:23 +01:00
parent 29d587670d
commit 2cfd16a316
2 changed files with 48 additions and 63 deletions

View File

@ -238,8 +238,8 @@ static void issue_read_start(const struct sr_dev_inst *sdi)
acq->mem_addr_next = 4;
acq->mem_addr_stop = acq->mem_addr_fill;
/* Byte offset into the packet output buffer. */
acq->out_offset = 0;
/* Sample position in the packet output buffer. */
acq->out_index = 0;
regvals = devc->reg_write_seq;
@ -434,49 +434,6 @@ static void request_read_mem(const struct sr_dev_inst *sdi)
}
}
/* Send a packet of logic samples to the session bus. The payload is taken
* from the acquisition state. The return value indicates whether to stop
* reading more samples.
*/
static gboolean send_logic_packet(const struct sr_dev_inst *sdi)
{
uint64_t samples;
struct dev_context *devc;
struct acquisition_state *acq;
struct sr_datafeed_packet packet;
struct sr_datafeed_logic logic;
int last;
devc = sdi->priv;
acq = devc->acquisition;
if (acq->samples_done >= acq->samples_max)
return TRUE;
packet.type = SR_DF_LOGIC;
packet.payload = &logic;
logic.unitsize = UNIT_SIZE;
logic.data = acq->out_packet;
logic.length = acq->out_offset;
samples = acq->out_offset / UNIT_SIZE;
last = FALSE;
/* Cut the packet short if necessary. */
if (acq->samples_done + samples >= acq->samples_max) {
samples = acq->samples_max - acq->samples_done;
logic.length = samples * UNIT_SIZE;
last = TRUE;
}
acq->samples_done += samples;
acq->out_offset = 0;
/* Send off logic datafeed packet. */
sr_session_send(sdi, &packet);
return last;
}
/* Demangle and decompress incoming sample data from the capture buffer.
* The data chunk is taken from the acquisition state, and is expected to
* contain a multiple of 8 device words.
@ -487,15 +444,19 @@ static gboolean send_logic_packet(const struct sr_dev_inst *sdi)
static int process_sample_data(const struct sr_dev_inst *sdi)
{
uint64_t sample;
uint64_t run_len;
uint64_t high_nibbles;
uint64_t word;
struct dev_context *devc;
struct acquisition_state *acq;
uint8_t *out_p;
uint16_t *slice;
struct sr_datafeed_packet packet;
struct sr_datafeed_logic logic;
size_t expect_len;
size_t actual_len;
size_t out_max_samples;
size_t out_run_samples;
size_t ri;
size_t in_words_left;
size_t si;
@ -518,27 +479,49 @@ static int process_sample_data(const struct sr_dev_inst *sdi)
return SR_ERR;
}
acq->mem_addr_done += in_words_left;
/* Prepare session packet. */
packet.type = SR_DF_LOGIC;
packet.payload = &logic;
logic.unitsize = UNIT_SIZE;
logic.data = acq->out_packet;
slice = acq->xfer_buf_in;
si = 0; /* word index within slice */
for (;;) {
sample = acq->sample;
/* Calculate number of samples to write into packet. */
out_max_samples = MIN(acq->samples_max - acq->samples_done,
PACKET_LENGTH - acq->out_index);
out_run_samples = MIN(acq->run_len, out_max_samples);
/* Expand run-length samples into session packet. */
for (run_len = acq->run_len; run_len > 0; --run_len) {
out_p = &acq->out_packet[acq->out_offset];
sample = acq->sample;
out_p = &acq->out_packet[acq->out_index * UNIT_SIZE];
for (ri = 0; ri < out_run_samples; ++ri) {
out_p[0] = sample & 0xFF;
out_p[1] = (sample >> 8) & 0xFF;
out_p[2] = (sample >> 16) & 0xFF;
out_p[3] = (sample >> 24) & 0xFF;
out_p[4] = (sample >> 32) & 0xFF;
acq->out_offset += UNIT_SIZE;
/* Send out packet if it is full. */
if (acq->out_offset > PACKET_SIZE - UNIT_SIZE)
if (send_logic_packet(sdi))
return SR_OK; /* sample limit reached */
out_p += UNIT_SIZE;
}
acq->run_len -= out_run_samples;
acq->out_index += out_run_samples;
acq->samples_done += out_run_samples;
/* Packet full or sample count limit reached? */
if (out_run_samples == out_max_samples) {
logic.length = acq->out_index * UNIT_SIZE;
sr_session_send(sdi, &packet);
acq->out_index = 0;
if (acq->samples_done >= acq->samples_max)
return SR_OK; /* sample limit reached */
if (acq->run_len > 0)
continue; /* need another packet */
}
acq->run_len = 0;
if (in_words_left == 0)
break; /* done with current chunk */
@ -566,10 +549,12 @@ static int process_sample_data(const struct sr_dev_inst *sdi)
--in_words_left;
}
/* Send out partially filled packet if it is the last one. */
if (acq->mem_addr_done >= acq->mem_addr_stop && acq->out_offset > 0)
send_logic_packet(sdi);
/* Send out partially filled packet if this was the last chunk. */
if (acq->mem_addr_done >= acq->mem_addr_stop && acq->out_index > 0) {
logic.length = acq->out_index * UNIT_SIZE;
sr_session_send(sdi, &packet);
acq->out_index = 0;
}
return SR_OK;
}

View File

@ -44,7 +44,7 @@
/** Unit and packet size for the sigrok logic datafeed.
*/
#define UNIT_SIZE ((NUM_PROBES + 7) / 8)
#define PACKET_SIZE (10000 * UNIT_SIZE) /* bytes */
#define PACKET_LENGTH 10000 /* units */
/** Size of the acquisition buffer in device memory units.
*/
@ -158,7 +158,7 @@ struct acquisition_state {
size_t mem_addr_next;
size_t mem_addr_stop;
size_t out_offset;
size_t out_index;
struct libusb_transfer *xfer_in;
struct libusb_transfer *xfer_out;
@ -175,7 +175,7 @@ struct acquisition_state {
uint16_t xfer_buf_in[MAX_ACQ_RECV_WORDS];
/* Payload buffer for sigrok logic packets. */
uint8_t out_packet[PACKET_SIZE];
uint8_t out_packet[PACKET_LENGTH * UNIT_SIZE];
};
/** Private, per-device-instance driver context.