ikalogic-scanaquad: device init stuff

This commit is contained in:
Triss 2021-06-25 03:02:51 +02:00
parent d1074befa3
commit 638bdaec16
3 changed files with 191 additions and 40 deletions

View File

@ -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;
} }

View File

@ -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)

View File

@ -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);