static int capture_setup(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
+ struct acquisition_state *acq;
uint64_t divider_count;
uint64_t memory_limit;
uint16_t command[3 + 10*4];
devc = sdi->priv;
+ acq = devc->acquisition;
command[0] = LWLA_WORD(CMD_CAP_SETUP);
command[1] = LWLA_WORD(0); /* address */
* 100 MHz. At the highest samplerate of 125 MHz the clock divider
* is bypassed.
*/
- if (devc->cur_clock_source == CLOCK_SOURCE_INT
- && devc->samplerate > 0
- && devc->samplerate < SR_MHZ(100))
+ if (!acq->bypass_clockdiv && devc->samplerate > 0)
divider_count = SR_MHZ(100) / devc->samplerate - 1;
else
divider_count = 0;
acq->sample = 0;
acq->run_len = 0;
- acq->captured_samples = 0;
- acq->transferred_samples = 0;
+ acq->samples_done = 0;
/* For some reason, the start address is 4 rather than 0. */
acq->mem_addr_done = 4;
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;
static void process_capture_status(const struct sr_dev_inst *sdi)
{
uint64_t duration;
- uint64_t timescale;
struct dev_context *devc;
struct acquisition_state *acq;
acq->capture_flags = LWLA_READ32(&acq->xfer_buf_in[16])
& STATUS_FLAG_MASK;
- /* The 125 MHz setting is special, and uses the same timebase
- * for the duration field as the 100 MHz setting.
+ /* The LWLA1034 runs at 125 MHz if the clock divider is bypassed.
+ * However, the time base used for the duration is apparently not
+ * adjusted for this "boost" mode. Whereas normally the duration
+ * unit is 1 ms, it is 0.8 ms when the clock divider is bypassed.
+ * As 0.8 = 100 MHz / 125 MHz, it seems that the internal cycle
+ * counter period is the same as at the 100 MHz setting.
*/
- timescale = MIN(devc->samplerate, SR_MHZ(100));
- acq->captured_samples = duration * timescale / 1000;
+ if (acq->bypass_clockdiv)
+ acq->duration_now = duration * 4 / 5;
+ else
+ acq->duration_now = duration;
- sr_spew("Captured %lu words, %" PRIu64 " samples, flags 0x%02X",
- (unsigned long)acq->mem_addr_fill,
- acq->captured_samples, acq->capture_flags);
+ sr_spew("Captured %zu words, %" PRIu64 " ms, flags 0x%02X",
+ acq->mem_addr_fill, acq->duration_now, acq->capture_flags);
- if (acq->captured_samples >= devc->limit_samples) {
+ if (acq->duration_now >= acq->duration_max) {
issue_stop_capture(sdi);
return;
}
}
}
-/* 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->transferred_samples >= devc->limit_samples)
- 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->transferred_samples + samples >= devc->limit_samples) {
- samples = devc->limit_samples - acq->transferred_samples;
- logic.length = samples * UNIT_SIZE;
- last = TRUE;
- }
- acq->transferred_samples += 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.
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;
acq = devc->acquisition;
if (acq->mem_addr_done >= acq->mem_addr_stop
- || acq->transferred_samples >= devc->limit_samples)
+ || acq->samples_done >= acq->samples_max)
return SR_OK;
in_words_left = MIN(acq->mem_addr_stop - acq->mem_addr_done,
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 */
--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;
}
case STATE_READ_RESPONSE:
if (process_sample_data(sdi) == SR_OK
&& acq->mem_addr_next < acq->mem_addr_stop
- && acq->transferred_samples < devc->limit_samples)
+ && acq->samples_done < acq->samples_max)
request_read_mem(sdi);
else
issue_read_end(sdi);
{
struct dev_context *devc;
struct sr_usb_dev_inst *usb;
+ struct acquisition_state *acq;
struct regval_pair regvals[7];
int ret;
- gboolean bypass;
devc = sdi->priv;
usb = sdi->conn;
+ acq = devc->acquisition;
+
+ /* By default, run virtually unlimited. */
+ acq->duration_max = (devc->limit_msec > 0)
+ ? devc->limit_msec : MAX_LIMIT_MSEC;
+ acq->samples_max = (devc->limit_samples > 0)
+ ? devc->limit_samples : MAX_LIMIT_SAMPLES;
+
+ switch (devc->cur_clock_source) {
+ case CLOCK_SOURCE_INT:
+ if (devc->samplerate == 0)
+ return SR_ERR_BUG;
+ /* At 125 MHz, the clock divider is bypassed. */
+ acq->bypass_clockdiv = (devc->samplerate > SR_MHZ(100));
+
+ /* If only one of the limits is set, derive the other one. */
+ if (devc->limit_msec == 0 && devc->limit_samples > 0)
+ acq->duration_max = devc->limit_samples
+ * 1000 / devc->samplerate + 1;
+ else if (devc->limit_samples == 0 && devc->limit_msec > 0)
+ acq->samples_max = devc->limit_msec
+ * devc->samplerate / 1000;
+ break;
+ case CLOCK_SOURCE_EXT_FALL:
+ case CLOCK_SOURCE_EXT_RISE:
+ acq->bypass_clockdiv = TRUE;
+ break;
+ default:
+ sr_err("No valid clock source has been configured.");
+ return SR_ERR;
+ }
regvals[0].reg = REG_MEM_CTRL2;
regvals[0].val = 2;
regvals[5].reg = REG_CMD_CTRL1;
regvals[5].val = 0;
- switch (devc->cur_clock_source) {
- case CLOCK_SOURCE_INT:
- bypass = (devc->samplerate > SR_MHZ(100));
- break;
- case CLOCK_SOURCE_EXT_FALL:
- case CLOCK_SOURCE_EXT_RISE:
- bypass = TRUE;
- break;
- default:
- bypass = FALSE;
- break;
- }
regvals[6].reg = REG_DIV_BYPASS;
- regvals[6].val = bypass;
+ regvals[6].val = acq->bypass_clockdiv;
ret = lwla_write_regs(usb, regvals, G_N_ELEMENTS(regvals));
if (ret != SR_OK)
usb = sdi->conn;
acq = devc->acquisition;
+ acq->duration_now = 0;
+
libusb_fill_bulk_transfer(acq->xfer_out, usb->devhdl, EP_COMMAND,
(unsigned char *)acq->xfer_buf_out, 0,
&receive_transfer_out,