soft-trigger: Add support for pre-triggering.

This commit is contained in:
Aurelien Jacobs 2014-11-25 12:23:34 +01:00
parent bc96d5f08f
commit fe5a735553
8 changed files with 91 additions and 13 deletions

View File

@ -361,7 +361,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi,
/* Configure triggers & send header packet */ /* Configure triggers & send header packet */
if ((trigger = sr_session_trigger_get(sdi->session))) { if ((trigger = sr_session_trigger_get(sdi->session))) {
devc->stl = soft_trigger_logic_new(sdi, trigger); devc->stl = soft_trigger_logic_new(sdi, trigger, 0);
devc->trigger_fired = FALSE; devc->trigger_fired = FALSE;
} else } else
devc->trigger_fired = TRUE; devc->trigger_fired = TRUE;

View File

@ -67,9 +67,7 @@ SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data)
} else { } else {
/* Check for trigger */ /* Check for trigger */
trigger_offset = soft_trigger_logic_check(devc->stl, trigger_offset = soft_trigger_logic_check(devc->stl,
logic.data, logic.data, packetsize, NULL);
packetsize);
if (trigger_offset > -1) { if (trigger_offset > -1) {
trigger_offset *= logic.unitsize; trigger_offset *= logic.unitsize;
logic.length = MIN(packetsize - trigger_offset, logic.length = MIN(packetsize - trigger_offset,

View File

@ -567,7 +567,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
devc->empty_transfer_count = 0; devc->empty_transfer_count = 0;
if ((trigger = sr_session_trigger_get(sdi->session))) { if ((trigger = sr_session_trigger_get(sdi->session))) {
devc->stl = soft_trigger_logic_new(sdi, trigger); devc->stl = soft_trigger_logic_new(sdi, trigger, 0);
devc->trigger_fired = FALSE; devc->trigger_fired = FALSE;
} else } else
devc->trigger_fired = TRUE; devc->trigger_fired = TRUE;

View File

@ -458,7 +458,7 @@ SR_PRIV void fx2lafw_receive_transfer(struct libusb_transfer *transfer)
} }
} else { } else {
trigger_offset = soft_trigger_logic_check(devc->stl, trigger_offset = soft_trigger_logic_check(devc->stl,
transfer->buffer, transfer->actual_length); transfer->buffer, transfer->actual_length, NULL);
if (trigger_offset > -1) { if (trigger_offset > -1) {
packet.type = SR_DF_LOGIC; packet.type = SR_DF_LOGIC;
packet.payload = &logic; packet.payload = &logic;

View File

@ -719,7 +719,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
memset(devc->channel_data, 0, sizeof(devc->channel_data)); memset(devc->channel_data, 0, sizeof(devc->channel_data));
if ((trigger = sr_session_trigger_get(sdi->session))) { if ((trigger = sr_session_trigger_get(sdi->session))) {
devc->stl = soft_trigger_logic_new(sdi, trigger); devc->stl = soft_trigger_logic_new(sdi, trigger, 0);
devc->trigger_fired = FALSE; devc->trigger_fired = FALSE;
} else } else
devc->trigger_fired = TRUE; devc->trigger_fired = TRUE;

View File

@ -785,7 +785,7 @@ SR_PRIV void logic16_receive_transfer(struct libusb_transfer *transfer)
devc->sent_samples += new_samples; devc->sent_samples += new_samples;
} else { } else {
trigger_offset = soft_trigger_logic_check(devc->stl, trigger_offset = soft_trigger_logic_check(devc->stl,
devc->convbuffer, new_samples * 2); devc->convbuffer, new_samples * 2, NULL);
if (trigger_offset > -1) { if (trigger_offset > -1) {
packet.type = SR_DF_LOGIC; packet.type = SR_DF_LOGIC;
packet.payload = &logic; packet.payload = &logic;

View File

@ -646,13 +646,18 @@ struct soft_trigger_logic {
int unitsize; int unitsize;
int cur_stage; int cur_stage;
uint8_t *prev_sample; uint8_t *prev_sample;
uint8_t *pre_trigger_buffer;
uint8_t *pre_trigger_head;
int pre_trigger_size;
int pre_trigger_fill;
}; };
SR_PRIV struct soft_trigger_logic *soft_trigger_logic_new( SR_PRIV struct soft_trigger_logic *soft_trigger_logic_new(
const struct sr_dev_inst *sdi, struct sr_trigger *trigger); const struct sr_dev_inst *sdi, struct sr_trigger *trigger,
int pre_trigger_samples);
SR_PRIV void soft_trigger_logic_free(struct soft_trigger_logic *st); SR_PRIV void soft_trigger_logic_free(struct soft_trigger_logic *st);
SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *st, uint8_t *buf, SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *st, uint8_t *buf,
int len); int len, int *pre_trigger_samples);
/*--- hardware/serial.c -----------------------------------------------------*/ /*--- hardware/serial.c -----------------------------------------------------*/

View File

@ -26,7 +26,8 @@
/* @endcond */ /* @endcond */
SR_PRIV struct soft_trigger_logic *soft_trigger_logic_new( SR_PRIV struct soft_trigger_logic *soft_trigger_logic_new(
const struct sr_dev_inst *sdi, struct sr_trigger *trigger) const struct sr_dev_inst *sdi, struct sr_trigger *trigger,
int pre_trigger_samples)
{ {
struct soft_trigger_logic *stl; struct soft_trigger_logic *stl;
@ -35,16 +36,83 @@ SR_PRIV struct soft_trigger_logic *soft_trigger_logic_new(
stl->trigger = trigger; stl->trigger = trigger;
stl->unitsize = (g_slist_length(sdi->channels) + 7) / 8; stl->unitsize = (g_slist_length(sdi->channels) + 7) / 8;
stl->prev_sample = g_malloc0(stl->unitsize); stl->prev_sample = g_malloc0(stl->unitsize);
stl->pre_trigger_size = stl->unitsize * pre_trigger_samples;
stl->pre_trigger_buffer = g_malloc(stl->pre_trigger_size);
stl->pre_trigger_head = stl->pre_trigger_buffer;
if (stl->pre_trigger_size > 0 && stl->pre_trigger_buffer == NULL) {
soft_trigger_logic_free(stl);
return NULL;
}
return stl; return stl;
} }
SR_PRIV void soft_trigger_logic_free(struct soft_trigger_logic *stl) SR_PRIV void soft_trigger_logic_free(struct soft_trigger_logic *stl)
{ {
g_free(stl->pre_trigger_buffer);
g_free(stl->prev_sample); g_free(stl->prev_sample);
g_free(stl); g_free(stl);
} }
static void pre_trigger_append(struct soft_trigger_logic *stl,
uint8_t *buf, int len)
{
/* Avoid uselessly copying more than the pre-trigger size. */
if (len > stl->pre_trigger_size) {
buf += len - stl->pre_trigger_size;
len = stl->pre_trigger_size;
}
/* Update the filling level of the pre-trigger circular buffer. */
stl->pre_trigger_fill = MIN(stl->pre_trigger_fill + len,
stl->pre_trigger_size);
/* Actually copy data to the pre-trigger circular buffer. */
while (len > 0) {
size_t size = MIN(stl->pre_trigger_buffer + stl->pre_trigger_size
- stl->pre_trigger_head, len);
memcpy(stl->pre_trigger_head, buf, size);
stl->pre_trigger_head += size;
if (stl->pre_trigger_head >= stl->pre_trigger_buffer
+ stl->pre_trigger_size)
stl->pre_trigger_head = stl->pre_trigger_buffer;
buf += size;
len -= size;
}
}
static void pre_trigger_send(struct soft_trigger_logic *stl,
int *pre_trigger_samples)
{
struct sr_datafeed_packet packet;
struct sr_datafeed_logic logic;
packet.type = SR_DF_LOGIC;
packet.payload = &logic;
logic.unitsize = stl->unitsize;
if (pre_trigger_samples)
*pre_trigger_samples = 0;
/* If pre-trigger buffer not full, rewind head to the first valid sample. */
if (stl->pre_trigger_fill < stl->pre_trigger_size)
stl->pre_trigger_head = stl->pre_trigger_buffer;
/* Send logic packets for the pre-trigger circular buffer content. */
while (stl->pre_trigger_fill > 0) {
size_t size = MIN(stl->pre_trigger_buffer + stl->pre_trigger_size
- stl->pre_trigger_head, stl->pre_trigger_fill);
logic.length = size;
logic.data = stl->pre_trigger_head;
sr_session_send(stl->sdi, &packet);
stl->pre_trigger_head = stl->pre_trigger_buffer;
stl->pre_trigger_fill -= size;
if (pre_trigger_samples)
*pre_trigger_samples += size / stl->unitsize;
}
}
static gboolean logic_check_match(struct soft_trigger_logic *stl, static gboolean logic_check_match(struct soft_trigger_logic *stl,
uint8_t *sample, struct sr_trigger_match *match) uint8_t *sample, struct sr_trigger_match *match)
{ {
@ -80,7 +148,7 @@ static gboolean logic_check_match(struct soft_trigger_logic *stl,
/* Returns the offset (in samples) within buf of where the trigger /* Returns the offset (in samples) within buf of where the trigger
* occurred, or -1 if not triggered. */ * occurred, or -1 if not triggered. */
SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *stl, SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *stl,
uint8_t *buf, int len) uint8_t *buf, int len, int *pre_trigger_samples)
{ {
struct sr_datafeed_packet packet; struct sr_datafeed_packet packet;
struct sr_trigger_stage *stage; struct sr_trigger_stage *stage;
@ -116,7 +184,11 @@ SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *stl,
/* Advance to next stage. */ /* Advance to next stage. */
stl->cur_stage++; stl->cur_stage++;
} else { } else {
/* Matched on last stage, fire trigger. */ /* Matched on last stage, send pre-trigger data. */
pre_trigger_append(stl, buf, i);
pre_trigger_send(stl, pre_trigger_samples);
/* Fire trigger. */
offset = i / stl->unitsize; offset = i / stl->unitsize;
packet.type = SR_DF_TRIGGER; packet.type = SR_DF_TRIGGER;
@ -142,6 +214,9 @@ SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *stl,
} }
} }
if (offset == -1)
pre_trigger_append(stl, buf, len);
return offset; return offset;
} }