ikalogic-scanaquad: low-level protocol stuff
This commit is contained in:
parent
012becda49
commit
d8f08acdc3
|
@ -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])
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2021 sys64738 <sys64738@disroot.org>
|
||||
* Copyright (C) 2021 sys64738 <sys64738@disroot.org>,
|
||||
* haskal <haskal@awoo.systems>
|
||||
*
|
||||
* 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
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2021 sys64738 <sys64738@disroot.org>
|
||||
* Copyright (C) 2021 sys64738 <sys64738@disroot.org>,
|
||||
* haskal <haskal@awoo.systems>
|
||||
*
|
||||
* 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 <config.h>
|
||||
#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;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2021 sys64738 <sys64738@disroot.org>
|
||||
* Copyright (C) 2021 sys64738 <sys64738@disroot.org>,
|
||||
* haskal <haskal@awoo.systems>
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include <ftdi.h>
|
||||
#include <libsigrok/libsigrok.h>
|
||||
#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
|
||||
|
|
Loading…
Reference in New Issue