diff --git a/src/hardware/ikalogic-scanaquad/api.c b/src/hardware/ikalogic-scanaquad/api.c index ab681b94..ef352b73 100644 --- a/src/hardware/ikalogic-scanaquad/api.c +++ b/src/hardware/ikalogic-scanaquad/api.c @@ -21,10 +21,13 @@ #include #include "protocol.h" -#define USB_VENDOR_ID 0x0403 -#define USB_DEVICE_ID 0x7fd0 +#define USB_VENDOR_ID 0x0403 +#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; @@ -38,20 +41,21 @@ static const uint32_t devopts[] = { // * VOLTAGE_THRESHSOLD vs LOGIC_THRESHOLD // * VOLTAGE/VOLTAGE_TARGET: max? // * 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? // * DATALOG: effect? SR_CONF_CONN | SR_CONF_GET, SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, - SR_CONF_PATTERN_MODE | SR_CONF_GET | SR_CONF_SET, - SR_CONF_BUFFERSIZE | SR_CONF_GET | SR_CONF_SET, - SR_CONF_LOGIC_THRESHOLD | SR_CONFIG_GET | SR_CONFIG_SET | SR_CONFIG_LIST, + //SR_CONF_PATTERN_MODE | SR_CONF_GET | SR_CONF_SET, // TODO: idk how this works + //SR_CONF_BUFFERSIZE | SR_CONF_GET | SR_CONF_SET, // TODO: ??? + //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? */ - 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_FRAMES | 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[] = { @@ -65,46 +69,173 @@ static const uint64_t samplerates[] = { 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) { - 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) { - struct drv_context *drvc; - GSList *devices; + struct sr_dev_inst *sdi; + struct drv_context *dc; + struct ftdi_context *ft; + char *manuf, *prod, *serial; + unsigned int i; + int ret; (void)options; - devices = NULL; - drvc = di->context; - drvc->instances = NULL; + if (!(ft = ftdi_new())) { + sr_err("Failed to initialize libftdi."); + return NULL; + } - /* TODO: scan for devices, either based on a SR_CONF_CONN option - * or on a USB scan. */ + dc = sq_new(ft); + 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) { - (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) { - (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; } diff --git a/src/hardware/ikalogic-scanaquad/protocol.c b/src/hardware/ikalogic-scanaquad/protocol.c index 0a3d411d..517d8d44 100644 --- a/src/hardware/ikalogic-scanaquad/protocol.c +++ b/src/hardware/ikalogic-scanaquad/protocol.c @@ -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->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; } 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; } +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) */ 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; } - /* TODO: send default settings? */ - - return SR_OK; + return sq_app_apply_default_settings(dc); } SR_PRIV int ikalogic_scanaquad_receive_data(int fd, int revents, void *cb_data) diff --git a/src/hardware/ikalogic-scanaquad/protocol.h b/src/hardware/ikalogic-scanaquad/protocol.h index 2861226e..c7b934ea 100644 --- a/src/hardware/ikalogic-scanaquad/protocol.h +++ b/src/hardware/ikalogic-scanaquad/protocol.h @@ -30,9 +30,19 @@ #define LOG_PREFIX "ikalogic-scanaquad" +#define MAX_MEMSIZE_SQ50 0x03d090 + struct dev_context { 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]; 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_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 */ SR_PRIV int scanaquad_init(struct dev_context *devc);