support for multiple FX2 devices
This commit is contained in:
parent
e53c830f33
commit
6d754b6d3a
|
@ -31,6 +31,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
int ezusb_reset(struct libusb_device_handle *hdl, int set_clear)
|
int ezusb_reset(struct libusb_device_handle *hdl, int set_clear)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -56,10 +57,11 @@ int ezusb_install_firmware(libusb_device_handle *hdl, const char *filename)
|
||||||
if ((fw = g_fopen(filename, "rb")) == NULL) {
|
if ((fw = g_fopen(filename, "rb")) == NULL) {
|
||||||
sr_warn("Unable to open firmware file %s for reading: %s",
|
sr_warn("Unable to open firmware file %s for reading: %s",
|
||||||
filename, strerror(errno));
|
filename, strerror(errno));
|
||||||
return 1;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = offset = 0;
|
result = SR_OK;
|
||||||
|
offset = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
chunksize = fread(buf, 1, 4096, fw);
|
chunksize = fread(buf, 1, 4096, fw);
|
||||||
if (chunksize == 0)
|
if (chunksize == 0)
|
||||||
|
@ -69,7 +71,7 @@ int ezusb_install_firmware(libusb_device_handle *hdl, const char *filename)
|
||||||
0x0000, buf, chunksize, 100);
|
0x0000, buf, chunksize, 100);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
sr_warn("Unable to send firmware to device: %d", err);
|
sr_warn("Unable to send firmware to device: %d", err);
|
||||||
result = 1;
|
result = SR_ERR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sr_info("Uploaded %d bytes", chunksize);
|
sr_info("Uploaded %d bytes", chunksize);
|
||||||
|
@ -90,36 +92,33 @@ int ezusb_upload_firmware(libusb_device *dev, int configuration,
|
||||||
sr_info("uploading firmware to device on %d.%d",
|
sr_info("uploading firmware to device on %d.%d",
|
||||||
libusb_get_bus_number(dev), libusb_get_device_address(dev));
|
libusb_get_bus_number(dev), libusb_get_device_address(dev));
|
||||||
|
|
||||||
err = libusb_open(dev, &hdl);
|
if ((err = libusb_open(dev, &hdl)) < 0) {
|
||||||
if (err != 0) {
|
|
||||||
sr_warn("failed to open device: %d", err);
|
sr_warn("failed to open device: %d", err);
|
||||||
return 1;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (libusb_kernel_driver_active(hdl, 0)) {
|
if (libusb_kernel_driver_active(hdl, 0)) {
|
||||||
err = libusb_detach_kernel_driver(hdl, 0);
|
if ((err = libusb_detach_kernel_driver(hdl, 0)) < 0) {
|
||||||
if (err != 0) {
|
sr_warn("failed to detach kernel driver: %d", err);
|
||||||
g_warning("failed to detach kernel driver: %d", err);
|
return SR_ERR;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = libusb_set_configuration(hdl, configuration);
|
if ((err = libusb_set_configuration(hdl, configuration)) < 0) {
|
||||||
if (err != 0) {
|
|
||||||
sr_warn("Unable to set configuration: %d", err);
|
sr_warn("Unable to set configuration: %d", err);
|
||||||
return 1;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ezusb_reset(hdl, 1)) < 0)
|
if ((ezusb_reset(hdl, 1)) < 0)
|
||||||
return 1;
|
return SR_ERR;
|
||||||
|
|
||||||
if (ezusb_install_firmware(hdl, filename) != 0)
|
if (ezusb_install_firmware(hdl, filename) < 0)
|
||||||
return 1;
|
return SR_ERR;
|
||||||
|
|
||||||
if ((ezusb_reset(hdl, 0)) < 0)
|
if ((ezusb_reset(hdl, 0)) < 0)
|
||||||
return 1;
|
return SR_ERR;
|
||||||
|
|
||||||
libusb_close(hdl);
|
libusb_close(hdl);
|
||||||
|
|
||||||
return 0;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,8 @@ AM_CPPFLAGS = -DFIRMWARE_DIR='"$(FIRMWARE_DIR)"'
|
||||||
noinst_LTLIBRARIES = libsigrokhwsaleaelogic.la
|
noinst_LTLIBRARIES = libsigrokhwsaleaelogic.la
|
||||||
|
|
||||||
libsigrokhwsaleaelogic_la_SOURCES = \
|
libsigrokhwsaleaelogic_la_SOURCES = \
|
||||||
saleae-logic.c
|
saleae-logic.c \
|
||||||
|
saleae-logic.h
|
||||||
|
|
||||||
libsigrokhwsaleaelogic_la_CFLAGS = \
|
libsigrokhwsaleaelogic_la_CFLAGS = \
|
||||||
-I$(top_srcdir)/libsigrok
|
-I$(top_srcdir)/libsigrok
|
||||||
|
|
|
@ -26,44 +26,16 @@
|
||||||
#include <libusb.h>
|
#include <libusb.h>
|
||||||
#include <sigrok.h>
|
#include <sigrok.h>
|
||||||
#include <sigrok-internal.h>
|
#include <sigrok-internal.h>
|
||||||
|
#include "saleae-logic.h"
|
||||||
|
|
||||||
#define USB_INTERFACE 0
|
static struct fx2_profile supported_fx2[] = {
|
||||||
#define USB_CONFIGURATION 1
|
|
||||||
#define NUM_TRIGGER_STAGES 4
|
|
||||||
#define TRIGGER_TYPES "01"
|
|
||||||
#define FIRMWARE FIRMWARE_DIR "/saleae-logic.fw"
|
|
||||||
#define GTV_TO_MSEC(gtv) (gtv.tv_sec * 1000 + gtv.tv_usec / 1000)
|
|
||||||
|
|
||||||
/* delay in ms */
|
|
||||||
#define MAX_RENUM_DELAY 3000
|
|
||||||
#define NUM_SIMUL_TRANSFERS 10
|
|
||||||
#define MAX_EMPTY_TRANSFERS (NUM_SIMUL_TRANSFERS * 2)
|
|
||||||
|
|
||||||
/* Software trigger implementation: positive values indicate trigger stage. */
|
|
||||||
#define TRIGGER_FIRED -1
|
|
||||||
|
|
||||||
struct fx2_device {
|
|
||||||
/* VID/PID when first found */
|
|
||||||
uint16_t orig_vid;
|
|
||||||
uint16_t orig_pid;
|
|
||||||
/* VID/PID after firmware upload */
|
|
||||||
uint16_t fw_vid;
|
|
||||||
uint16_t fw_pid;
|
|
||||||
char *vendor;
|
|
||||||
char *model;
|
|
||||||
char *model_version;
|
|
||||||
int num_probes;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct fx2_device supported_fx2[] = {
|
|
||||||
/* Saleae Logic */
|
/* Saleae Logic */
|
||||||
{ 0x0925, 0x3881, 0x0925, 0x3881, "Saleae", "Logic", NULL, 8 },
|
{ 0x0925, 0x3881, 0x0925, 0x3881, "Saleae", "Logic", NULL, 8 },
|
||||||
/* default Cypress FX2 without EEPROM */
|
/* default Cypress FX2 without EEPROM */
|
||||||
{ 0x04b4, 0x8613, 0x0925, 0x3881, "Cypress", "FX2", NULL, 16 },
|
{ 0x04b4, 0x8613, 0x0925, 0x3881, "Cypress", "FX2", NULL, 16 },
|
||||||
{ 0, 0, 0, 0, NULL, NULL, NULL, 0 }
|
{ 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* There is only one model Saleae Logic, and this is what it supports: */
|
|
||||||
static int capabilities[] = {
|
static int capabilities[] = {
|
||||||
SR_HWCAP_LOGIC_ANALYZER,
|
SR_HWCAP_LOGIC_ANALYZER,
|
||||||
SR_HWCAP_SAMPLERATE,
|
SR_HWCAP_SAMPLERATE,
|
||||||
|
@ -74,19 +46,6 @@ static int capabilities[] = {
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* List of struct sr_device_instance, maintained by opendev()/closedev(). */
|
|
||||||
static GSList *device_instances = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Since we can't keep track of a Saleae Logic device after upgrading the
|
|
||||||
* firmware -- it re-enumerates into a different device address after the
|
|
||||||
* upgrade -- this is like a global lock. No device will open until a proper
|
|
||||||
* delay after the last device was upgraded.
|
|
||||||
*/
|
|
||||||
static GTimeVal fw_updated = { 0, 0 };
|
|
||||||
|
|
||||||
static libusb_context *usb_context = NULL;
|
|
||||||
|
|
||||||
static uint64_t supported_samplerates[] = {
|
static uint64_t supported_samplerates[] = {
|
||||||
SR_KHZ(200),
|
SR_KHZ(200),
|
||||||
SR_KHZ(250),
|
SR_KHZ(250),
|
||||||
|
@ -108,15 +67,9 @@ static struct sr_samplerates samplerates = {
|
||||||
supported_samplerates,
|
supported_samplerates,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TODO: All of these should go in a device-specific struct. */
|
/* List of struct sr_device_instance, maintained by opendev()/closedev(). */
|
||||||
static uint64_t cur_samplerate = 0;
|
static GSList *device_instances = NULL;
|
||||||
static uint64_t limit_samples = 0;
|
static libusb_context *usb_context = NULL;
|
||||||
static uint8_t probe_mask = 0;
|
|
||||||
static uint8_t trigger_mask[NUM_TRIGGER_STAGES] = { 0 };
|
|
||||||
static uint8_t trigger_value[NUM_TRIGGER_STAGES] = { 0 };
|
|
||||||
static uint8_t trigger_buffer[NUM_TRIGGER_STAGES] = { 0 };
|
|
||||||
static struct fx2_device *fx2 = NULL;
|
|
||||||
static int trigger_stage = TRIGGER_FIRED;
|
|
||||||
|
|
||||||
static int hw_set_configuration(int device_index, int capability, void *value);
|
static int hw_set_configuration(int device_index, int capability, void *value);
|
||||||
static void hw_stop_acquisition(int device_index, gpointer session_device_id);
|
static void hw_stop_acquisition(int device_index, gpointer session_device_id);
|
||||||
|
@ -181,19 +134,21 @@ static int check_conf_profile(libusb_device *dev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sr_device_instance *sl_open_device(int device_index)
|
static int sl_open_device(int device_index)
|
||||||
{
|
{
|
||||||
libusb_device **devlist;
|
libusb_device **devlist;
|
||||||
struct libusb_device_descriptor des;
|
struct libusb_device_descriptor des;
|
||||||
struct sr_device_instance *sdi;
|
struct sr_device_instance *sdi;
|
||||||
|
struct fx2_device *fx2;
|
||||||
int err, skip, i;
|
int err, skip, i;
|
||||||
|
|
||||||
if (!(sdi = sr_get_device_instance(device_instances, device_index)))
|
if (!(sdi = sr_get_device_instance(device_instances, device_index)))
|
||||||
return NULL;
|
return SR_ERR;
|
||||||
|
fx2 = sdi->priv;
|
||||||
|
|
||||||
if (sdi->status == SR_ST_ACTIVE)
|
if (sdi->status == SR_ST_ACTIVE)
|
||||||
/* already in use */
|
/* already in use */
|
||||||
return NULL;
|
return SR_ERR;
|
||||||
|
|
||||||
skip = 0;
|
skip = 0;
|
||||||
libusb_get_device_list(usb_context, &devlist);
|
libusb_get_device_list(usb_context, &devlist);
|
||||||
|
@ -203,7 +158,7 @@ static struct sr_device_instance *sl_open_device(int device_index)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (des.idVendor != fx2->fw_vid || des.idProduct != fx2->fw_pid)
|
if (des.idVendor != fx2->profile->fw_vid || des.idProduct != fx2->profile->fw_pid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sdi->status == SR_ST_INITIALIZING) {
|
if (sdi->status == SR_ST_INITIALIZING) {
|
||||||
|
@ -237,29 +192,17 @@ static struct sr_device_instance *sl_open_device(int device_index)
|
||||||
sdi->usb->address, USB_INTERFACE);
|
sdi->usb->address, USB_INTERFACE);
|
||||||
} else {
|
} else {
|
||||||
sr_warn("failed to open device: %d", err);
|
sr_warn("failed to open device: %d", err);
|
||||||
sdi = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* if we made it here, we handled the device one way or another */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
libusb_free_device_list(devlist, 1);
|
libusb_free_device_list(devlist, 1);
|
||||||
|
|
||||||
if (sdi && sdi->status != SR_ST_ACTIVE)
|
if (sdi->status != SR_ST_ACTIVE)
|
||||||
sdi = NULL;
|
return SR_ERR;
|
||||||
|
|
||||||
return sdi;
|
return SR_OK;
|
||||||
}
|
|
||||||
|
|
||||||
static int upload_firmware(libusb_device *dev)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = ezusb_upload_firmware(dev, USB_CONFIGURATION, FIRMWARE);
|
|
||||||
if (ret != 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* Remember when the last firmware update was done. */
|
|
||||||
g_get_current_time(&fw_updated);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_device(struct sr_device_instance *sdi)
|
static void close_device(struct sr_device_instance *sdi)
|
||||||
|
@ -275,17 +218,17 @@ static void close_device(struct sr_device_instance *sdi)
|
||||||
sdi->status = SR_ST_INACTIVE;
|
sdi->status = SR_ST_INACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int configure_probes(GSList *probes)
|
static int configure_probes(struct fx2_device *fx2, GSList *probes)
|
||||||
{
|
{
|
||||||
struct sr_probe *probe;
|
struct sr_probe *probe;
|
||||||
GSList *l;
|
GSList *l;
|
||||||
int probe_bit, stage, i;
|
int probe_bit, stage, i;
|
||||||
char *tc;
|
char *tc;
|
||||||
|
|
||||||
probe_mask = 0;
|
fx2->probe_mask = 0;
|
||||||
for (i = 0; i < NUM_TRIGGER_STAGES; i++) {
|
for (i = 0; i < NUM_TRIGGER_STAGES; i++) {
|
||||||
trigger_mask[i] = 0;
|
fx2->trigger_mask[i] = 0;
|
||||||
trigger_value[i] = 0;
|
fx2->trigger_value[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
stage = -1;
|
stage = -1;
|
||||||
|
@ -294,15 +237,15 @@ static int configure_probes(GSList *probes)
|
||||||
if (probe->enabled == FALSE)
|
if (probe->enabled == FALSE)
|
||||||
continue;
|
continue;
|
||||||
probe_bit = 1 << (probe->index - 1);
|
probe_bit = 1 << (probe->index - 1);
|
||||||
probe_mask |= probe_bit;
|
fx2->probe_mask |= probe_bit;
|
||||||
if (!(probe->trigger))
|
if (!(probe->trigger))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
stage = 0;
|
stage = 0;
|
||||||
for (tc = probe->trigger; *tc; tc++) {
|
for (tc = probe->trigger; *tc; tc++) {
|
||||||
trigger_mask[stage] |= probe_bit;
|
fx2->trigger_mask[stage] |= probe_bit;
|
||||||
if (*tc == '1')
|
if (*tc == '1')
|
||||||
trigger_value[stage] |= probe_bit;
|
fx2->trigger_value[stage] |= probe_bit;
|
||||||
stage++;
|
stage++;
|
||||||
if (stage > NUM_TRIGGER_STAGES)
|
if (stage > NUM_TRIGGER_STAGES)
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
|
@ -314,13 +257,27 @@ static int configure_probes(GSList *probes)
|
||||||
* We didn't configure any triggers, make sure acquisition
|
* We didn't configure any triggers, make sure acquisition
|
||||||
* doesn't wait for any.
|
* doesn't wait for any.
|
||||||
*/
|
*/
|
||||||
trigger_stage = TRIGGER_FIRED;
|
fx2->trigger_stage = TRIGGER_FIRED;
|
||||||
else
|
else
|
||||||
trigger_stage = 0;
|
fx2->trigger_stage = 0;
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct fx2_device *fx2_device_new(void)
|
||||||
|
{
|
||||||
|
struct fx2_device *fx2;
|
||||||
|
|
||||||
|
if (!(fx2 = g_try_malloc0(sizeof(struct fx2_device)))) {
|
||||||
|
sr_err("saleae: %s: saleae malloc failed", __func__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fx2->trigger_stage = TRIGGER_FIRED;
|
||||||
|
|
||||||
|
return fx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* API callbacks
|
* API callbacks
|
||||||
*/
|
*/
|
||||||
|
@ -329,6 +286,8 @@ static int hw_init(const char *deviceinfo)
|
||||||
{
|
{
|
||||||
struct sr_device_instance *sdi;
|
struct sr_device_instance *sdi;
|
||||||
struct libusb_device_descriptor des;
|
struct libusb_device_descriptor des;
|
||||||
|
struct fx2_profile *fx2_prof;
|
||||||
|
struct fx2_device *fx2;
|
||||||
libusb_device **devlist;
|
libusb_device **devlist;
|
||||||
int err, devcnt, i, j;
|
int err, devcnt, i, j;
|
||||||
|
|
||||||
|
@ -341,10 +300,10 @@ static int hw_init(const char *deviceinfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find all Saleae Logic devices and upload firmware to all of them. */
|
/* Find all Saleae Logic devices and upload firmware to all of them. */
|
||||||
fx2 = NULL;
|
|
||||||
devcnt = 0;
|
devcnt = 0;
|
||||||
libusb_get_device_list(usb_context, &devlist);
|
libusb_get_device_list(usb_context, &devlist);
|
||||||
for (i = 0; devlist[i]; i++) {
|
for (i = 0; devlist[i]; i++) {
|
||||||
|
fx2_prof = NULL;
|
||||||
err = libusb_get_device_descriptor(devlist[i], &des);
|
err = libusb_get_device_descriptor(devlist[i], &des);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
sr_warn("failed to get device descriptor: %d", err);
|
sr_warn("failed to get device descriptor: %d", err);
|
||||||
|
@ -354,43 +313,39 @@ static int hw_init(const char *deviceinfo)
|
||||||
for (j = 0; supported_fx2[j].orig_vid; j++) {
|
for (j = 0; supported_fx2[j].orig_vid; j++) {
|
||||||
if (des.idVendor == supported_fx2[j].orig_vid
|
if (des.idVendor == supported_fx2[j].orig_vid
|
||||||
&& des.idProduct == supported_fx2[j].orig_pid) {
|
&& des.idProduct == supported_fx2[j].orig_pid) {
|
||||||
fx2 = &supported_fx2[j];
|
fx2_prof = &supported_fx2[j];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!fx2)
|
if (!fx2_prof)
|
||||||
/* not a supported VID/PID */
|
/* not a supported VID/PID */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sdi = sr_device_instance_new(devcnt, SR_ST_INITIALIZING,
|
sdi = sr_device_instance_new(devcnt, SR_ST_INITIALIZING,
|
||||||
fx2->vendor, fx2->model, fx2->model_version);
|
fx2_prof->vendor, fx2_prof->model, fx2_prof->model_version);
|
||||||
if (!sdi)
|
if (!sdi)
|
||||||
return 0;
|
return 0;
|
||||||
|
fx2 = fx2_device_new();
|
||||||
|
fx2->profile = fx2_prof;
|
||||||
|
sdi->priv = fx2;
|
||||||
device_instances = g_slist_append(device_instances, sdi);
|
device_instances = g_slist_append(device_instances, sdi);
|
||||||
|
|
||||||
if (check_conf_profile(devlist[i]) == 0) {
|
if (check_conf_profile(devlist[i])) {
|
||||||
/*
|
|
||||||
* Continue on the off chance that the device is in a
|
|
||||||
* working state. TODO: Could maybe try a USB reset,
|
|
||||||
* or uploading the firmware again.
|
|
||||||
*/
|
|
||||||
if (upload_firmware(devlist[i]) > 0)
|
|
||||||
sr_warn("firmware upload failed for device %d",
|
|
||||||
devcnt);
|
|
||||||
|
|
||||||
sdi->usb = sr_usb_device_instance_new
|
|
||||||
(libusb_get_bus_number(devlist[i]), 0xff, NULL);
|
|
||||||
} else {
|
|
||||||
/* Already has the firmware, so fix the new address. */
|
/* Already has the firmware, so fix the new address. */
|
||||||
sdi->status = SR_ST_INACTIVE;
|
sdi->status = SR_ST_INACTIVE;
|
||||||
sdi->usb = sr_usb_device_instance_new
|
sdi->usb = sr_usb_device_instance_new
|
||||||
(libusb_get_bus_number(devlist[i]),
|
(libusb_get_bus_number(devlist[i]),
|
||||||
libusb_get_device_address(devlist[i]), NULL);
|
libusb_get_device_address(devlist[i]), NULL);
|
||||||
|
} else {
|
||||||
|
if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION, FIRMWARE) == SR_OK)
|
||||||
|
/* Remember when the firmware on this device was updated */
|
||||||
|
g_get_current_time(&fx2->fw_updated);
|
||||||
|
else
|
||||||
|
sr_warn("firmware upload failed for device %d", devcnt);
|
||||||
|
sdi->usb = sr_usb_device_instance_new
|
||||||
|
(libusb_get_bus_number(devlist[i]), 0xff, NULL);
|
||||||
}
|
}
|
||||||
devcnt++;
|
devcnt++;
|
||||||
|
|
||||||
/* not supporting multiple FX2s in this driver yet */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
libusb_free_device_list(devlist, 1);
|
libusb_free_device_list(devlist, 1);
|
||||||
|
|
||||||
|
@ -401,34 +356,40 @@ static int hw_opendev(int device_index)
|
||||||
{
|
{
|
||||||
GTimeVal cur_time;
|
GTimeVal cur_time;
|
||||||
struct sr_device_instance *sdi;
|
struct sr_device_instance *sdi;
|
||||||
|
struct fx2_device *fx2;
|
||||||
int timediff, err;
|
int timediff, err;
|
||||||
|
|
||||||
|
if (!(sdi = sr_get_device_instance(device_instances, device_index)))
|
||||||
|
return SR_ERR;
|
||||||
|
fx2 = sdi->priv;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the firmware was recently uploaded, wait up to MAX_RENUM_DELAY ms
|
* if the firmware was recently uploaded, wait up to MAX_RENUM_DELAY ms
|
||||||
* for the FX2 to renumerate
|
* for the FX2 to renumerate
|
||||||
*/
|
*/
|
||||||
sdi = NULL;
|
err = 0;
|
||||||
if (fw_updated.tv_sec > 0) {
|
if (GTV_TO_MSEC(fx2->fw_updated) > 0) {
|
||||||
sr_info("saleae: waiting for device to reset");
|
sr_info("saleae: waiting for device to reset");
|
||||||
/* takes at least 300ms for the FX2 to be gone from the USB bus */
|
/* takes at least 300ms for the FX2 to be gone from the USB bus */
|
||||||
g_usleep(300*1000);
|
g_usleep(300*1000);
|
||||||
timediff = 0;
|
timediff = 0;
|
||||||
while (timediff < MAX_RENUM_DELAY) {
|
while (timediff < MAX_RENUM_DELAY) {
|
||||||
if ((sdi = sl_open_device(device_index)))
|
if ((err = sl_open_device(device_index)) == SR_OK)
|
||||||
break;
|
break;
|
||||||
g_usleep(100*1000);
|
g_usleep(100*1000);
|
||||||
g_get_current_time(&cur_time);
|
g_get_current_time(&cur_time);
|
||||||
timediff = GTV_TO_MSEC(cur_time) - GTV_TO_MSEC(fw_updated);
|
timediff = GTV_TO_MSEC(cur_time) - GTV_TO_MSEC(fx2->fw_updated);
|
||||||
}
|
}
|
||||||
sr_info("saleae: device came back after %d ms", timediff);
|
sr_info("saleae: device came back after %d ms", timediff);
|
||||||
} else {
|
} else {
|
||||||
sdi = sl_open_device(device_index);
|
err = sl_open_device(device_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sdi) {
|
if (err != SR_OK) {
|
||||||
sr_warn("unable to open device");
|
sr_warn("unable to open device");
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
fx2 = sdi->priv;
|
||||||
|
|
||||||
err = libusb_claim_interface(sdi->usb->devhdl, USB_INTERFACE);
|
err = libusb_claim_interface(sdi->usb->devhdl, USB_INTERFACE);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
|
@ -436,7 +397,7 @@ static int hw_opendev(int device_index)
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur_samplerate == 0) {
|
if (fx2->cur_samplerate == 0) {
|
||||||
/* Samplerate hasn't been set; default to the slowest one. */
|
/* Samplerate hasn't been set; default to the slowest one. */
|
||||||
if (hw_set_configuration(device_index, SR_HWCAP_SAMPLERATE,
|
if (hw_set_configuration(device_index, SR_HWCAP_SAMPLERATE,
|
||||||
&supported_samplerates[0]) == SR_ERR)
|
&supported_samplerates[0]) == SR_ERR)
|
||||||
|
@ -483,17 +444,19 @@ static void hw_cleanup(void)
|
||||||
static void *hw_get_device_info(int device_index, int device_info_id)
|
static void *hw_get_device_info(int device_index, int device_info_id)
|
||||||
{
|
{
|
||||||
struct sr_device_instance *sdi;
|
struct sr_device_instance *sdi;
|
||||||
|
struct fx2_device *fx2;
|
||||||
void *info = NULL;
|
void *info = NULL;
|
||||||
|
|
||||||
if (!(sdi = sr_get_device_instance(device_instances, device_index)))
|
if (!(sdi = sr_get_device_instance(device_instances, device_index)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
fx2 = sdi->priv;
|
||||||
|
|
||||||
switch (device_info_id) {
|
switch (device_info_id) {
|
||||||
case SR_DI_INSTANCE:
|
case SR_DI_INSTANCE:
|
||||||
info = sdi;
|
info = sdi;
|
||||||
break;
|
break;
|
||||||
case SR_DI_NUM_PROBES:
|
case SR_DI_NUM_PROBES:
|
||||||
info = GINT_TO_POINTER(fx2->num_probes);
|
info = GINT_TO_POINTER(fx2->profile->num_probes);
|
||||||
break;
|
break;
|
||||||
case SR_DI_SAMPLERATES:
|
case SR_DI_SAMPLERATES:
|
||||||
info = &samplerates;
|
info = &samplerates;
|
||||||
|
@ -502,7 +465,7 @@ static void *hw_get_device_info(int device_index, int device_info_id)
|
||||||
info = TRIGGER_TYPES;
|
info = TRIGGER_TYPES;
|
||||||
break;
|
break;
|
||||||
case SR_DI_CUR_SAMPLERATE:
|
case SR_DI_CUR_SAMPLERATE:
|
||||||
info = &cur_samplerate;
|
info = &fx2->cur_samplerate;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,10 +491,12 @@ static int *hw_get_capabilities(void)
|
||||||
static int set_configuration_samplerate(struct sr_device_instance *sdi,
|
static int set_configuration_samplerate(struct sr_device_instance *sdi,
|
||||||
uint64_t samplerate)
|
uint64_t samplerate)
|
||||||
{
|
{
|
||||||
|
struct fx2_device *fx2;
|
||||||
uint8_t divider;
|
uint8_t divider;
|
||||||
int ret, result, i;
|
int ret, result, i;
|
||||||
unsigned char buf[2];
|
unsigned char buf[2];
|
||||||
|
|
||||||
|
fx2 = sdi->priv;
|
||||||
for (i = 0; supported_samplerates[i]; i++) {
|
for (i = 0; supported_samplerates[i]; i++) {
|
||||||
if (supported_samplerates[i] == samplerate)
|
if (supported_samplerates[i] == samplerate)
|
||||||
break;
|
break;
|
||||||
|
@ -551,7 +516,7 @@ static int set_configuration_samplerate(struct sr_device_instance *sdi,
|
||||||
sr_warn("failed to set samplerate: %d", ret);
|
sr_warn("failed to set samplerate: %d", ret);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
cur_samplerate = samplerate;
|
fx2->cur_samplerate = samplerate;
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
@ -559,20 +524,22 @@ static int set_configuration_samplerate(struct sr_device_instance *sdi,
|
||||||
static int hw_set_configuration(int device_index, int capability, void *value)
|
static int hw_set_configuration(int device_index, int capability, void *value)
|
||||||
{
|
{
|
||||||
struct sr_device_instance *sdi;
|
struct sr_device_instance *sdi;
|
||||||
|
struct fx2_device *fx2;
|
||||||
int ret;
|
int ret;
|
||||||
uint64_t *tmp_u64;
|
uint64_t *tmp_u64;
|
||||||
|
|
||||||
if (!(sdi = sr_get_device_instance(device_instances, device_index)))
|
if (!(sdi = sr_get_device_instance(device_instances, device_index)))
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
|
fx2 = sdi->priv;
|
||||||
|
|
||||||
if (capability == SR_HWCAP_SAMPLERATE) {
|
if (capability == SR_HWCAP_SAMPLERATE) {
|
||||||
tmp_u64 = value;
|
tmp_u64 = value;
|
||||||
ret = set_configuration_samplerate(sdi, *tmp_u64);
|
ret = set_configuration_samplerate(sdi, *tmp_u64);
|
||||||
} else if (capability == SR_HWCAP_PROBECONFIG) {
|
} else if (capability == SR_HWCAP_PROBECONFIG) {
|
||||||
ret = configure_probes((GSList *) value);
|
ret = configure_probes(fx2, (GSList *) value);
|
||||||
} else if (capability == SR_HWCAP_LIMIT_SAMPLES) {
|
} else if (capability == SR_HWCAP_LIMIT_SAMPLES) {
|
||||||
tmp_u64 = value;
|
tmp_u64 = value;
|
||||||
limit_samples = *tmp_u64;
|
fx2->limit_samples = *tmp_u64;
|
||||||
ret = SR_OK;
|
ret = SR_OK;
|
||||||
} else {
|
} else {
|
||||||
ret = SR_ERR;
|
ret = SR_ERR;
|
||||||
|
@ -601,7 +568,7 @@ void receive_transfer(struct libusb_transfer *transfer)
|
||||||
static int num_samples = 0;
|
static int num_samples = 0;
|
||||||
static int empty_transfer_count = 0;
|
static int empty_transfer_count = 0;
|
||||||
struct sr_datafeed_packet packet;
|
struct sr_datafeed_packet packet;
|
||||||
void *user_data;
|
struct fx2_device *fx2;
|
||||||
int cur_buflen, trigger_offset, i;
|
int cur_buflen, trigger_offset, i;
|
||||||
unsigned char *cur_buf, *new_buf;
|
unsigned char *cur_buf, *new_buf;
|
||||||
|
|
||||||
|
@ -625,7 +592,7 @@ void receive_transfer(struct libusb_transfer *transfer)
|
||||||
/* Save incoming transfer before reusing the transfer struct. */
|
/* Save incoming transfer before reusing the transfer struct. */
|
||||||
cur_buf = transfer->buffer;
|
cur_buf = transfer->buffer;
|
||||||
cur_buflen = transfer->actual_length;
|
cur_buflen = transfer->actual_length;
|
||||||
user_data = transfer->user_data;
|
fx2 = transfer->user_data;
|
||||||
|
|
||||||
/* Fire off a new request. */
|
/* Fire off a new request. */
|
||||||
if (!(new_buf = g_try_malloc(4096))) {
|
if (!(new_buf = g_try_malloc(4096))) {
|
||||||
|
@ -648,7 +615,7 @@ void receive_transfer(struct libusb_transfer *transfer)
|
||||||
* The FX2 gave up. End the acquisition, the frontend
|
* The FX2 gave up. End the acquisition, the frontend
|
||||||
* will work out that the samplecount is short.
|
* will work out that the samplecount is short.
|
||||||
*/
|
*/
|
||||||
hw_stop_acquisition(-1, user_data);
|
hw_stop_acquisition(-1, fx2->session_data);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -656,14 +623,14 @@ void receive_transfer(struct libusb_transfer *transfer)
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger_offset = 0;
|
trigger_offset = 0;
|
||||||
if (trigger_stage >= 0) {
|
if (fx2->trigger_stage >= 0) {
|
||||||
for (i = 0; i < cur_buflen; i++) {
|
for (i = 0; i < cur_buflen; i++) {
|
||||||
|
|
||||||
if ((cur_buf[i] & trigger_mask[trigger_stage]) == trigger_value[trigger_stage]) {
|
if ((cur_buf[i] & fx2->trigger_mask[fx2->trigger_stage]) == fx2->trigger_value[fx2->trigger_stage]) {
|
||||||
/* Match on this trigger stage. */
|
/* Match on this trigger stage. */
|
||||||
trigger_buffer[trigger_stage] = cur_buf[i];
|
fx2->trigger_buffer[fx2->trigger_stage] = cur_buf[i];
|
||||||
trigger_stage++;
|
fx2->trigger_stage++;
|
||||||
if (trigger_stage == NUM_TRIGGER_STAGES || trigger_mask[trigger_stage] == 0) {
|
if (fx2->trigger_stage == NUM_TRIGGER_STAGES || fx2->trigger_mask[fx2->trigger_stage] == 0) {
|
||||||
/* Match on all trigger stages, we're done. */
|
/* Match on all trigger stages, we're done. */
|
||||||
trigger_offset = i + 1;
|
trigger_offset = i + 1;
|
||||||
|
|
||||||
|
@ -673,19 +640,19 @@ void receive_transfer(struct libusb_transfer *transfer)
|
||||||
*/
|
*/
|
||||||
packet.type = SR_DF_TRIGGER;
|
packet.type = SR_DF_TRIGGER;
|
||||||
packet.length = 0;
|
packet.length = 0;
|
||||||
sr_session_bus(user_data, &packet);
|
sr_session_bus(fx2->session_data, &packet);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send the samples that triggered it, since we're
|
* Send the samples that triggered it, since we're
|
||||||
* skipping past them.
|
* skipping past them.
|
||||||
*/
|
*/
|
||||||
packet.type = SR_DF_LOGIC;
|
packet.type = SR_DF_LOGIC;
|
||||||
packet.length = trigger_stage;
|
packet.length = fx2->trigger_stage;
|
||||||
packet.unitsize = 1;
|
packet.unitsize = 1;
|
||||||
packet.payload = trigger_buffer;
|
packet.payload = fx2->trigger_buffer;
|
||||||
sr_session_bus(user_data, &packet);
|
sr_session_bus(fx2->session_data, &packet);
|
||||||
|
|
||||||
trigger_stage = TRIGGER_FIRED;
|
fx2->trigger_stage = TRIGGER_FIRED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -698,30 +665,28 @@ void receive_transfer(struct libusb_transfer *transfer)
|
||||||
* the next sample from the one that matched originally, which the
|
* the next sample from the one that matched originally, which the
|
||||||
* counter increment at the end of the loop takes care of.
|
* counter increment at the end of the loop takes care of.
|
||||||
*/
|
*/
|
||||||
if (trigger_stage > 0) {
|
if (fx2->trigger_stage > 0) {
|
||||||
i -= trigger_stage;
|
i -= fx2->trigger_stage;
|
||||||
if (i < -1)
|
if (i < -1)
|
||||||
i = -1; /* Oops, went back past this buffer. */
|
i = -1; /* Oops, went back past this buffer. */
|
||||||
/* Reset trigger stage. */
|
/* Reset trigger stage. */
|
||||||
trigger_stage = 0;
|
fx2->trigger_stage = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trigger_stage == TRIGGER_FIRED) {
|
if (fx2->trigger_stage == TRIGGER_FIRED) {
|
||||||
/* Send the incoming transfer to the session bus. */
|
/* Send the incoming transfer to the session bus. */
|
||||||
packet.type = SR_DF_LOGIC;
|
packet.type = SR_DF_LOGIC;
|
||||||
packet.length = cur_buflen - trigger_offset;
|
packet.length = cur_buflen - trigger_offset;
|
||||||
packet.unitsize = 1;
|
packet.unitsize = 1;
|
||||||
packet.payload = cur_buf + trigger_offset;
|
packet.payload = cur_buf + trigger_offset;
|
||||||
sr_session_bus(user_data, &packet);
|
sr_session_bus(fx2->session_data, &packet);
|
||||||
g_free(cur_buf);
|
g_free(cur_buf);
|
||||||
|
|
||||||
num_samples += cur_buflen;
|
num_samples += cur_buflen;
|
||||||
if (limit_samples && (unsigned int) num_samples > limit_samples) {
|
if (fx2->limit_samples && (unsigned int) num_samples > fx2->limit_samples) {
|
||||||
hw_stop_acquisition(-1, user_data);
|
hw_stop_acquisition(-1, fx2->session_data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
|
@ -731,11 +696,12 @@ void receive_transfer(struct libusb_transfer *transfer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hw_start_acquisition(int device_index, gpointer session_device_id)
|
static int hw_start_acquisition(int device_index, gpointer session_data)
|
||||||
{
|
{
|
||||||
struct sr_device_instance *sdi;
|
struct sr_device_instance *sdi;
|
||||||
struct sr_datafeed_packet *packet;
|
struct sr_datafeed_packet *packet;
|
||||||
struct sr_datafeed_header *header;
|
struct sr_datafeed_header *header;
|
||||||
|
struct fx2_device *fx2;
|
||||||
struct libusb_transfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
const struct libusb_pollfd **lupfd;
|
const struct libusb_pollfd **lupfd;
|
||||||
int size, i;
|
int size, i;
|
||||||
|
@ -743,6 +709,8 @@ static int hw_start_acquisition(int device_index, gpointer session_device_id)
|
||||||
|
|
||||||
if (!(sdi = sr_get_device_instance(device_instances, device_index)))
|
if (!(sdi = sr_get_device_instance(device_instances, device_index)))
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
|
fx2 = sdi->priv;
|
||||||
|
fx2->session_data = session_data;
|
||||||
|
|
||||||
if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
|
if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
|
||||||
sr_err("saleae: %s: packet malloc failed", __func__);
|
sr_err("saleae: %s: packet malloc failed", __func__);
|
||||||
|
@ -764,7 +732,7 @@ static int hw_start_acquisition(int device_index, gpointer session_device_id)
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = libusb_alloc_transfer(0);
|
||||||
libusb_fill_bulk_transfer(transfer, sdi->usb->devhdl,
|
libusb_fill_bulk_transfer(transfer, sdi->usb->devhdl,
|
||||||
2 | LIBUSB_ENDPOINT_IN, buf, size,
|
2 | LIBUSB_ENDPOINT_IN, buf, size,
|
||||||
receive_transfer, session_device_id, 40);
|
receive_transfer, fx2, 40);
|
||||||
if (libusb_submit_transfer(transfer) != 0) {
|
if (libusb_submit_transfer(transfer) != 0) {
|
||||||
/* TODO: Free them all. */
|
/* TODO: Free them all. */
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
|
@ -785,11 +753,11 @@ static int hw_start_acquisition(int device_index, gpointer session_device_id)
|
||||||
packet->payload = (unsigned char *)header;
|
packet->payload = (unsigned char *)header;
|
||||||
header->feed_version = 1;
|
header->feed_version = 1;
|
||||||
gettimeofday(&header->starttime, NULL);
|
gettimeofday(&header->starttime, NULL);
|
||||||
header->samplerate = cur_samplerate;
|
header->samplerate = fx2->cur_samplerate;
|
||||||
header->protocol_id = SR_PROTO_RAW;
|
header->protocol_id = SR_PROTO_RAW;
|
||||||
header->num_logic_probes = fx2->num_probes;
|
header->num_logic_probes = fx2->profile->num_probes;
|
||||||
header->num_analog_probes = 0;
|
header->num_analog_probes = 0;
|
||||||
sr_session_bus(session_device_id, packet);
|
sr_session_bus(session_data, packet);
|
||||||
g_free(header);
|
g_free(header);
|
||||||
g_free(packet);
|
g_free(packet);
|
||||||
|
|
||||||
|
@ -797,7 +765,7 @@ static int hw_start_acquisition(int device_index, gpointer session_device_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This stops acquisition on ALL devices, ignoring device_index. */
|
/* This stops acquisition on ALL devices, ignoring device_index. */
|
||||||
static void hw_stop_acquisition(int device_index, gpointer session_device_id)
|
static void hw_stop_acquisition(int device_index, gpointer session_data)
|
||||||
{
|
{
|
||||||
struct sr_datafeed_packet packet;
|
struct sr_datafeed_packet packet;
|
||||||
|
|
||||||
|
@ -805,7 +773,7 @@ static void hw_stop_acquisition(int device_index, gpointer session_device_id)
|
||||||
device_index = device_index;
|
device_index = device_index;
|
||||||
|
|
||||||
packet.type = SR_DF_END;
|
packet.type = SR_DF_END;
|
||||||
sr_session_bus(session_device_id, &packet);
|
sr_session_bus(session_data, &packet);
|
||||||
|
|
||||||
receive_transfer(NULL);
|
receive_transfer(NULL);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the sigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Bert Vermeulen <bert@biot.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SALEAE_LOGIC_H_
|
||||||
|
#define SALEAE_LOGIC_H_
|
||||||
|
|
||||||
|
#define USB_INTERFACE 0
|
||||||
|
#define USB_CONFIGURATION 1
|
||||||
|
#define NUM_TRIGGER_STAGES 4
|
||||||
|
#define TRIGGER_TYPES "01"
|
||||||
|
#define FIRMWARE FIRMWARE_DIR "/saleae-logic.fw"
|
||||||
|
#define GTV_TO_MSEC(gtv) (gtv.tv_sec * 1000 + gtv.tv_usec / 1000)
|
||||||
|
|
||||||
|
/* delay in ms */
|
||||||
|
#define MAX_RENUM_DELAY 3000
|
||||||
|
#define NUM_SIMUL_TRANSFERS 10
|
||||||
|
#define MAX_EMPTY_TRANSFERS (NUM_SIMUL_TRANSFERS * 2)
|
||||||
|
|
||||||
|
/* Software trigger implementation: positive values indicate trigger stage. */
|
||||||
|
#define TRIGGER_FIRED -1
|
||||||
|
|
||||||
|
struct fx2_profile {
|
||||||
|
/* VID/PID when first found */
|
||||||
|
uint16_t orig_vid;
|
||||||
|
uint16_t orig_pid;
|
||||||
|
/* VID/PID after firmware upload */
|
||||||
|
uint16_t fw_vid;
|
||||||
|
uint16_t fw_pid;
|
||||||
|
char *vendor;
|
||||||
|
char *model;
|
||||||
|
char *model_version;
|
||||||
|
int num_probes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fx2_device {
|
||||||
|
struct fx2_profile *profile;
|
||||||
|
/*
|
||||||
|
* Since we can't keep track of a Saleae Logic device after upgrading the
|
||||||
|
* firmware (it re-enumerates into a different device address after the
|
||||||
|
* upgrade) this is like a global lock. No device will open until a proper
|
||||||
|
* delay after the last device was upgraded.
|
||||||
|
*/
|
||||||
|
GTimeVal fw_updated;
|
||||||
|
/* device/capture settings */
|
||||||
|
uint64_t cur_samplerate;
|
||||||
|
uint64_t limit_samples;
|
||||||
|
uint8_t probe_mask;
|
||||||
|
uint8_t trigger_mask[NUM_TRIGGER_STAGES];
|
||||||
|
uint8_t trigger_value[NUM_TRIGGER_STAGES];
|
||||||
|
int trigger_stage;
|
||||||
|
uint8_t trigger_buffer[NUM_TRIGGER_STAGES];
|
||||||
|
/*
|
||||||
|
* opaque session data passed in by the frontend, will be passed back
|
||||||
|
* on the session bus along with samples.
|
||||||
|
*/
|
||||||
|
void *session_data;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* SALEAE_LOGIC_H_ */
|
Loading…
Reference in New Issue