From d8f08acdc303be74c5f4991284293913f57c8aa7 Mon Sep 17 00:00:00 2001 From: sys64738 Date: Thu, 24 Jun 2021 02:43:49 +0200 Subject: [PATCH] ikalogic-scanaquad: low-level protocol stuff --- configure.ac | 2 +- src/hardware/ikalogic-scanaquad/api.c | 3 +- src/hardware/ikalogic-scanaquad/protocol.c | 482 ++++++++++++++++++++- src/hardware/ikalogic-scanaquad/protocol.h | 97 ++++- 4 files changed, 579 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index db16ec55..fc8b371d 100644 --- a/configure.ac +++ b/configure.ac @@ -289,7 +289,7 @@ SR_DRIVER([hp-59306a], [hp-59306a]) SR_DRIVER([Hung-Chang DSO-2100], [hung-chang-dso-2100], [libieee1284]) SR_DRIVER([Ikalogic Scanalogic-2], [ikalogic-scanalogic2], [libusb]) SR_DRIVER([Ikalogic Scanaplus], [ikalogic-scanaplus], [libftdi]) -SR_DRIVER([Ikalogic ScanaQuad], [ikalogic-scanaquad]) +SR_DRIVER([Ikalogic ScanaQuad], [ikalogic-scanaquad], [libftdi]) SR_DRIVER([IPDBG LA], [ipdbg-la]) SR_DRIVER([ITECH IT8500], [itech-it8500], [serial_comm]) SR_DRIVER([Kecheng KC-330B], [kecheng-kc-330b], [libusb]) diff --git a/src/hardware/ikalogic-scanaquad/api.c b/src/hardware/ikalogic-scanaquad/api.c index e8374479..599f7d1f 100644 --- a/src/hardware/ikalogic-scanaquad/api.c +++ b/src/hardware/ikalogic-scanaquad/api.c @@ -1,7 +1,8 @@ /* * This file is part of the libsigrok project. * - * Copyright (C) 2021 sys64738 + * Copyright (C) 2021 sys64738 , + * haskal * * 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 diff --git a/src/hardware/ikalogic-scanaquad/protocol.c b/src/hardware/ikalogic-scanaquad/protocol.c index dfcd94c2..0a3d411d 100644 --- a/src/hardware/ikalogic-scanaquad/protocol.c +++ b/src/hardware/ikalogic-scanaquad/protocol.c @@ -1,7 +1,8 @@ /* * This file is part of the libsigrok project. * - * Copyright (C) 2021 sys64738 + * Copyright (C) 2021 sys64738 , + * haskal * * 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 @@ -20,6 +21,485 @@ #include #include "protocol.h" +SR_PRIV struct dev_context *sq_new(struct ftdi_context *ft) +{ + struct dev_context *dc; + int rv; + + if (!ft) return NULL; + + 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) +{ + if (!dc) return; + + if (dc->ft) { + ftdi_free(dc->ft); + dc->ft = NULL; + } + gfree(dc); +} + +#define CHECK_FTDI_RETVAL(write, ft, rv, expect, ...) \ + do { \ + if ((rv) < 0) { \ + sr_err("Failed to %s FTDI data (%d): %s.\n", (write)?"write":"read", (rv), \ + ftdi_get_error_string(ft)); \ + return SR_ERR; \ + } else if ((rv) != (expect) __VA_OPT__(&& __VA_ARGS__)) { \ + sr_err("FTDI %s error, only %d/%zu bytes %s: %s.", (write)?"write":"read",\ + (rv), expect, (write)?"written":"read", ftdi_get_error_string(ft)); \ + return SR_ERR; \ + } \ + } while (0) \ + +#define CHECK_SQ_RETVAL(rv, fmt, ...) \ + do { \ + if ((rv) < SR_ERR) { \ + if (FALSE) { \ + sr_err(fmt " (%d): %s", ##__VA_ARGS__ , (rv), ftdi_get_error_string(/*ft*/NULL)); \ + } else { \ + sr_err(fmt, ##__VA_ARGS__); \ + } \ + return rv; \ + } \ + } while (0) \ + +/* low-level commands */ + +SR_PRIV int sq_get_status(struct dev_context *dc) +{ + static const uint8_t get_status_cmd[] = {0xfd,0x00,0x01,0x02,0xfe}; + uint8_t stat[4]; + int rv; + + if (!dc) return SR_ERR; + + rv = ftdi_write_data(dc->ft, get_status_cmd, sizeof get_status_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof get_status_cmd); + + rv = ftdi_read_data(dc->ft, stat, sizeof stat); + CHECK_FTDI_RETVAL(FALSE, dc->ft, rv, sizeof stat); + + if (stat[0] != staƧ[1] || stat[0] != stat[2] || staƧ[0] != stat[3]) + sr_warn("status: incoherent: %02x %02x %02x %02x", stat[0], stat[1], stat[2], stat[3]); + else + sr_spew("status: %02x", stat[0]); + + return stat[0]; /* array contains the same value 4 times */ +} +SR_PRIV int sq_reset_app(struct dev_context *dc) +{ + static const uint8_t go_app_cmd[] = {0x93}; + int rv; + + if (!dc) return SR_ERR; + + sr_spew("reset to app"); + rv = ftdi_write_data(dc->ft, go_app_cmd, sizeof go_app_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof go_app_cmd); + + return SR_OK; +} +SR_PRIV int sq_reset_bl(struct dev_context *dc) +{ + static const uint8_t go_bl_cmd[] = {0x94}; + int rv; + + if (!dc) return SR_ERR; + + sr_spew("reset to bl"); + rv = ftdi_write_data(dc->ft, go_bl_cmd, sizeof go_bl_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof go_bl_cmd); + + return SR_OK; + +} +SR_PRIV int sq_get_devid_from_eeprom(struct dev_context *dc, uint8_t *devid) +{ + int val1, val2, rv; + + if (!dc) return SR_ERR; + + if ((rv = ftdi_read_eeprom_location(dc->ft, 0x12, &val1)) < 0) { + sr_err("Failed to read EEPROM index 0x12 (%d): %s.", + ret, ftdi_get_error_string(dc->ft)); + return SR_ERR; + } + if ((rv = ftdi_read_eeprom_location(dc->ft, 0x13, &val2)) < 0) { + sr_err("Failed to read EEPROM index 0x13 (%d): %s.", + ret, ftdi_get_error_string(dc->ft)); + return SR_ERR; + } + + devid[0] = (val1 >> 0) & 0xff; + devid[1] = (val1 >> 8) & 0xff; + devid[2] = (val2 >> 0) & 0xff; + + sr_dbg("got devid %02x %02x %02x", devid[0], devid[1], devid[2]); + + return SR_OK; +} + +SR_PRIV int sq_bl_send_devid(struct dev_context *dc, const uint8_t *devid) +{ + uint8_t send_devid_cmd[27] = {0xf1, 0,0,0, 0}; + int rv; + + if (!dc || !devid) return SR_ERR; + + send_devid_cmd[1] = devid[0]; + send_devid_cmd[2] = devid[1]; + send_devid_cmd[3] = devid[2]; + + sr_spew("auth with devid %02x %02x %02x", devid[0], devid[1], devid[2]); + + rv = ftdi_write_data(dc->ft, send_devid_cmd, sizeof send_devid_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_devid_cmd); + return SR_OK; +} +SR_PRIV int sq_bl_spi_chipsel(struct dev_context *dc) +{ + static const uint8_t send_spi_chipsel_cmd[2] = {0x90,0x00}; + int rv; + + if (!dc) return SR_ERR; + + sr_spew("SPI chip select"); + + rv = ftdi_write_data(dc->ft, send_spi_chipsel_cmd, sizeof send_spi_chipsel_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_spi_chipsel_cmd); + return SR_OK; +} +SR_PRIV int sq_bl_spi_chipdesel(struct dev_context *dc) +{ + static const uint8_t send_spi_chipdesel_cmd[2] = {0x91,0x00}; + int rv; + + if (!dc) return SR_ERR; + + sr_spew("SPI chip deselect"); + + rv = ftdi_write_data(dc->ft, send_spi_chipdesel_cmd, sizeof send_spi_chipdesel_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_spi_chipdesel_cmd); + return SR_OK; +} +SR_PRIV int sq_bl_spi_xfer(struct dev_context *dc, uint8_t val) +{ + uint8_t send_spi_xfer_cmd[2] = {0x92, 0}; + int rv; + uint8_t read = 0; + + if (!dc) return SR_ERR; + + rv = ftdi_write_data(dc->ft, send_spi_xfer_cmd, sizeof send_spi_xfer_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_spi_xfer_cmd); + + rv = ftdi_read_data(dc->ft, &read, 1); + CHECK_FTDI_RETVAL(FALSE, dc->ft, rv, 1); + + sr_spew("SPI xfer: %02x -> %02x", val, read); + + return read; +} + +SR_PRIV int sq_app_cancel_capture(struct dev_context *dc) +{ + static const uint8_t send_capture_cancel_cmd[] = {0xf0,0x00}; + int rv; + + if (!dc) return SR_ERR; + + sr_spew("cancel sc/wft"); + + rv = ftdi_write_data(dc->ft, send_capture_cancel_cmd, sizeof send_capture_cancel_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_capture_cancel_cmd); + + return SR_OK; +} +SR_PRIV int sq_app_start_capture(struct dev_context *dc) +{ + static const uint8_t send_start_capture_cmd[] = {0xf0,0x01}; + uint8_t result[4]; + int rv; + + if (!dc) return SR_ERR; + + sr_spew("sc/wft"); + + rv = ftdi_write_data(dc->ft, send_start_capture_cmd, sizeof send_start_capture_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_start_capture_cmd); + + return SR_OK; +} +SR_PRIV int sq_app_get_capture_result(struct dev_context *dc, uint32_t *trig_instant) +{ + uint8_t result[4]; + int rv; + + if (!dc || !trig_instant) return SR_ERR; + + rv = ftdi_read_data(dc->ft, result, sizeof result); + CHECK_FTDI_RETVAL(FALSE, dc->ft, rv, sizeof result); + + *trig_instant = (uint32_t)result[0] | ((uint32_t)result[1] << 8) | ((uint32_t)result[2] << 16); + + sr_spew("sc/wft -> %06x %02x", *trig_instant, result[3]); + + return result[3]; +} +SR_PRIV int sq_app_start_generate_inf(struct dev_context *dc) +{ + static const uint8_t send_start_geninf_cmd[] = {0xf0,0x02}; + int rv; + + if (!dc) return SR_ERR; + + sc_spew("start generate inf"); + + rv = ftdi_write_data(dc->ft, send_start_geninf_cmd, sizeof send_start_geninf_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_start_geninf_cmd); + + return SR_OK; +} +SR_PRIV int sq_app_start_capgenmix(struct dev_context *dc) +{ + static const uint8_t send_start_capture_cmd[] = {0xf0,0x03}; + int rv; + + if (!dc) return SR_ERR; + + sr_spew("start mixed sc/g/wft"); + + rv = ftdi_write_data(dc->ft, send_start_capgenmix_cmd, sizeof send_start_capgenmix_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_start_capgenmix_cmd); + + return SR_OK; +} +SR_PRIV int sq_app_upload_genpattern(struct dev_context *dc, const void *data, size_t len) +{ + static const uint8_t send_upl_genpat_cmd[] = {0xf0,0x05,0xf3}; + int rv; + size_t pos = 0; + + if (!dc || !data || !len) return SR_ERR; + + sr_spew("upload genpatt %zx", len); + + rv = ftdi_write_data(dc->ft, send_upl_genpat_cmd, sizeof send_upl_genpat_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_upl_genpat_cmd); + + do { + rv = ftdi_write_data(dc->ft, (const uint8_t *)data + pos, len - pos); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, len, FALSE); + + pos += rv; + } while (pos < len); + + return SR_OK; +} +SR_PRIV int sq_app_download_capture(struct dev_context *dc, void *data, size_t len) +{ + static const uint8_t send_dl_capt_cmd[] = {0xf0,0x06}; + int rv; + size_t pos = 0; + + if (!dc || !data || !len) return SR_ERR; + + sr_spew("download capture %zx", len); + + rv = ftdi_write_data(dc->ft, send_dl_capt_cmd, sizeof send_dl_capt_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_dl_capt_cmd); + + do { + rv = ftdi_read_data(dc->ft, (uint8_t *)data + pos, len - pos); + CHECK_FTDI_RETVAL(FALSE, dc->ft, rv, len, FALSE); + + pos += rv; + } while (pos < len); + + return SR_OK; +} +SR_PRIV sq_app_start_generate_once(struct dev_context *dc) +{ + static const uint8_t send_start_genonce_cmd[] = {0xf0,0x07}; + int rv; + + if (!dc) return SR_ERR; + + sr_spew("start generate once"); + + rv = ftdi_write_data(dc->ft, send_start_genonce_cmd, sizeof send_start_genonce_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_start_genonce_cmd); + + return SR_OK; +} + +SR_PRIV sq_app_apply_settings(struct dev_context *dc, const struct sq_app_settings *sett) +{ + uint8_t send_sett_cmd[25] = {0xf1, 0}; + uint8_t *blob; + int rv; + + if (!dc || !sett) return SR_ERR; + + blob = &send_sett_cmd[1]; /* so i wont mess up offsets while writing this code */ + + blob[0x00] = sett->trigscale_us; + blob[0x01] = sett->clockfreq & 0xff; + blob[0x02] = (sett->clockfreq>>8) & 0xff; + blob[0x03] = sett->trigger_pw_scale & 0xff; + blob[0x04] = (sett->trigger_pw_scale>>8) & 0xff; + blob[0x05] = sett->memsetting1[0]; + blob[0x06] = sett->memsetting1[1]; + blob[0x07] = sett->memsetting1[2]; + blob[0x08] = sett->memsetting2[0]; + blob[0x09] = sett->memsetting2[1]; + blob[0x0a] = sett->memsetting2[2]; + blob[0x0b] = sett->memsetting3[0]; + blob[0x0c] = sett->memsetting3[1]; + blob[0x0d] = sett->memsetting3[2]; + blob[0x0e] = 0; + blob[0x0f] = sett->ntrigsteps; + blob[0x10] = 0xf0; + blob[0x11] = 0x0f; + blob[0x12] = sett->chanoutmap; + blob[0x13] = sett->voltage[0]; + blob[0x14] = sett->voltage[1]; + blob[0x15] = 0x32; + blob[0x16] = sett->capture ? 0x01 : 0x00; + blob[0x17] = sett->generate ? 0x01 : 0x00; + + sr_spew("apply settings"); /* TODO: print info about applied settings */ + + rv = ftdi_write_data(dc->ft, send_sett_cmd, sizeof send_sett_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_sett_cmd); + + return SR_OK; +} +SR_PRIV sq_app_apply_triggers(struct dev_context *dc, const struct sq_app_trigstep *steps, size_t nsteps) +{ + uint8_t *send_trig_cmd; + size_t i, blobsize; + uint32_t bitfield; + int rv; + + if (!dc || !steps || !nsteps) return SR_ERR; + + /* nsteps shouldn't exceed 8 or so */ + blobsize = 1 + nsteps * 4; + send_trig_cmd = (uint8_t *)gmalloc0(blobsize); + send_trig_cmd[0] = 0xf4; + + for (i = 0; i < nsteps; ++i) { + bitfield = 0; + + bitfield |= (steps[i].level ? 1 : 0) << 31; + bitfield |= (steps[i].pw_max & 0x1ff) << 21; + bitfield |= (steps[i].lvloverride ? 1 : 0) << 20; + bitfield |= (steps[i].pw_min & 0x1ff) << 10; + bitfield |= (steps[i].ch_ignore & 0xf) << 6; + bitfield |= (steps[i].nomax ? 1 : 0) << 5; + bitfield |= (steps[i].nomin ? 1 : 0) << 4; + bitfield |= (steps[i].ch_hi_rise_lo_fall & 0xf) << 0; + + send_trig_cmd[1 + i*4 + 0] = (bitfield>> 0)&0xff; + send_trig_cmd[1 + i*4 + 1] = (bitfield>> 8)&0xff; + send_trig_cmd[1 + i*4 + 2] = (bitfield>>16)&0xff; + send_trig_cmd[1 + i*4 + 3] = (bitfield>>14)&0xff; + } + + sr_spew("apply triggers"); /* TODO: print info about applied triggers */ + + rv = ftdi_write_data(dc->ft, send_trig_cmd, blobsize); + gfree(send_trig_cmd); + CHECK_FTDI_RETVAL(TRUE, dc->ft, rv, sizeof send_trig_cmd); + + return SR_OK; +} + +/* higher-level routines (finally) */ +SR_PRIV int scanaquad_init(struct dev_context *dc) +{ + size_t i; + int rv; + + sr_info("scanaquad: init!"); + + rv = sq_get_status(dc); + CHECK_SQ_RETVAL(rv, "couldn't get status"); + + if (rv == sq_status_app) { + rv = sq_app_cancel_capture(dc); + CHECK_SQ_RETVAL(rv, "couldn't cancel capture/wait-for-trigger"); + } + + rv = sq_reset_bl(dc); + CHECK_SQ_RETVAL(rv, "couldn't reset to bootloader"); + + /* wait until we are in bootloader mode */ + for (i = 0; i < 0x1000; ++i) { + rv = sq_get_status(dc); + CHECK_SQ_RETVAL(rv, "couldn't get status"); + if (rv != sq_status_app) break; + } + if (rv == sq_status_app) { + sr_err("Failed to enter bootloader mode (timed out)"); + return SR_ERR; + } + + if (!dc->has_devid) { + rv = sq_get_devid_from_eeprom(dc, &dc->devid[0]); + CHECK_SQ_RETVAL(rv, "couldn't get magic device ID"); + dc->has_devid = TRUE; + } + + rv = sq_bl_send_devid(dc, dc->devid); + CHECK_SQ_RETVAL(rv, "couldn't send magic device ID"); + + for (i = 0; i < 0x1000 /* should be enough */; ++i) { + rv = sq_get_status(dc); + CHECK_SQ_RETVAL(rv, "couldn't get status"); + if (rv == sq_status_bl_auth) break; + } + if (rv != sq_status_bl_auth) { + sr_err("Failed to authenticate ScanaQuad device (timed out)... devid=%02x %02x %02x", + dc->devid[0], dc->devid[1], dc->devid[2]); + return SR_ERR; + } + + rv = sq_reset_app(dc); + CHECK_SQ_RETVAL(rv, "couldn't reset to application"); + + for (i = 0; i < 0x1000 /* should be enough */; ++i) { + rv = sq_get_status(dc); + CHECK_SQ_RETVAL(rv, "couldn't get status"); + if (rv == sq_status_app) break; + } + if (rv != sq_status_app) { + sr_err("Failed to enter application mode (timed out)"); + return SR_ERR; + } + + /* TODO: send default settings? */ + + return SR_OK; +} + SR_PRIV int ikalogic_scanaquad_receive_data(int fd, int revents, void *cb_data) { const struct sr_dev_inst *sdi; diff --git a/src/hardware/ikalogic-scanaquad/protocol.h b/src/hardware/ikalogic-scanaquad/protocol.h index 8d3e07f7..2861226e 100644 --- a/src/hardware/ikalogic-scanaquad/protocol.h +++ b/src/hardware/ikalogic-scanaquad/protocol.h @@ -1,7 +1,8 @@ /* * This file is part of the libsigrok project. * - * Copyright (C) 2021 sys64738 + * Copyright (C) 2021 sys64738 , + * haskal * * 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 @@ -21,15 +22,107 @@ #define LIBSIGROK_HARDWARE_IKALOGIC_SCANAQUAD_PROTOCOL_H #include +#include #include +#include #include #include "libsigrok-internal.h" #define LOG_PREFIX "ikalogic-scanaquad" struct dev_context { + struct ftdi_context *ft; + + uint8_t devid[3]; + gboolean has_devid; }; -SR_PRIV int ikalogic_scanaquad_receive_data(int fd, int revents, void *cb_data); +enum sq_status { + sq_status_bl_auth = 0x01, + sq_status_bl_boot = 0x09, + sq_status_app = 0x22 +}; +struct sq_app_settings { + uint16_t clockfreq; + uint16_t trigger_pw_scale; + uint8_t memsetting1[3]; + uint8_t memsetting2[3]; + uint8_t memsetting3[3]; + uint8_t voltage[2]; + uint8_t trigscale_us; + uint8_t ntrigsteps; + uint8_t chanoutmap; + + gboolean capture; + gboolean generate; +}; +struct sq_app_trigstep { + uint16_t pw_min; + uint16_t pw_max; + + uint8_t ch_ignore; /* set bit in this mask to ignore a channel */ + uint8_t ch_hi_rise_lo_fall; /* 1 in mask => match high/rise for chan, else low/fall */ + + gboolean level; /* false: edge */ + gboolean lvloverride; + gboolean nomax; + gboolean nomin; +}; + +#define SQ_APP_START_CAPTURE_SUCCESS 0xdd + +SR_PRIV struct dev_context *sq_new(struct ftdi_context *ft); +SR_PRIV void sq_destroy(struct dev_context *dc); + +/* low-level wire protocol functions. see + * https://git.lain.faith/BLAHAJ/sq50-re/wiki/USB-protocol for docs on how + * these work. */ + +/* general commands */ +SR_PRIV int sq_get_status(struct dev_context *dc); +SR_PRIV int sq_reset_app(struct dev_context *dc); +SR_PRIV int sq_reset_bl (struct dev_context *dc); +SR_PRIV int sq_get_devid_from_eeprom(struct dev_context *dc, uint8_t *devid); + +/* bootloader mode commands */ +SR_PRIV int sq_bl_send_devid(struct dev_context *dc, const uint8_t *devid); +SR_PRIV int sq_bl_spi_chipsel(struct dev_context *dc); +SR_PRIV int sq_bl_spi_chipdesel(struct dev_context *dc); +SR_PRIV int sq_bl_spi_xfer(struct dev_context *dc, uint8_t val); +/* two aliases for clarity */ +static inline SR_PRIV int sq_bl_spi_xfer_write(struct dev_context *dc, uint8_t val) +{ + return sq_bl_spi_xfer(dc, val); +} +static inline SR_PRIV int sq_bl_spi_xfer_read(struct dev_context *dc) +{ + return sq_bl_spi_xfer(dc, 0xff); +} + +/* application mode commands */ +/* 0xf0 0x0X commands */ +SR_PRIV int sq_app_cancel_capture(struct dev_context *dc); +SR_PRIV int sq_app_start_capture(struct dev_context *dc); +SR_PRIV int sq_app_get_capture_result(struct dev_context *dc, uint32_t *trig_instant); +SR_PRIV int sq_app_start_generate_inf(struct dev_context *dc); +SR_PRIV int sq_app_start_capgenmix(struct dev_context *dc); +static inline SR_PRIV int sq_app_get_capgenmix_result(struct dev_context *dc, uint32_t *trig_instant) { + return sq_app_get_capture_result(dc, trig_instant); +} +/* NOTE: at this point, no checks are done whether the length of the data is + * consistent with the current capture/genpattern memory size in the + * device's settings */ +SR_PRIV int sq_app_upload_genpattern(struct dev_context *dc, const void *data, size_t len); +SR_PRIV int sq_app_download_capture(struct dev_context *dc, void *data, size_t len); +SR_PRIV int sq_app_start_generate_once(struct dev_context *dc); + +/* 0xf1, 0xf4 */ +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); + +/* higher-level stuff used by api.c */ + +SR_PRIV int scanaquad_init(struct dev_context *devc); +SR_PRIV int scanaquad_receive_data(int fd, int revents, void *cb_data); #endif