ikalogic-scanaquad: device init stuff
This commit is contained in:
parent
d1074befa3
commit
638bdaec16
|
@ -21,10 +21,13 @@
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
|
||||||
#define USB_VENDOR_ID 0x0403
|
#define USB_VENDOR_ID 0x0403
|
||||||
#define USB_DEVICE_ID 0x7fd0
|
#define USB_PRODUCT_ID 0x7fd0
|
||||||
|
|
||||||
#define USB_IPRODUCT_50 "ScanaQuad SQ50"
|
#define USB_IPRODUCT_25 "ScanaQuad SQ25"
|
||||||
|
#define USB_IPRODUCT_50 "ScanaQuad SQ50"
|
||||||
|
#define USB_IPRODUCT_100 "ScanaQuad SQ100"
|
||||||
|
#define USB_IPRODUCT_200 "ScanaQuad SQ200"
|
||||||
|
|
||||||
static struct sr_dev_driver ikalogic_scanaquad_driver_info;
|
static struct sr_dev_driver ikalogic_scanaquad_driver_info;
|
||||||
|
|
||||||
|
@ -38,20 +41,21 @@ static const uint32_t devopts[] = {
|
||||||
// * VOLTAGE_THRESHSOLD vs LOGIC_THRESHOLD
|
// * VOLTAGE_THRESHSOLD vs LOGIC_THRESHOLD
|
||||||
// * VOLTAGE/VOLTAGE_TARGET: max?
|
// * VOLTAGE/VOLTAGE_TARGET: max?
|
||||||
// * triggers: TRIGGER_SLOPE vs TRIGGER_SOURCE vs TRIGGER_MATCH vs TRIGGER_LEVEL vs TRIGGER_PATTERN
|
// * triggers: TRIGGER_SLOPE vs TRIGGER_SOURCE vs TRIGGER_MATCH vs TRIGGER_LEVEL vs TRIGGER_PATTERN
|
||||||
|
// * TRIGGER_SLOPE: probably dV/dt thing? so not applicable here
|
||||||
// * OUTPUT_FREQUENCY used in PATTERN_MODE?
|
// * OUTPUT_FREQUENCY used in PATTERN_MODE?
|
||||||
// * DATALOG: effect?
|
// * DATALOG: effect?
|
||||||
SR_CONF_CONN | SR_CONF_GET,
|
SR_CONF_CONN | SR_CONF_GET,
|
||||||
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||||
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
|
||||||
SR_CONF_PATTERN_MODE | SR_CONF_GET | SR_CONF_SET,
|
//SR_CONF_PATTERN_MODE | SR_CONF_GET | SR_CONF_SET, // TODO: idk how this works
|
||||||
SR_CONF_BUFFERSIZE | SR_CONF_GET | SR_CONF_SET,
|
//SR_CONF_BUFFERSIZE | SR_CONF_GET | SR_CONF_SET, // TODO: ???
|
||||||
SR_CONF_LOGIC_THRESHOLD | SR_CONFIG_GET | SR_CONFIG_SET | SR_CONFIG_LIST,
|
//SR_CONF_LOGIC_THRESHOLD | SR_CONFIG_GET | SR_CONFIG_SET | SR_CONFIG_LIST, // TODO: or VOLTAGE_THRESHOLD?
|
||||||
/* TODO: LOGIC_THRESHOLD_CUSTOM ? does the hw support this? */
|
/* TODO: LOGIC_THRESHOLD_CUSTOM ? does the hw support this? */
|
||||||
SR_CONF_OUTPUT_FREQUENCY | SR_CONFIG_GET | SR_CONFIG_SET | SR_CONFIG_LIST,
|
//SR_CONF_OUTPUT_FREQUENCY | SR_CONFIG_GET | SR_CONFIG_SET | SR_CONFIG_LIST, // TODO: is this used??
|
||||||
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
||||||
SR_CONF_LIMIT_FRAMES | SR_CONF_GET | SR_CONF_SET,
|
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||||
SR_CONF_DATALOG
|
/*SR_CONF_LIMIT_FRAMES | SR_CONF_GET | SR_CONF_SET, "frame is a single capture" -> don't use */
|
||||||
|
//SR_CONF_DATALOG // TODO: ????
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *channel_names[] = {
|
static const char *channel_names[] = {
|
||||||
|
@ -65,46 +69,173 @@ static const uint64_t samplerates[] = {
|
||||||
SR_KHZ(500), SR_KHZ(250), SR_KHZ(100), SR_KHZ(50), SR_KHZ(10)
|
SR_KHZ(500), SR_KHZ(250), SR_KHZ(100), SR_KHZ(50), SR_KHZ(10)
|
||||||
};
|
};
|
||||||
|
|
||||||
static void clear_helper(struct dev_context *dc)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
static int dev_clear(struct sr_dev_driver *di)
|
static int dev_clear(struct sr_dev_driver *di)
|
||||||
{
|
{
|
||||||
return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
|
return std_dev_clear_with_callback(di, (std_dev_clear_callback)sq_destroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
{
|
{
|
||||||
struct drv_context *drvc;
|
struct sr_dev_inst *sdi;
|
||||||
GSList *devices;
|
struct drv_context *dc;
|
||||||
|
struct ftdi_context *ft;
|
||||||
|
char *manuf, *prod, *serial;
|
||||||
|
unsigned int i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
(void)options;
|
(void)options;
|
||||||
|
|
||||||
devices = NULL;
|
if (!(ft = ftdi_new())) {
|
||||||
drvc = di->context;
|
sr_err("Failed to initialize libftdi.");
|
||||||
drvc->instances = NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: scan for devices, either based on a SR_CONF_CONN option
|
dc = sq_new(ft);
|
||||||
* or on a USB scan. */
|
if (dc == NULL) {
|
||||||
|
sr_err("Failed to initialize ScanaQuad device context.");
|
||||||
|
ftdi_free(ft);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return devices;
|
/* open the FTDI device for a second to 1) check it exists, and
|
||||||
|
* 2) check which device it is from the SQ series */
|
||||||
|
|
||||||
|
rv = ftdio_usb_open(ft, USB_VENDOR_ID, USB_PRODUCT_ID);
|
||||||
|
if (rv < 0) {
|
||||||
|
if (rv != -3) { /* -3: device not found */
|
||||||
|
sr_err("Failed to open device (%d): %s", rv, ftdi_get_error_string(ft));
|
||||||
|
sq_destroy(dc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
manuf = gmalloc0(256);
|
||||||
|
prod = gmalloc0(256);
|
||||||
|
serial = gmalloc0(256);
|
||||||
|
rv = ftdio_eeprom_get_strings(ft, manuf, 256, prod, 256, serial, 256);
|
||||||
|
if (rv < 0) {
|
||||||
|
sr_err("Failed to get device info strings (%d): %s", rv, ftdi_get_error_string(ft));
|
||||||
|
gfree(serial);
|
||||||
|
gfree(prod );
|
||||||
|
gfree(manuf );
|
||||||
|
sq_destroy(dc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ftdi_usb_close(ft); /* enough for now */
|
||||||
|
|
||||||
|
if (!strcmp(manuf, "IKALOGIC")) {
|
||||||
|
sr_warn("Unexpected manufacturer name %s!", manuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(prod, USB_IPRODUCT_25)) {
|
||||||
|
dc->devtype = 25;
|
||||||
|
dc->memsize = MAX_MEMSIZE_SQ50 / 2;
|
||||||
|
sr_info(prod);
|
||||||
|
} else if (!strcmp(prod, USB_IPRODUCT_50)) {
|
||||||
|
dc->devtype = 50;
|
||||||
|
dc->memsize = MAX_MEMSIZE_SQ50;
|
||||||
|
sr_info(prod);
|
||||||
|
} else if (!strcmp(prod, USB_IPRODUCT_100)) {
|
||||||
|
dc->devtype = 100;
|
||||||
|
dc->memsize = MAX_MEMSIZE_SQ50 * 2;
|
||||||
|
sr_info(prod);
|
||||||
|
} else if (!strcmp(prod, USB_IPRODUCT_200)) {
|
||||||
|
dc->devtype = 200;
|
||||||
|
dc->memsize = MAX_MEMSIZE_SQ50 * 4;
|
||||||
|
sr_info(prod);
|
||||||
|
} else {
|
||||||
|
sr_warn("Unexpected product name %s! Assuming SQ50 behavior...", prod);
|
||||||
|
}
|
||||||
|
|
||||||
|
sr_info("ScanaQuad serial number: %s", serial);
|
||||||
|
|
||||||
|
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
||||||
|
sdi->status = SR_ST_INACTIVE;
|
||||||
|
sdi->vendor = g_strdup(manuf);
|
||||||
|
sdi->model = g_strdup(prod);
|
||||||
|
sdi->priv = dc;
|
||||||
|
|
||||||
|
gfree(serial);
|
||||||
|
gfree(prod );
|
||||||
|
gfree(manuf );
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(channel_names); ++i)
|
||||||
|
sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE/*TODO:?*/, channel_names[i]);
|
||||||
|
|
||||||
|
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CHECK_FTDI_RETVAL(msg, ft, rv) \
|
||||||
|
do { \
|
||||||
|
if ((rv) < 0) { \
|
||||||
|
sr_err(msg " (%d): %s.\n", (rv), ftdi_get_error_string(ft)); \
|
||||||
|
return SR_ERR; \
|
||||||
|
} \
|
||||||
|
} while (0) \
|
||||||
|
|
||||||
|
#define CHECK_SQ_RETVAL(msg, ft, rv) \
|
||||||
|
do { \
|
||||||
|
if ((rv) < 0) { \
|
||||||
|
sr_err(msg " (%d).\n", (rv)); \
|
||||||
|
return SR_ERR; \
|
||||||
|
} \
|
||||||
|
} while (0) \
|
||||||
|
|
||||||
static int dev_open(struct sr_dev_inst *sdi)
|
static int dev_open(struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
(void)sdi;
|
struct dev_context *dc;
|
||||||
|
int rv;
|
||||||
|
|
||||||
/* TODO: get handle from sdi->conn and open it. */
|
dc = sdi->priv;
|
||||||
|
|
||||||
return SR_OK;
|
rv = ftdi_set_interface(dc->ft, INTERFACE_A);
|
||||||
|
CHECK_FTDI_RETVAL("Failed to set FTDI interface A", dc->ft, rv);
|
||||||
|
|
||||||
|
rv = ftdi_usb_open(dc->ft, USB_VENDOR_ID, USB_PRODUCT_ID);
|
||||||
|
CHECK_FTDI_RETVAL("Failed to open FTDI device", dc->ft, rv);
|
||||||
|
|
||||||
|
rv = ftdi_tcioflush(dc->ft);
|
||||||
|
CHECK_FTDI_RETVAL("Failed to purge buffers", dc->ft, rv);
|
||||||
|
|
||||||
|
rv = ftdi_set_latency_timer(dc->ft, 2);
|
||||||
|
CHECK_FTDI_RETVAL("Failed to set FTDI latency timer", dc->ft, rv);
|
||||||
|
|
||||||
|
rv = ftdi_read_data_set_chunksize(dc->ft, 64*1024); /* TODO: is this the right size? */
|
||||||
|
CHECK_FTDI_RETVAL("Failed to set FTDI read data chunk size", dc->ft, rv);
|
||||||
|
|
||||||
|
return scanaquad_init(dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_close(struct sr_dev_inst *sdi)
|
static int dev_close(struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
(void)sdi;
|
struct dev_context *dc;
|
||||||
|
int rv;
|
||||||
|
|
||||||
/* TODO: get handle from sdi->conn and close it. */
|
dc = sdi->priv;
|
||||||
|
|
||||||
|
rv = sq_get_status(dc);
|
||||||
|
CHECK_SQ_RETVAL(rv, "Failed to get ScanaQuad status", rv);
|
||||||
|
if (rv == sq_status_app) {
|
||||||
|
/* cancel ongoing capture/wait-for-trigger */
|
||||||
|
rv = sq_app_cancel_capture(dc);
|
||||||
|
CHECK_SQ_RETVAL(rv, "Failed to cancel ongoing SC/WFT", rv);
|
||||||
|
|
||||||
|
/* cancel ongoing pattern generation */
|
||||||
|
rv = sq_app_apply_default_settings(dc);
|
||||||
|
CHECK_SQ_RETVAL(rv, "Failed to apply default settings", rv);
|
||||||
|
|
||||||
|
/* cancel ongoing capture/wait-for-trigger */
|
||||||
|
rv = sq_app_cancel_capture(dc);
|
||||||
|
CHECK_SQ_RETVAL(rv, "Failed to cancel ongoing SC/WFT", rv);
|
||||||
|
|
||||||
|
/* cancel ongoing pattern generation */
|
||||||
|
rv = sq_app_apply_default_settings(dc);
|
||||||
|
CHECK_SQ_RETVAL(rv, "Failed to apply default settings", rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = ftdi_usb_close(dc->ft);
|
||||||
|
CHECK_FTDI_RETVAL("Failed to close FTDI device", dc->ft, rv);
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,16 +31,6 @@ SR_PRIV struct dev_context *sq_new(struct ftdi_context *ft)
|
||||||
dc = (struct dev_context *)gmalloc0(sizeof(struct dev_context));
|
dc = (struct dev_context *)gmalloc0(sizeof(struct dev_context));
|
||||||
dc->ft = ft;
|
dc->ft = ft;
|
||||||
|
|
||||||
rv = ftdi_tcioflush(ft);
|
|
||||||
if (rv == -3 /* USB device unavailable */) {
|
|
||||||
sr_err("ftdi_tcioflush: (%d) USB device unavailable", rv);
|
|
||||||
|
|
||||||
dc->ft = NULL;
|
|
||||||
gfree(dc);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* other errors (failed to purge buffers): eh, let's ignore that */
|
|
||||||
|
|
||||||
return dc;
|
return dc;
|
||||||
}
|
}
|
||||||
SR_PRIV void sq_destroy(struct dev_context *dc)
|
SR_PRIV void sq_destroy(struct dev_context *dc)
|
||||||
|
@ -432,6 +422,25 @@ SR_PRIV sq_app_apply_triggers(struct dev_context *dc, const struct sq_app_trigst
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SR_PRIV int sq_app_apply_default_settings(struct dev_context *dc)
|
||||||
|
{
|
||||||
|
/* buffer sizes meant for SQ25, but won't hurt on others I guess */
|
||||||
|
static const uint8_t send_sdef_cmd[25] = {
|
||||||
|
0xf1,
|
||||||
|
0x01, 0x04, 0x00, 0x00, 0x00, 0x48, 0xe8, 0x01,
|
||||||
|
0x48, 0xe8, 0x01, 0x08, 0x28, 0xf1, 0x00, 0x00,
|
||||||
|
0xf0, 0x0f, 0x0f, 0x81, 0x4b, 0x32, 0x01, 0x00
|
||||||
|
};
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
sr_spew("apply default settings");
|
||||||
|
|
||||||
|
rv = ftdi_write_data(dc->ft, send_sdef_cmd, sizeof send_sdef_cmd);
|
||||||
|
CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_sdef_cmd);
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* higher-level routines (finally) */
|
/* higher-level routines (finally) */
|
||||||
SR_PRIV int scanaquad_init(struct dev_context *dc)
|
SR_PRIV int scanaquad_init(struct dev_context *dc)
|
||||||
{
|
{
|
||||||
|
@ -495,9 +504,7 @@ SR_PRIV int scanaquad_init(struct dev_context *dc)
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: send default settings? */
|
return sq_app_apply_default_settings(dc);
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV int ikalogic_scanaquad_receive_data(int fd, int revents, void *cb_data)
|
SR_PRIV int ikalogic_scanaquad_receive_data(int fd, int revents, void *cb_data)
|
||||||
|
|
|
@ -30,9 +30,19 @@
|
||||||
|
|
||||||
#define LOG_PREFIX "ikalogic-scanaquad"
|
#define LOG_PREFIX "ikalogic-scanaquad"
|
||||||
|
|
||||||
|
#define MAX_MEMSIZE_SQ50 0x03d090
|
||||||
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
struct ftdi_context *ft;
|
struct ftdi_context *ft;
|
||||||
|
|
||||||
|
/* settings for next capture */
|
||||||
|
uint64_t samplerate;
|
||||||
|
float voltage;
|
||||||
|
float total_buffer_usage_percent;
|
||||||
|
float pretrigger_percent;
|
||||||
|
|
||||||
|
uint32_t memsize_max;
|
||||||
|
int devtype; /* 25, 50, 100 or 200 for SQ25, SQ50, and so on */
|
||||||
uint8_t devid[3];
|
uint8_t devid[3];
|
||||||
gboolean has_devid;
|
gboolean has_devid;
|
||||||
};
|
};
|
||||||
|
@ -120,6 +130,9 @@ SR_PRIV int sq_app_start_generate_once(struct dev_context *dc);
|
||||||
SR_PRIV int sq_app_apply_settings(struct dev_context *dc, const struct sq_app_settings *sett);
|
SR_PRIV int sq_app_apply_settings(struct dev_context *dc, const struct sq_app_settings *sett);
|
||||||
SR_PRIV int sq_app_apply_triggers(struct dev_context *dc, const struct sq_app_trigstep *steps, size_t nsteps);
|
SR_PRIV int sq_app_apply_triggers(struct dev_context *dc, const struct sq_app_trigstep *steps, size_t nsteps);
|
||||||
|
|
||||||
|
/* useful at device init & reset, as it cancels ongoing signal generator stuff */
|
||||||
|
SR_PRIV int sq_app_apply_default_settings(struct dev_context *dc);
|
||||||
|
|
||||||
/* higher-level stuff used by api.c */
|
/* higher-level stuff used by api.c */
|
||||||
|
|
||||||
SR_PRIV int scanaquad_init(struct dev_context *devc);
|
SR_PRIV int scanaquad_init(struct dev_context *devc);
|
||||||
|
|
Loading…
Reference in New Issue