From: Uwe Hermann Date: Wed, 28 Jun 2017 06:15:24 +0000 (+0200) Subject: saleae-logic-pro: Driver name consistency fixes. X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=b6189f7c8af7d8eed6bdcf75fa05c95d8120c9b8;p=libsigrok.git saleae-logic-pro: Driver name consistency fixes. --- diff --git a/Makefile.am b/Makefile.am index f5657339..d7280960 100644 --- a/Makefile.am +++ b/Makefile.am @@ -452,11 +452,11 @@ src_libdrivers_la_SOURCES += \ src/hardware/saleae-logic16/protocol.c \ src/hardware/saleae-logic16/api.c endif -if HW_SALEAE_LOGICPRO +if HW_SALEAE_LOGIC_PRO src_libdrivers_la_SOURCES += \ - src/hardware/saleae-logicpro/protocol.h \ - src/hardware/saleae-logicpro/protocol.c \ - src/hardware/saleae-logicpro/api.c + src/hardware/saleae-logic-pro/protocol.h \ + src/hardware/saleae-logic-pro/protocol.c \ + src/hardware/saleae-logic-pro/api.c endif if HW_SCPI_PPS src_libdrivers_la_SOURCES += \ diff --git a/configure.ac b/configure.ac index 9a618769..bf400f55 100644 --- a/configure.ac +++ b/configure.ac @@ -264,7 +264,7 @@ SR_DRIVER([Pipistrello-OLS], [pipistrello-ols], [libftdi]) SR_DRIVER([Rigol DS], [rigol-ds]) SR_DRIVER([Rohde&Schwarz SME-0x], [rohde-schwarz-sme-0x], [libserialport]) SR_DRIVER([Saleae Logic16], [saleae-logic16], [libusb]) -SR_DRIVER([Saleae Logic Pro], [saleae-logicpro], [libusb]) +SR_DRIVER([Saleae Logic Pro], [saleae-logic-pro], [libusb]) SR_DRIVER([SCPI PPS], [scpi-pps]) SR_DRIVER([serial DMM], [serial-dmm], [libserialport]) SR_DRIVER([serial LCR], [serial-lcr], [libserialport]) diff --git a/src/hardware/saleae-logic-pro/api.c b/src/hardware/saleae-logic-pro/api.c new file mode 100644 index 00000000..74bf7cce --- /dev/null +++ b/src/hardware/saleae-logic-pro/api.c @@ -0,0 +1,441 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2017 Jan Luebbe + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include "protocol.h" + +#define BUF_COUNT (8) +#define BUF_SIZE (16*1024) +#define BUF_TIMEOUT (1000*1000) + +SR_PRIV struct sr_dev_driver saleae_logic_pro_driver_info; + +static const uint32_t drvopts[] = { + SR_CONF_LOGIC_ANALYZER, +}; + +static const uint32_t scanopts[] = { + SR_CONF_CONN, +}; + +static const uint32_t devopts[] = { + SR_CONF_CONTINUOUS, + SR_CONF_CONN | SR_CONF_GET, + SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, +}; + +static const char *channel_names[] = { + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15", +}; + +static const uint64_t samplerates[] = { + SR_MHZ(1), + SR_MHZ(2), + SR_KHZ(2500), + SR_MHZ(10), + SR_MHZ(25), + SR_MHZ(50), +}; + +static gboolean scan_firmware(libusb_device *dev) +{ + struct libusb_device_descriptor des; + struct libusb_device_handle *hdl; + gboolean ret; + unsigned char strdesc[64]; + + hdl = NULL; + ret = FALSE; + + libusb_get_device_descriptor(dev, &des); + + if (libusb_open(dev, &hdl) != 0) + goto out; + + if (libusb_get_string_descriptor_ascii(hdl, + des.iManufacturer, strdesc, sizeof(strdesc)) < 0) + goto out; + if (strcmp((const char *)strdesc, "Saleae")) + goto out; + + if (libusb_get_string_descriptor_ascii(hdl, + des.iProduct, strdesc, sizeof(strdesc)) < 0) + goto out; + if (strcmp((const char *)strdesc, "Logic Pro")) + goto out; + + ret = TRUE; + +out: + if (hdl) + libusb_close(hdl); + + return ret; +} + +static GSList *scan(struct sr_dev_driver *di, GSList *options) +{ + struct drv_context *drvc; + struct dev_context *devc; + struct sr_dev_inst *sdi; + GSList *devices, *conn_devices; + libusb_device **devlist; + struct libusb_device_descriptor des; + const char *conn; + char connection_id[64]; + + devices = NULL; + drvc = di->context; + drvc->instances = NULL; + + conn = NULL; + for (GSList *l = options; l; l = l->next) { + struct sr_config *src = l->data; + + switch (src->key) { + case SR_CONF_CONN: + conn = g_variant_get_string(src->data, NULL); + break; + } + } + + if (conn) + conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn); + else + conn_devices = NULL; + + libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); + for (unsigned int i = 0; devlist[i]; i++) { + if (conn) { + struct sr_usb_dev_inst *usb = NULL; + GSList *l; + + for (l = conn_devices; l; l = l->next) { + usb = l->data; + if (usb->bus == libusb_get_bus_number(devlist[i]) + && usb->address == libusb_get_device_address(devlist[i])) + break; + } + if (!l) + /* This device matched none of the ones that + * matched the conn specification. */ + continue; + } + + libusb_get_device_descriptor(devlist[i], &des); + + usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)); + + if (des.idVendor != 0x21a9 || des.idProduct != 0x1006) + continue; + + if (!scan_firmware(devlist[i])) { + sr_err("Found a Logic Pro device, but firmware is not loaded (use Saleae application)."); + continue; + } + + sdi = g_malloc0(sizeof(struct sr_dev_inst)); + sdi->status = SR_ST_INITIALIZING; + sdi->vendor = g_strdup("Saleae"); + sdi->model = g_strdup("Logic Pro 16"); + sdi->connection_id = g_strdup(connection_id); + + for (unsigned int j = 0; j < ARRAY_SIZE(channel_names); j++) + sr_channel_new(sdi, j, SR_CHANNEL_LOGIC, TRUE, + channel_names[j]); + + sr_dbg("Found a Logic Pro 16 device."); + sdi->status = SR_ST_INACTIVE; + sdi->inst_type = SR_INST_USB; + sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), + libusb_get_device_address(devlist[i]), NULL); + + devc = g_malloc0(sizeof(struct dev_context)); + sdi->priv = devc; + devices = g_slist_append(devices, sdi); + + } + libusb_free_device_list(devlist, 1); + g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); + + return std_scan_complete(di, devices); +} + +static int dev_clear(const struct sr_dev_driver *di) +{ + return std_dev_clear(di, NULL); +} + +static int dev_open(struct sr_dev_inst *sdi) +{ + struct sr_dev_driver *di = sdi->driver; + struct drv_context *drvc = di->context; + struct dev_context *devc = sdi->priv; + struct sr_usb_dev_inst *usb = sdi->conn; + int ret; + + if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK) + return SR_ERR; + + if ((ret = libusb_claim_interface(usb->devhdl, 0))) { + sr_err("Failed to claim interface: %s.", libusb_error_name(ret)); + return SR_ERR; + } + + /* configure default samplerate */ + if (devc->dig_samplerate == 0) + devc->dig_samplerate = samplerates[3]; + + sdi->status = SR_ST_ACTIVE; + + return SR_OK; +} + +static int dev_close(struct sr_dev_inst *sdi) +{ + struct sr_usb_dev_inst *usb = sdi->conn; + + sr_usb_close(usb); + + sdi->status = SR_ST_INACTIVE; + + return SR_OK; +} + +static int config_get(uint32_t key, GVariant **data, + const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) +{ + struct sr_usb_dev_inst *usb; + struct dev_context *devc; + int ret; + + (void)cg; + + ret = SR_OK; + switch (key) { + case SR_CONF_CONN: + if (!sdi || !sdi->conn) + return SR_ERR_ARG; + usb = sdi->conn; + *data = g_variant_new_printf("%d.%d", usb->bus, usb->address); + break; + case SR_CONF_SAMPLERATE: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + *data = g_variant_new_uint64(devc->dig_samplerate); + break; + default: + return SR_ERR_NA; + } + + return ret; +} + +static int config_set(uint32_t key, GVariant *data, + const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) +{ + struct dev_context *devc; + int ret; + + (void)cg; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR_DEV_CLOSED; + devc = sdi->priv; + + ret = SR_OK; + switch (key) { + case SR_CONF_SAMPLERATE: + devc->dig_samplerate = g_variant_get_uint64(data); + break; + default: + ret = SR_ERR_NA; + } + + return ret; +} + +static int config_list(uint32_t key, GVariant **data, + const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) +{ + GVariant *gvar; + GVariantBuilder gvb; + int ret; + + (void)sdi; + (void)cg; + + ret = SR_OK; + switch (key) { + case SR_CONF_SCAN_OPTIONS: + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, + scanopts, + ARRAY_SIZE(scanopts), + sizeof(uint32_t)); + break; + case SR_CONF_DEVICE_OPTIONS: + if (!sdi) { + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, + drvopts, + ARRAY_SIZE(drvopts), + sizeof(uint32_t)); + } else { + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, + devopts, + ARRAY_SIZE(devopts), + sizeof(uint32_t)); + } + break; + case SR_CONF_SAMPLERATE: + g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); + gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), + samplerates, ARRAY_SIZE(samplerates), sizeof(uint64_t)); + g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); + *data = g_variant_builder_end(&gvb); + break; + default: + return SR_ERR_NA; + } + + return ret; +} + +static void dev_acquisition_abort(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc = sdi->priv; + unsigned int i; + + for (i = 0; i < devc->num_transfers; i++) { + if (devc->transfers[i]) + libusb_cancel_transfer(devc->transfers[i]); + } +} + +static int dev_acquisition_handle(int fd, int revents, void *cb_data) +{ + struct sr_dev_inst *sdi = cb_data; + struct drv_context *drvc = sdi->driver->context; + struct timeval tv = {}; + + (void)fd; + (void)revents; + + libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv); + + return TRUE; +} + +static int dev_acquisition_start(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc = sdi->priv; + struct drv_context *drvc = sdi->driver->context; + struct libusb_transfer *transfer; + struct sr_usb_dev_inst *usb; + uint8_t *buf; + unsigned int i, ret; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR_DEV_CLOSED; + + ret = saleae_logic_pro_init(sdi); + if (ret != SR_OK) + return ret; + + ret = saleae_logic_pro_prepare(sdi); + if (ret != SR_OK) + return ret; + + usb = sdi->conn; + + devc->conv_buffer = g_malloc(CONV_BUFFER_SIZE); + + devc->num_transfers = BUF_COUNT; + devc->transfers = g_malloc0(sizeof(*devc->transfers) * BUF_COUNT); + for (i = 0; i < devc->num_transfers; i++) { + buf = g_malloc(BUF_SIZE); + transfer = libusb_alloc_transfer(0); + libusb_fill_bulk_transfer(transfer, usb->devhdl, + 2 | LIBUSB_ENDPOINT_IN, buf, BUF_SIZE, + saleae_logic_pro_receive_data, (void *)sdi, BUF_TIMEOUT); + if ((ret = libusb_submit_transfer(transfer)) != 0) { + sr_err("Failed to submit transfer: %s.", + libusb_error_name(ret)); + libusb_free_transfer(transfer); + g_free(buf); + dev_acquisition_abort(sdi); + return SR_ERR; + } + devc->transfers[i] = transfer; + devc->submitted_transfers++; + } + + usb_source_add(sdi->session, drvc->sr_ctx, BUF_TIMEOUT, dev_acquisition_handle, (void *)sdi); + + std_session_send_df_header(sdi); + + saleae_logic_pro_start(sdi); + if (ret != SR_OK) + return ret; + + return SR_OK; +} + +static int dev_acquisition_stop(struct sr_dev_inst *sdi) +{ + struct dev_context *devc = sdi->priv; + struct drv_context *drvc = sdi->driver->context; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR_DEV_CLOSED; + + saleae_logic_pro_stop(sdi); + + std_session_send_df_end(sdi); + + usb_source_remove(sdi->session, drvc->sr_ctx); + + g_free(devc->conv_buffer); + + return SR_OK; +} + +SR_PRIV struct sr_dev_driver saleae_logic_pro_driver_info = { + .name = "saleae-logic-pro", + .longname = "Saleae Logic Pro", + .api_version = 1, + .init = std_init, + .cleanup = std_cleanup, + .scan = scan, + .dev_list = std_dev_list, + .dev_clear = dev_clear, + .config_get = config_get, + .config_set = config_set, + .config_list = config_list, + .dev_open = dev_open, + .dev_close = dev_close, + .dev_acquisition_start = dev_acquisition_start, + .dev_acquisition_stop = dev_acquisition_stop, + .context = NULL, +}; + +SR_REGISTER_DEV_DRIVER(saleae_logic_pro_driver_info); diff --git a/src/hardware/saleae-logic-pro/protocol.c b/src/hardware/saleae-logic-pro/protocol.c new file mode 100644 index 00000000..ed065461 --- /dev/null +++ b/src/hardware/saleae-logic-pro/protocol.c @@ -0,0 +1,627 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2017 Jan Luebbe + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "protocol.h" + +#define COMMAND_START_CAPTURE 0x01 +#define COMMAND_STOP_CAPTURE 0x02 +#define COMMAND_READ_EEPROM 0x07 +#define COMMAND_WRITE_REG 0x80 +#define COMMAND_READ_REG 0x81 +#define COMMAND_WRITE_I2C 0x87 +#define COMMAND_READ_I2C 0x88 +#define COMMAND_WAKE_I2C 0x89 +#define COMMAND_READ_FW_VER 0x8b + +#define REG_LED_RED 0x0f +#define REG_LED_GREEN 0x10 +#define REG_LED_BLUE 0x11 + +static void iterate_lfsr(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc = sdi->priv; + uint32_t lfsr = devc->lfsr; + int i, max; + + max = (lfsr & 0x1f) + 34; + for (i = 0; i <= max; i++) { + lfsr = (lfsr >> 1) | \ + ((lfsr ^ \ + (lfsr >> 1) ^ \ + (lfsr >> 21) ^ \ + (lfsr >> 31) \ + ) << 31); + } + sr_dbg("Iterate 0x%08x -> 0x%08x", devc->lfsr, lfsr); + devc->lfsr = lfsr; +} + +static void encrypt(const struct sr_dev_inst *sdi, const uint8_t *in, uint8_t *out, uint8_t len) +{ + struct dev_context *devc = sdi->priv; + uint32_t lfsr = devc->lfsr; + uint8_t value, mask; + int i; + + for (i = 0; i < len; i++) { + value = in[i]; + mask = lfsr >> (i%4*8); + if (i == 0) + value = (value & 0x28) | ((value ^ mask) & ~0x28); + else + value = value ^ mask; + out[i] = value; + } + iterate_lfsr(sdi); +} + +static void decrypt(const struct sr_dev_inst *sdi, uint8_t *data, uint8_t len) +{ + struct dev_context *devc = sdi->priv; + uint32_t lfsr = devc->lfsr; + int i; + + for (i = 0; i < len; i++) { + data[i] ^= (lfsr >> (i%4*8)); + } + iterate_lfsr(sdi); +} + +static int transact(const struct sr_dev_inst *sdi, + const uint8_t *req, uint8_t req_len, + uint8_t *rsp, uint8_t rsp_len) +{ + struct sr_usb_dev_inst *usb = sdi->conn; + uint8_t *req_enc; + uint8_t rsp_dummy[1] = {}; + int ret, xfer; + + if (req_len < 2 || req_len > 64 || rsp_len > 128 || + !req || (rsp_len > 0 && !rsp)) + return SR_ERR_ARG; + + req_enc = g_malloc(req_len); + encrypt(sdi, req, req_enc, req_len); + + ret = libusb_bulk_transfer(usb->devhdl, 1, req_enc, req_len, &xfer, 1000); + if (ret != 0) { + sr_dbg("Failed to send request 0x%02x: %s.", + req[1], libusb_error_name(ret)); + return SR_ERR; + } + if (xfer != req_len) { + sr_dbg("Failed to send request 0x%02x: incorrect length " + "%d != %d.", req[1], xfer, req_len); + return SR_ERR; + } + + if (req[0] == 0x20) { // reseed + return SR_OK; + } else if (rsp_len == 0) { + rsp = rsp_dummy; + rsp_len = sizeof(rsp_dummy); + } + + ret = libusb_bulk_transfer(usb->devhdl, 0x80 | 1, rsp, rsp_len, + &xfer, 1000); + if (ret != 0) { + sr_dbg("Failed to receive response to request 0x%02x: %s.", + req[1], libusb_error_name(ret)); + return SR_ERR; + } + if (xfer != rsp_len) { + sr_dbg("Failed to receive response to request 0x%02x: " + "incorrect length %d != %d.", req[1], xfer, rsp_len); + return SR_ERR; + } + + decrypt(sdi, rsp, rsp_len); + + return SR_OK; +} + +static int reseed(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc = sdi->priv; + uint8_t req[] = {0x20, 0x24, 0x4b, 0x35, 0x8e}; + + devc->lfsr = 0; + return transact(sdi, req, sizeof(req), NULL, 0); +} + +static int write_regs(const struct sr_dev_inst *sdi, uint8_t (*regs)[2], uint8_t cnt) +{ + uint8_t req[64]; + int i; + + if (cnt < 1 || cnt > 30) + return SR_ERR_ARG; + + req[0] = 0x00; + req[1] = COMMAND_WRITE_REG; + req[2] = cnt; + + for (i = 0; i < cnt; i++) { + req[3 + 2 * i] = regs[i][0]; + req[4 + 2 * i] = regs[i][1]; + } + + return transact(sdi, req, 3 + 2*cnt, NULL, 0); +} + +static int write_reg(const struct sr_dev_inst *sdi, + uint8_t address, uint8_t value) +{ + uint8_t regs[2] = {address, value}; + + return write_regs(sdi, ®s, 1); +} + +static int get_firmware_version(const struct sr_dev_inst *sdi) +{ + uint8_t req[2] = {0x00, COMMAND_READ_FW_VER}; + uint8_t rsp[128] = {}; + int ret; + + ret = transact(sdi, req, sizeof(req), rsp, sizeof(rsp)); + if (ret == SR_OK) { + rsp[63] = 0; + sr_dbg("fw-version: %s", rsp); + } + + return ret; +} + +static int read_i2c(const struct sr_dev_inst *sdi, uint8_t *data, uint8_t len) +{ + uint8_t req[5]; + uint8_t rsp[1+128]; + int ret; + + if (len < 1 || len > 128 || !data) + return SR_ERR_ARG; + + req[0] = 0x00; + req[1] = COMMAND_READ_I2C; + req[2] = 0xc0; // fixed address + req[3] = len; + req[4] = 0; // len msb? + + ret = transact(sdi, req, sizeof(req), rsp, 1 + len); + if (ret != SR_OK) { + return ret; + } + if (rsp[0] != 0x02) { + sr_dbg("Failed to do I2C read (0x%02x).", rsp[0]); + return SR_ERR; + } + + memcpy(data, rsp+1, len); + return SR_OK; +} + +static int write_i2c(const struct sr_dev_inst *sdi, const uint8_t *data, uint8_t len) +{ + uint8_t req[5 + 128]; + uint8_t rsp[1]; + int ret; + + if (len < 1 || len > 128 || !data) + return SR_ERR_ARG; + + req[0] = 0x00; + req[1] = COMMAND_WRITE_I2C; + req[2] = 0xc0; // fixed address + req[3] = len; + req[4] = 0; // len msb? + memcpy(req + 5, data, len); + + ret = transact(sdi, req, 5 + len, rsp, sizeof(rsp)); + if (ret != SR_OK) { + return ret; + } + if (rsp[0] != 0x02) { + sr_dbg("Failed to do I2C write (0x%02x).", rsp[0]); + return SR_ERR; + } + + return SR_OK; +} + +static int wake_i2c(const struct sr_dev_inst *sdi) +{ + uint8_t req[] = {0x00, COMMAND_WAKE_I2C}; + uint8_t rsp[1] = {}; + uint8_t i2c_rsp[1+1+2] = {}; + int ret; + + ret = transact(sdi, req, sizeof(req), rsp, sizeof(rsp)); + if (ret != SR_OK) { + return ret; + } + if (rsp[0] != 0x00) { + sr_dbg("Failed to do I2C wake trigger (0x%02x).", rsp[0]); + return SR_ERR; + } + + ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); + if (ret != SR_OK) { + return ret; + } + if (i2c_rsp[1] != 0x11) { + sr_dbg("Failed to do I2C wake read (0x%02x).", i2c_rsp[0]); + return SR_ERR; + } + + return SR_OK; +} + +static int crypto_random(const struct sr_dev_inst *sdi, uint8_t *data) +{ + uint8_t i2c_req[8] = {0x03, 0x07, 0x1b, 0x00, 0x00, 0x00, 0x24, 0xcd}; + uint8_t i2c_rsp[1+32+2] = {}; + int ret; + + ret = write_i2c(sdi, i2c_req, sizeof(i2c_req)); + if (ret != SR_OK) { + return ret; + } + + g_usleep(100000); // TODO: poll instead + + ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); + if (ret != SR_OK) { + return ret; + } + + if (data) { + memcpy(data, i2c_rsp+1, 32); + } + + return SR_OK; +} + +static int crypto_nonce(const struct sr_dev_inst *sdi, uint8_t *data) +{ + uint8_t i2c_req[6+20+2] = {0x03, 0x1b, 0x16, 0x00, 0x00, 0x00}; + uint8_t i2c_rsp[1+32+2] = {}; + int ret; + + // CRC + i2c_req[26] = 0x7d; + i2c_req[27] = 0xe0; + + ret = write_i2c(sdi, i2c_req, sizeof(i2c_req)); + if (ret != SR_OK) { + return ret; + } + + g_usleep(100000); // TODO: poll instead + + ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); + if (ret != SR_OK) { + return ret; + } + + if (data) { + memcpy(data, i2c_rsp+1, 32); + } + + return SR_OK; +} + +static int crypto_sign(const struct sr_dev_inst *sdi, uint8_t *data, uint8_t *crc) +{ + uint8_t i2c_req[8] = {0x03, 0x07, 0x41, 0x80, 0x00, 0x00, 0x28, 0x05}; + uint8_t i2c_rsp[1+64+2] = {}; + int ret; + + ret = write_i2c(sdi, i2c_req, sizeof(i2c_req)); + if (ret != SR_OK) { + return ret; + } + + g_usleep(100000); // TODO: poll instead + + ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); + if (ret != SR_OK) { + return ret; + } + + memcpy(data, i2c_rsp+1, 64); + memcpy(crc, i2c_rsp+1+64, 2); + + return SR_OK; +} + +static int authenticate(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc = sdi->priv; + uint8_t random[32] = {}; + uint8_t nonce[32] = {}; + uint8_t sig[64] = {}; + uint8_t sig_crc[64] = {}; + uint32_t lfsr; + int i, ret; + + ret = wake_i2c(sdi); + if (ret != SR_OK) + return ret; + + ret = crypto_random(sdi, random); + if (ret != SR_OK) + return ret; + sr_dbg("random: 0x%02x 0x%02x 0x%02x 0x%02x", random[0], random[1], random[2], random[3]); + + ret = crypto_nonce(sdi, nonce); + if (ret != SR_OK) + return ret; + sr_dbg("nonce: 0x%02x 0x%02x 0x%02x 0x%02x", nonce[0], nonce[1], nonce[2], nonce[3]); + + ret = crypto_nonce(sdi, nonce); + if (ret != SR_OK) + return ret; + sr_dbg("nonce: 0x%02x 0x%02x 0x%02x 0x%02x", nonce[0], nonce[1], nonce[2], nonce[3]); + + ret = crypto_sign(sdi, sig, sig_crc); + if (ret != SR_OK) + return ret; + sr_dbg("sig: 0x%02x 0x%02x 0x%02x 0x%02x", sig[0], sig[1], sig[2], sig[3]); + sr_dbg("sig crc: 0x%02x 0x%02x", sig_crc[0], sig_crc[1]); + + lfsr = 0; + for (i = 0; i < 28; i++) + lfsr ^= nonce[i] << (8*(i%4)); + lfsr ^= sig_crc[0] | sig_crc[1] << 8; + + sr_dbg("Authenticate 0x%08x -> 0x%08x", devc->lfsr, lfsr); + devc->lfsr = lfsr; + + return SR_OK; +} + +static int set_led(const struct sr_dev_inst *sdi, uint8_t r, uint8_t g, uint8_t b) +{ + uint8_t regs[][2] = { + {REG_LED_RED, r}, + {REG_LED_GREEN, g}, + {REG_LED_BLUE, b}, + }; + + authenticate(sdi); + + return write_regs(sdi, regs, G_N_ELEMENTS(regs)); +} + +static int configure_channels(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc = sdi->priv; + const struct sr_channel *c; + const GSList *l; + uint16_t mask; + + devc->dig_channel_cnt = 0; + devc->dig_channel_mask = 0; + for (l = sdi->channels; l; l = l->next) { + c = l->data; + if (!c->enabled) + continue; + + mask = 1 << c->index; + devc->dig_channel_masks[devc->dig_channel_cnt++] = mask; + devc->dig_channel_mask |= mask; + + } + sr_dbg("%d channels enabled (0x%04x)", + devc->dig_channel_cnt, + devc->dig_channel_mask); + + return SR_OK; +} + +SR_PRIV int saleae_logic_pro_init(const struct sr_dev_inst *sdi) +{ + reseed(sdi); + get_firmware_version(sdi); + /* setting the LED doesn't work yet */ + /* set_led(sdi, 0x00, 0x00, 0xff); */ + + return SR_OK; +} + +SR_PRIV int saleae_logic_pro_prepare(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc = sdi->priv; + uint8_t regs_unknown[][2] = { + {0x03, 0x0f}, + {0x04, 0x00}, + {0x05, 0x00}, + }; + uint8_t regs_config[][2] = { + {0x00, 0x00}, + {0x08, 0x00}, /* analog channel mask (LSB) */ + {0x09, 0x00}, /* analog channel mask (MSB) */ + {0x06, 0x01}, /* digital channel mask (LSB) */ + {0x07, 0x00}, /* digital channel mask (MSB) */ + {0x0a, 0x00}, /* analog sample rate? */ + {0x0b, 0x64}, /* digital sample rate? */ + {0x0c, 0x00}, + {0x0d, 0x00}, /* analog mux rate? */ + {0x0e, 0x01}, /* digital mux rate? */ + {0x12, 0x04}, + {0x13, 0x00}, + {0x14, 0xff}, /* pre-divider? */ + }; + uint8_t start_req[] = {0x00, 0x01}; + uint8_t start_rsp[2] = {}; + + configure_channels(sdi); + + /* digital channel mask and muxing */ + regs_config[3][1] = devc->dig_channel_mask; + regs_config[4][1] = devc->dig_channel_mask >> 8; + regs_config[9][1] = devc->dig_channel_cnt; + + /* samplerate */ + switch (devc->dig_samplerate) { + case SR_MHZ(1): + regs_config[6][1] = 0x64; + break; + case SR_MHZ(2): + regs_config[6][1] = 0x32; + break; + case SR_KHZ(2500): + regs_config[6][1] = 0x28; + break; + case SR_MHZ(10): + regs_config[6][1] = 0x0a; + break; + case SR_MHZ(25): + regs_config[6][1] = 0x04; + regs_config[12][1] = 0x80; + break; + case SR_MHZ(50): + regs_config[6][1] = 0x02; + regs_config[12][1] = 0x40; + break; + default: + return SR_ERR_ARG; + } + + authenticate(sdi); + + write_reg(sdi, 0x15, 0x03); + write_regs(sdi, regs_unknown, G_N_ELEMENTS(regs_unknown)); + write_regs(sdi, regs_config, G_N_ELEMENTS(regs_config)); + + transact(sdi, start_req, sizeof(start_req), start_rsp, sizeof(start_rsp)); + + return SR_OK; +} + +SR_PRIV int saleae_logic_pro_start(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc = sdi->priv; + + devc->conv_size = 0; + devc->batch_index = 0; + + write_reg(sdi, 0x00, 0x01); + + return SR_OK; +} + +SR_PRIV int saleae_logic_pro_stop(const struct sr_dev_inst *sdi) +{ + uint8_t stop_req[] = {0x00, 0x02}; + uint8_t stop_rsp[2] = {}; + + write_reg(sdi, 0x00, 0x00); + transact(sdi, stop_req, sizeof(stop_req), stop_rsp, sizeof(stop_rsp)); + + return SR_OK; +} + +static void saleae_logic_pro_send_data(const struct sr_dev_inst *sdi, + void *data, size_t length, size_t unitsize) +{ + const struct sr_datafeed_logic logic = { + .length = length, + .unitsize = unitsize, + .data = data + }; + + const struct sr_datafeed_packet packet = { + .type = SR_DF_LOGIC, + .payload = &logic + }; + + sr_session_send(sdi, &packet); +} + +/* + * One batch from the device consists of 32 samples per active digital channel. + * This stream of batches is packed into USB packets with 16384 bytes each. + */ +static void saleae_logic_pro_convert_data(const struct sr_dev_inst *sdi, + const uint32_t *src, size_t srccnt) +{ + struct dev_context *devc = sdi->priv; + uint8_t *dst = devc->conv_buffer; + uint32_t samples; + uint16_t channel_mask; + unsigned int sample_index, batch_index; + uint16_t *dst_batch; + + /* copy partial batch to the beginning */ + memcpy(dst, dst+devc->conv_size, CONV_BATCH_SIZE); + /* reset converted size */ + devc->conv_size = 0; + + batch_index = devc->batch_index; + while (srccnt--) { + samples = *src++; + dst_batch = (uint16_t*)dst; + + /* first index of the batch */ + if (batch_index == 0) + memset(dst, 0, CONV_BATCH_SIZE); + + /* convert one channel */ + channel_mask = devc->dig_channel_masks[batch_index]; + for (sample_index = 0; sample_index <= 31; sample_index++) + if ((samples >> (31-sample_index)) & 1) + dst_batch[sample_index] |= channel_mask; + + /* last index of the batch */ + if (++batch_index == devc->dig_channel_cnt) { + devc->conv_size += CONV_BATCH_SIZE; + batch_index = 0; + dst += CONV_BATCH_SIZE; + } + } + devc->batch_index = batch_index; +} + +SR_PRIV void LIBUSB_CALL saleae_logic_pro_receive_data(struct libusb_transfer *transfer) +{ + const struct sr_dev_inst *sdi = transfer->user_data; + struct dev_context *devc = sdi->priv; + int ret; + + switch (transfer->status) { + case LIBUSB_TRANSFER_NO_DEVICE: + sr_dbg("FIXME no device"); + return; + case LIBUSB_TRANSFER_COMPLETED: + case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */ + break; + default: + // FIXME + return; + } + + saleae_logic_pro_convert_data(sdi, (uint32_t*)transfer->buffer, 16*1024/4); + saleae_logic_pro_send_data(sdi, devc->conv_buffer, devc->conv_size, 2); + + if ((ret = libusb_submit_transfer(transfer)) != LIBUSB_SUCCESS) + sr_dbg("FIXME resubmit failed"); +} diff --git a/src/hardware/saleae-logic-pro/protocol.h b/src/hardware/saleae-logic-pro/protocol.h new file mode 100644 index 00000000..7fb099ca --- /dev/null +++ b/src/hardware/saleae-logic-pro/protocol.h @@ -0,0 +1,66 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2017 Jan Luebbe + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LIBSIGROK_HARDWARE_SALEAE_LOGIC_PRO_PROTOCOL_H +#define LIBSIGROK_HARDWARE_SALEAE_LOGIC_PRO_PROTOCOL_H + +#include +#include +#include +#include "libsigrok-internal.h" + +#define LOG_PREFIX "saleae-logic-pro" + +/* 16 channels * 32 samples */ +#define CONV_BATCH_SIZE (2*32) +/* one packet + one partial conversion: + * worst case is only one active channel converted to 2 bytes per sample, with + * 8*16384 samples per packet + */ +#define CONV_BUFFER_SIZE (2*8*16384 + CONV_BATCH_SIZE) + +/** Private, per-device-instance driver context. */ +struct dev_context { + /* Acquisition settings */ + unsigned int dig_channel_cnt; + uint16_t dig_channel_mask; + uint16_t dig_channel_masks[16]; + uint64_t dig_samplerate; + + /* Operational state */ + uint32_t lfsr; + + /* Temporary state across callbacks */ + unsigned int num_transfers; + unsigned int submitted_transfers; + struct libusb_transfer **transfers; + + /* Conversion buffer */ + uint8_t *conv_buffer; + unsigned int conv_size; + unsigned int batch_index; +}; + +SR_PRIV int saleae_logic_pro_init(const struct sr_dev_inst *sdi); +SR_PRIV int saleae_logic_pro_prepare(const struct sr_dev_inst *sdi); +SR_PRIV int saleae_logic_pro_start(const struct sr_dev_inst *sdi); +SR_PRIV int saleae_logic_pro_stop(const struct sr_dev_inst *sdi); +SR_PRIV void LIBUSB_CALL saleae_logic_pro_receive_data(struct libusb_transfer *transfer); + +#endif diff --git a/src/hardware/saleae-logicpro/api.c b/src/hardware/saleae-logicpro/api.c deleted file mode 100644 index 82105c14..00000000 --- a/src/hardware/saleae-logicpro/api.c +++ /dev/null @@ -1,441 +0,0 @@ -/* - * This file is part of the libsigrok project. - * - * Copyright (C) 2017 Jan Luebbe - * - * 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 - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include "protocol.h" - -#define BUF_COUNT (8) -#define BUF_SIZE (16*1024) -#define BUF_TIMEOUT (1000*1000) - -SR_PRIV struct sr_dev_driver saleae_logicpro_driver_info; - -static const uint32_t drvopts[] = { - SR_CONF_LOGIC_ANALYZER, -}; - -static const uint32_t scanopts[] = { - SR_CONF_CONN, -}; - -static const uint32_t devopts[] = { - SR_CONF_CONTINUOUS, - SR_CONF_CONN | SR_CONF_GET, - SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, -}; - -static const char *channel_names[] = { - "0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", "10", "11", "12", "13", "14", "15", -}; - -static const uint64_t samplerates[] = { - SR_MHZ(1), - SR_MHZ(2), - SR_KHZ(2500), - SR_MHZ(10), - SR_MHZ(25), - SR_MHZ(50), -}; - -static gboolean scan_firmware(libusb_device *dev) -{ - struct libusb_device_descriptor des; - struct libusb_device_handle *hdl; - gboolean ret; - unsigned char strdesc[64]; - - hdl = NULL; - ret = FALSE; - - libusb_get_device_descriptor(dev, &des); - - if (libusb_open(dev, &hdl) != 0) - goto out; - - if (libusb_get_string_descriptor_ascii(hdl, - des.iManufacturer, strdesc, sizeof(strdesc)) < 0) - goto out; - if (strcmp((const char *)strdesc, "Saleae")) - goto out; - - if (libusb_get_string_descriptor_ascii(hdl, - des.iProduct, strdesc, sizeof(strdesc)) < 0) - goto out; - if (strcmp((const char *)strdesc, "Logic Pro")) - goto out; - - ret = TRUE; - -out: - if (hdl) - libusb_close(hdl); - - return ret; -} - -static GSList *scan(struct sr_dev_driver *di, GSList *options) -{ - struct drv_context *drvc; - struct dev_context *devc; - struct sr_dev_inst *sdi; - GSList *devices, *conn_devices; - libusb_device **devlist; - struct libusb_device_descriptor des; - const char *conn; - char connection_id[64]; - - devices = NULL; - drvc = di->context; - drvc->instances = NULL; - - conn = NULL; - for (GSList *l = options; l; l = l->next) { - struct sr_config *src = l->data; - - switch (src->key) { - case SR_CONF_CONN: - conn = g_variant_get_string(src->data, NULL); - break; - } - } - - if (conn) - conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn); - else - conn_devices = NULL; - - libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); - for (unsigned int i = 0; devlist[i]; i++) { - if (conn) { - struct sr_usb_dev_inst *usb = NULL; - GSList *l; - - for (l = conn_devices; l; l = l->next) { - usb = l->data; - if (usb->bus == libusb_get_bus_number(devlist[i]) - && usb->address == libusb_get_device_address(devlist[i])) - break; - } - if (!l) - /* This device matched none of the ones that - * matched the conn specification. */ - continue; - } - - libusb_get_device_descriptor(devlist[i], &des); - - usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)); - - if (des.idVendor != 0x21a9 || des.idProduct != 0x1006) - continue; - - if (!scan_firmware(devlist[i])) { - sr_err("Found a Logic Pro device, but firmware is not loaded (use Saleae application)."); - continue; - } - - sdi = g_malloc0(sizeof(struct sr_dev_inst)); - sdi->status = SR_ST_INITIALIZING; - sdi->vendor = g_strdup("Saleae"); - sdi->model = g_strdup("Logic Pro 16"); - sdi->connection_id = g_strdup(connection_id); - - for (unsigned int j = 0; j < ARRAY_SIZE(channel_names); j++) - sr_channel_new(sdi, j, SR_CHANNEL_LOGIC, TRUE, - channel_names[j]); - - sr_dbg("Found a Logic Pro 16 device."); - sdi->status = SR_ST_INACTIVE; - sdi->inst_type = SR_INST_USB; - sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), - libusb_get_device_address(devlist[i]), NULL); - - devc = g_malloc0(sizeof(struct dev_context)); - sdi->priv = devc; - devices = g_slist_append(devices, sdi); - - } - libusb_free_device_list(devlist, 1); - g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); - - return std_scan_complete(di, devices); -} - -static int dev_clear(const struct sr_dev_driver *di) -{ - return std_dev_clear(di, NULL); -} - -static int dev_open(struct sr_dev_inst *sdi) -{ - struct sr_dev_driver *di = sdi->driver; - struct drv_context *drvc = di->context; - struct dev_context *devc = sdi->priv; - struct sr_usb_dev_inst *usb = sdi->conn; - int ret; - - if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK) - return SR_ERR; - - if ((ret = libusb_claim_interface(usb->devhdl, 0))) { - sr_err("Failed to claim interface: %s.", libusb_error_name(ret)); - return SR_ERR; - } - - /* configure default samplerate */ - if (devc->dig_samplerate == 0) - devc->dig_samplerate = samplerates[3]; - - sdi->status = SR_ST_ACTIVE; - - return SR_OK; -} - -static int dev_close(struct sr_dev_inst *sdi) -{ - struct sr_usb_dev_inst *usb = sdi->conn; - - sr_usb_close(usb); - - sdi->status = SR_ST_INACTIVE; - - return SR_OK; -} - -static int config_get(uint32_t key, GVariant **data, - const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) -{ - struct sr_usb_dev_inst *usb; - struct dev_context *devc; - int ret; - - (void)cg; - - ret = SR_OK; - switch (key) { - case SR_CONF_CONN: - if (!sdi || !sdi->conn) - return SR_ERR_ARG; - usb = sdi->conn; - *data = g_variant_new_printf("%d.%d", usb->bus, usb->address); - break; - case SR_CONF_SAMPLERATE: - if (!sdi) - return SR_ERR; - devc = sdi->priv; - *data = g_variant_new_uint64(devc->dig_samplerate); - break; - default: - return SR_ERR_NA; - } - - return ret; -} - -static int config_set(uint32_t key, GVariant *data, - const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) -{ - struct dev_context *devc; - int ret; - - (void)cg; - - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; - devc = sdi->priv; - - ret = SR_OK; - switch (key) { - case SR_CONF_SAMPLERATE: - devc->dig_samplerate = g_variant_get_uint64(data); - break; - default: - ret = SR_ERR_NA; - } - - return ret; -} - -static int config_list(uint32_t key, GVariant **data, - const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) -{ - GVariant *gvar; - GVariantBuilder gvb; - int ret; - - (void)sdi; - (void)cg; - - ret = SR_OK; - switch (key) { - case SR_CONF_SCAN_OPTIONS: - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - scanopts, - ARRAY_SIZE(scanopts), - sizeof(uint32_t)); - break; - case SR_CONF_DEVICE_OPTIONS: - if (!sdi) { - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - drvopts, - ARRAY_SIZE(drvopts), - sizeof(uint32_t)); - } else { - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - devopts, - ARRAY_SIZE(devopts), - sizeof(uint32_t)); - } - break; - case SR_CONF_SAMPLERATE: - g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); - gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), - samplerates, ARRAY_SIZE(samplerates), sizeof(uint64_t)); - g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); - *data = g_variant_builder_end(&gvb); - break; - default: - return SR_ERR_NA; - } - - return ret; -} - -static void dev_acquisition_abort(const struct sr_dev_inst *sdi) -{ - struct dev_context *devc = sdi->priv; - unsigned int i; - - for (i = 0; i < devc->num_transfers; i++) { - if (devc->transfers[i]) - libusb_cancel_transfer(devc->transfers[i]); - } -} - -static int dev_acquisition_handle(int fd, int revents, void *cb_data) -{ - struct sr_dev_inst *sdi = cb_data; - struct drv_context *drvc = sdi->driver->context; - struct timeval tv = {}; - - (void)fd; - (void)revents; - - libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv); - - return TRUE; -} - -static int dev_acquisition_start(const struct sr_dev_inst *sdi) -{ - struct dev_context *devc = sdi->priv; - struct drv_context *drvc = sdi->driver->context; - struct libusb_transfer *transfer; - struct sr_usb_dev_inst *usb; - uint8_t *buf; - unsigned int i, ret; - - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; - - ret = saleae_logicpro_init(sdi); - if (ret != SR_OK) - return ret; - - ret = saleae_logicpro_prepare(sdi); - if (ret != SR_OK) - return ret; - - usb = sdi->conn; - - devc->conv_buffer = g_malloc(CONV_BUFFER_SIZE); - - devc->num_transfers = BUF_COUNT; - devc->transfers = g_malloc0(sizeof(*devc->transfers) * BUF_COUNT); - for (i = 0; i < devc->num_transfers; i++) { - buf = g_malloc(BUF_SIZE); - transfer = libusb_alloc_transfer(0); - libusb_fill_bulk_transfer(transfer, usb->devhdl, - 2 | LIBUSB_ENDPOINT_IN, buf, BUF_SIZE, - saleae_logicpro_receive_data, (void *)sdi, BUF_TIMEOUT); - if ((ret = libusb_submit_transfer(transfer)) != 0) { - sr_err("Failed to submit transfer: %s.", - libusb_error_name(ret)); - libusb_free_transfer(transfer); - g_free(buf); - dev_acquisition_abort(sdi); - return SR_ERR; - } - devc->transfers[i] = transfer; - devc->submitted_transfers++; - } - - usb_source_add(sdi->session, drvc->sr_ctx, BUF_TIMEOUT, dev_acquisition_handle, (void *)sdi); - - std_session_send_df_header(sdi); - - saleae_logicpro_start(sdi); - if (ret != SR_OK) - return ret; - - return SR_OK; -} - -static int dev_acquisition_stop(struct sr_dev_inst *sdi) -{ - struct dev_context *devc = sdi->priv; - struct drv_context *drvc = sdi->driver->context; - - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; - - saleae_logicpro_stop(sdi); - - std_session_send_df_end(sdi); - - usb_source_remove(sdi->session, drvc->sr_ctx); - - g_free(devc->conv_buffer); - - return SR_OK; -} - -SR_PRIV struct sr_dev_driver saleae_logicpro_driver_info = { - .name = "saleae-logicpro", - .longname = "saleae-logicpro", - .api_version = 1, - .init = std_init, - .cleanup = std_cleanup, - .scan = scan, - .dev_list = std_dev_list, - .dev_clear = dev_clear, - .config_get = config_get, - .config_set = config_set, - .config_list = config_list, - .dev_open = dev_open, - .dev_close = dev_close, - .dev_acquisition_start = dev_acquisition_start, - .dev_acquisition_stop = dev_acquisition_stop, - .context = NULL, -}; - -SR_REGISTER_DEV_DRIVER(saleae_logicpro_driver_info); diff --git a/src/hardware/saleae-logicpro/protocol.c b/src/hardware/saleae-logicpro/protocol.c deleted file mode 100644 index ff8634b9..00000000 --- a/src/hardware/saleae-logicpro/protocol.c +++ /dev/null @@ -1,627 +0,0 @@ -/* - * This file is part of the libsigrok project. - * - * Copyright (C) 2017 Jan Luebbe - * - * 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 - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include "protocol.h" - -#define COMMAND_START_CAPTURE 0x01 -#define COMMAND_STOP_CAPTURE 0x02 -#define COMMAND_READ_EEPROM 0x07 -#define COMMAND_WRITE_REG 0x80 -#define COMMAND_READ_REG 0x81 -#define COMMAND_WRITE_I2C 0x87 -#define COMMAND_READ_I2C 0x88 -#define COMMAND_WAKE_I2C 0x89 -#define COMMAND_READ_FW_VER 0x8b - -#define REG_LED_RED 0x0f -#define REG_LED_GREEN 0x10 -#define REG_LED_BLUE 0x11 - -static void iterate_lfsr(const struct sr_dev_inst *sdi) -{ - struct dev_context *devc = sdi->priv; - uint32_t lfsr = devc->lfsr; - int i, max; - - max = (lfsr & 0x1f) + 34; - for (i = 0; i <= max; i++) { - lfsr = (lfsr >> 1) | \ - ((lfsr ^ \ - (lfsr >> 1) ^ \ - (lfsr >> 21) ^ \ - (lfsr >> 31) \ - ) << 31); - } - sr_dbg("Iterate 0x%08x -> 0x%08x", devc->lfsr, lfsr); - devc->lfsr = lfsr; -} - -static void encrypt(const struct sr_dev_inst *sdi, const uint8_t *in, uint8_t *out, uint8_t len) -{ - struct dev_context *devc = sdi->priv; - uint32_t lfsr = devc->lfsr; - uint8_t value, mask; - int i; - - for (i = 0; i < len; i++) { - value = in[i]; - mask = lfsr >> (i%4*8); - if (i == 0) - value = (value & 0x28) | ((value ^ mask) & ~0x28); - else - value = value ^ mask; - out[i] = value; - } - iterate_lfsr(sdi); -} - -static void decrypt(const struct sr_dev_inst *sdi, uint8_t *data, uint8_t len) -{ - struct dev_context *devc = sdi->priv; - uint32_t lfsr = devc->lfsr; - int i; - - for (i = 0; i < len; i++) { - data[i] ^= (lfsr >> (i%4*8)); - } - iterate_lfsr(sdi); -} - -static int transact(const struct sr_dev_inst *sdi, - const uint8_t *req, uint8_t req_len, - uint8_t *rsp, uint8_t rsp_len) -{ - struct sr_usb_dev_inst *usb = sdi->conn; - uint8_t *req_enc; - uint8_t rsp_dummy[1] = {}; - int ret, xfer; - - if (req_len < 2 || req_len > 64 || rsp_len > 128 || - !req || (rsp_len > 0 && !rsp)) - return SR_ERR_ARG; - - req_enc = g_malloc(req_len); - encrypt(sdi, req, req_enc, req_len); - - ret = libusb_bulk_transfer(usb->devhdl, 1, req_enc, req_len, &xfer, 1000); - if (ret != 0) { - sr_dbg("Failed to send request 0x%02x: %s.", - req[1], libusb_error_name(ret)); - return SR_ERR; - } - if (xfer != req_len) { - sr_dbg("Failed to send request 0x%02x: incorrect length " - "%d != %d.", req[1], xfer, req_len); - return SR_ERR; - } - - if (req[0] == 0x20) { // reseed - return SR_OK; - } else if (rsp_len == 0) { - rsp = rsp_dummy; - rsp_len = sizeof(rsp_dummy); - } - - ret = libusb_bulk_transfer(usb->devhdl, 0x80 | 1, rsp, rsp_len, - &xfer, 1000); - if (ret != 0) { - sr_dbg("Failed to receive response to request 0x%02x: %s.", - req[1], libusb_error_name(ret)); - return SR_ERR; - } - if (xfer != rsp_len) { - sr_dbg("Failed to receive response to request 0x%02x: " - "incorrect length %d != %d.", req[1], xfer, rsp_len); - return SR_ERR; - } - - decrypt(sdi, rsp, rsp_len); - - return SR_OK; -} - -static int reseed(const struct sr_dev_inst *sdi) -{ - struct dev_context *devc = sdi->priv; - uint8_t req[] = {0x20, 0x24, 0x4b, 0x35, 0x8e}; - - devc->lfsr = 0; - return transact(sdi, req, sizeof(req), NULL, 0); -} - -static int write_regs(const struct sr_dev_inst *sdi, uint8_t (*regs)[2], uint8_t cnt) -{ - uint8_t req[64]; - int i; - - if (cnt < 1 || cnt > 30) - return SR_ERR_ARG; - - req[0] = 0x00; - req[1] = COMMAND_WRITE_REG; - req[2] = cnt; - - for (i = 0; i < cnt; i++) { - req[3 + 2 * i] = regs[i][0]; - req[4 + 2 * i] = regs[i][1]; - } - - return transact(sdi, req, 3 + 2*cnt, NULL, 0); -} - -static int write_reg(const struct sr_dev_inst *sdi, - uint8_t address, uint8_t value) -{ - uint8_t regs[2] = {address, value}; - - return write_regs(sdi, ®s, 1); -} - -static int get_firmware_version(const struct sr_dev_inst *sdi) -{ - uint8_t req[2] = {0x00, COMMAND_READ_FW_VER}; - uint8_t rsp[128] = {}; - int ret; - - ret = transact(sdi, req, sizeof(req), rsp, sizeof(rsp)); - if (ret == SR_OK) { - rsp[63] = 0; - sr_dbg("fw-version: %s", rsp); - } - - return ret; -} - -static int read_i2c(const struct sr_dev_inst *sdi, uint8_t *data, uint8_t len) -{ - uint8_t req[5]; - uint8_t rsp[1+128]; - int ret; - - if (len < 1 || len > 128 || !data) - return SR_ERR_ARG; - - req[0] = 0x00; - req[1] = COMMAND_READ_I2C; - req[2] = 0xc0; // fixed address - req[3] = len; - req[4] = 0; // len msb? - - ret = transact(sdi, req, sizeof(req), rsp, 1 + len); - if (ret != SR_OK) { - return ret; - } - if (rsp[0] != 0x02) { - sr_dbg("Failed to do I2C read (0x%02x).", rsp[0]); - return SR_ERR; - } - - memcpy(data, rsp+1, len); - return SR_OK; -} - -static int write_i2c(const struct sr_dev_inst *sdi, const uint8_t *data, uint8_t len) -{ - uint8_t req[5 + 128]; - uint8_t rsp[1]; - int ret; - - if (len < 1 || len > 128 || !data) - return SR_ERR_ARG; - - req[0] = 0x00; - req[1] = COMMAND_WRITE_I2C; - req[2] = 0xc0; // fixed address - req[3] = len; - req[4] = 0; // len msb? - memcpy(req + 5, data, len); - - ret = transact(sdi, req, 5 + len, rsp, sizeof(rsp)); - if (ret != SR_OK) { - return ret; - } - if (rsp[0] != 0x02) { - sr_dbg("Failed to do I2C write (0x%02x).", rsp[0]); - return SR_ERR; - } - - return SR_OK; -} - -static int wake_i2c(const struct sr_dev_inst *sdi) -{ - uint8_t req[] = {0x00, COMMAND_WAKE_I2C}; - uint8_t rsp[1] = {}; - uint8_t i2c_rsp[1+1+2] = {}; - int ret; - - ret = transact(sdi, req, sizeof(req), rsp, sizeof(rsp)); - if (ret != SR_OK) { - return ret; - } - if (rsp[0] != 0x00) { - sr_dbg("Failed to do I2C wake trigger (0x%02x).", rsp[0]); - return SR_ERR; - } - - ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); - if (ret != SR_OK) { - return ret; - } - if (i2c_rsp[1] != 0x11) { - sr_dbg("Failed to do I2C wake read (0x%02x).", i2c_rsp[0]); - return SR_ERR; - } - - return SR_OK; -} - -static int crypto_random(const struct sr_dev_inst *sdi, uint8_t *data) -{ - uint8_t i2c_req[8] = {0x03, 0x07, 0x1b, 0x00, 0x00, 0x00, 0x24, 0xcd}; - uint8_t i2c_rsp[1+32+2] = {}; - int ret; - - ret = write_i2c(sdi, i2c_req, sizeof(i2c_req)); - if (ret != SR_OK) { - return ret; - } - - g_usleep(100000); // TODO: poll instead - - ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); - if (ret != SR_OK) { - return ret; - } - - if (data) { - memcpy(data, i2c_rsp+1, 32); - } - - return SR_OK; -} - -static int crypto_nonce(const struct sr_dev_inst *sdi, uint8_t *data) -{ - uint8_t i2c_req[6+20+2] = {0x03, 0x1b, 0x16, 0x00, 0x00, 0x00}; - uint8_t i2c_rsp[1+32+2] = {}; - int ret; - - // CRC - i2c_req[26] = 0x7d; - i2c_req[27] = 0xe0; - - ret = write_i2c(sdi, i2c_req, sizeof(i2c_req)); - if (ret != SR_OK) { - return ret; - } - - g_usleep(100000); // TODO: poll instead - - ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); - if (ret != SR_OK) { - return ret; - } - - if (data) { - memcpy(data, i2c_rsp+1, 32); - } - - return SR_OK; -} - -static int crypto_sign(const struct sr_dev_inst *sdi, uint8_t *data, uint8_t *crc) -{ - uint8_t i2c_req[8] = {0x03, 0x07, 0x41, 0x80, 0x00, 0x00, 0x28, 0x05}; - uint8_t i2c_rsp[1+64+2] = {}; - int ret; - - ret = write_i2c(sdi, i2c_req, sizeof(i2c_req)); - if (ret != SR_OK) { - return ret; - } - - g_usleep(100000); // TODO: poll instead - - ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); - if (ret != SR_OK) { - return ret; - } - - memcpy(data, i2c_rsp+1, 64); - memcpy(crc, i2c_rsp+1+64, 2); - - return SR_OK; -} - -static int authenticate(const struct sr_dev_inst *sdi) -{ - struct dev_context *devc = sdi->priv; - uint8_t random[32] = {}; - uint8_t nonce[32] = {}; - uint8_t sig[64] = {}; - uint8_t sig_crc[64] = {}; - uint32_t lfsr; - int i, ret; - - ret = wake_i2c(sdi); - if (ret != SR_OK) - return ret; - - ret = crypto_random(sdi, random); - if (ret != SR_OK) - return ret; - sr_dbg("random: 0x%02x 0x%02x 0x%02x 0x%02x", random[0], random[1], random[2], random[3]); - - ret = crypto_nonce(sdi, nonce); - if (ret != SR_OK) - return ret; - sr_dbg("nonce: 0x%02x 0x%02x 0x%02x 0x%02x", nonce[0], nonce[1], nonce[2], nonce[3]); - - ret = crypto_nonce(sdi, nonce); - if (ret != SR_OK) - return ret; - sr_dbg("nonce: 0x%02x 0x%02x 0x%02x 0x%02x", nonce[0], nonce[1], nonce[2], nonce[3]); - - ret = crypto_sign(sdi, sig, sig_crc); - if (ret != SR_OK) - return ret; - sr_dbg("sig: 0x%02x 0x%02x 0x%02x 0x%02x", sig[0], sig[1], sig[2], sig[3]); - sr_dbg("sig crc: 0x%02x 0x%02x", sig_crc[0], sig_crc[1]); - - lfsr = 0; - for (i = 0; i < 28; i++) - lfsr ^= nonce[i] << (8*(i%4)); - lfsr ^= sig_crc[0] | sig_crc[1] << 8; - - sr_dbg("Authenticate 0x%08x -> 0x%08x", devc->lfsr, lfsr); - devc->lfsr = lfsr; - - return SR_OK; -} - -static int set_led(const struct sr_dev_inst *sdi, uint8_t r, uint8_t g, uint8_t b) -{ - uint8_t regs[][2] = { - {REG_LED_RED, r}, - {REG_LED_GREEN, g}, - {REG_LED_BLUE, b}, - }; - - authenticate(sdi); - - return write_regs(sdi, regs, G_N_ELEMENTS(regs)); -} - -static int configure_channels(const struct sr_dev_inst *sdi) -{ - struct dev_context *devc = sdi->priv; - const struct sr_channel *c; - const GSList *l; - uint16_t mask; - - devc->dig_channel_cnt = 0; - devc->dig_channel_mask = 0; - for (l = sdi->channels; l; l = l->next) { - c = l->data; - if (!c->enabled) - continue; - - mask = 1 << c->index; - devc->dig_channel_masks[devc->dig_channel_cnt++] = mask; - devc->dig_channel_mask |= mask; - - } - sr_dbg("%d channels enabled (0x%04x)", - devc->dig_channel_cnt, - devc->dig_channel_mask); - - return SR_OK; -} - -SR_PRIV int saleae_logicpro_init(const struct sr_dev_inst *sdi) -{ - reseed(sdi); - get_firmware_version(sdi); - /* setting the LED doesn't work yet */ - /* set_led(sdi, 0x00, 0x00, 0xff); */ - - return SR_OK; -} - -SR_PRIV int saleae_logicpro_prepare(const struct sr_dev_inst *sdi) -{ - struct dev_context *devc = sdi->priv; - uint8_t regs_unknown[][2] = { - {0x03, 0x0f}, - {0x04, 0x00}, - {0x05, 0x00}, - }; - uint8_t regs_config[][2] = { - {0x00, 0x00}, - {0x08, 0x00}, /* analog channel mask (LSB) */ - {0x09, 0x00}, /* analog channel mask (MSB) */ - {0x06, 0x01}, /* digital channel mask (LSB) */ - {0x07, 0x00}, /* digital channel mask (MSB) */ - {0x0a, 0x00}, /* analog sample rate? */ - {0x0b, 0x64}, /* digital sample rate? */ - {0x0c, 0x00}, - {0x0d, 0x00}, /* analog mux rate? */ - {0x0e, 0x01}, /* digital mux rate? */ - {0x12, 0x04}, - {0x13, 0x00}, - {0x14, 0xff}, /* pre-divider? */ - }; - uint8_t start_req[] = {0x00, 0x01}; - uint8_t start_rsp[2] = {}; - - configure_channels(sdi); - - /* digital channel mask and muxing */ - regs_config[3][1] = devc->dig_channel_mask; - regs_config[4][1] = devc->dig_channel_mask >> 8; - regs_config[9][1] = devc->dig_channel_cnt; - - /* samplerate */ - switch (devc->dig_samplerate) { - case SR_MHZ(1): - regs_config[6][1] = 0x64; - break; - case SR_MHZ(2): - regs_config[6][1] = 0x32; - break; - case SR_KHZ(2500): - regs_config[6][1] = 0x28; - break; - case SR_MHZ(10): - regs_config[6][1] = 0x0a; - break; - case SR_MHZ(25): - regs_config[6][1] = 0x04; - regs_config[12][1] = 0x80; - break; - case SR_MHZ(50): - regs_config[6][1] = 0x02; - regs_config[12][1] = 0x40; - break; - default: - return SR_ERR_ARG; - } - - authenticate(sdi); - - write_reg(sdi, 0x15, 0x03); - write_regs(sdi, regs_unknown, G_N_ELEMENTS(regs_unknown)); - write_regs(sdi, regs_config, G_N_ELEMENTS(regs_config)); - - transact(sdi, start_req, sizeof(start_req), start_rsp, sizeof(start_rsp)); - - return SR_OK; -} - -SR_PRIV int saleae_logicpro_start(const struct sr_dev_inst *sdi) -{ - struct dev_context *devc = sdi->priv; - - devc->conv_size = 0; - devc->batch_index = 0; - - write_reg(sdi, 0x00, 0x01); - - return SR_OK; -} - -SR_PRIV int saleae_logicpro_stop(const struct sr_dev_inst *sdi) -{ - uint8_t stop_req[] = {0x00, 0x02}; - uint8_t stop_rsp[2] = {}; - - write_reg(sdi, 0x00, 0x00); - transact(sdi, stop_req, sizeof(stop_req), stop_rsp, sizeof(stop_rsp)); - - return SR_OK; -} - -static void saleae_logicpro_send_data(const struct sr_dev_inst *sdi, - void *data, size_t length, size_t unitsize) -{ - const struct sr_datafeed_logic logic = { - .length = length, - .unitsize = unitsize, - .data = data - }; - - const struct sr_datafeed_packet packet = { - .type = SR_DF_LOGIC, - .payload = &logic - }; - - sr_session_send(sdi, &packet); -} - -/* - * One batch from the device consists of 32 samples per active digital channel. - * This stream of batches is packed into USB packets with 16384 bytes each. - */ -static void saleae_logicpro_convert_data(const struct sr_dev_inst *sdi, - const uint32_t *src, size_t srccnt) -{ - struct dev_context *devc = sdi->priv; - uint8_t *dst = devc->conv_buffer; - uint32_t samples; - uint16_t channel_mask; - unsigned int sample_index, batch_index; - uint16_t *dst_batch; - - /* copy partial batch to the beginning */ - memcpy(dst, dst+devc->conv_size, CONV_BATCH_SIZE); - /* reset converted size */ - devc->conv_size = 0; - - batch_index = devc->batch_index; - while (srccnt--) { - samples = *src++; - dst_batch = (uint16_t*)dst; - - /* first index of the batch */ - if (batch_index == 0) - memset(dst, 0, CONV_BATCH_SIZE); - - /* convert one channel */ - channel_mask = devc->dig_channel_masks[batch_index]; - for (sample_index = 0; sample_index <= 31; sample_index++) - if ((samples >> (31-sample_index)) & 1) - dst_batch[sample_index] |= channel_mask; - - /* last index of the batch */ - if (++batch_index == devc->dig_channel_cnt) { - devc->conv_size += CONV_BATCH_SIZE; - batch_index = 0; - dst += CONV_BATCH_SIZE; - } - } - devc->batch_index = batch_index; -} - -SR_PRIV void LIBUSB_CALL saleae_logicpro_receive_data(struct libusb_transfer *transfer) -{ - const struct sr_dev_inst *sdi = transfer->user_data; - struct dev_context *devc = sdi->priv; - int ret; - - switch (transfer->status) { - case LIBUSB_TRANSFER_NO_DEVICE: - sr_dbg("FIXME no device"); - return; - case LIBUSB_TRANSFER_COMPLETED: - case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */ - break; - default: - // FIXME - return; - } - - saleae_logicpro_convert_data(sdi, (uint32_t*)transfer->buffer, 16*1024/4); - saleae_logicpro_send_data(sdi, devc->conv_buffer, devc->conv_size, 2); - - if ((ret = libusb_submit_transfer(transfer)) != LIBUSB_SUCCESS) - sr_dbg("FIXME resubmit failed"); -} diff --git a/src/hardware/saleae-logicpro/protocol.h b/src/hardware/saleae-logicpro/protocol.h deleted file mode 100644 index 2ac0af10..00000000 --- a/src/hardware/saleae-logicpro/protocol.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This file is part of the libsigrok project. - * - * Copyright (C) 2017 Jan Luebbe - * - * 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 - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef LIBSIGROK_HARDWARE_SALEAE_LOGICPRO_PROTOCOL_H -#define LIBSIGROK_HARDWARE_SALEAE_LOGICPRO_PROTOCOL_H - -#include -#include -#include -#include "libsigrok-internal.h" - -#define LOG_PREFIX "saleae-logicpro" - -/* 16 channels * 32 samples */ -#define CONV_BATCH_SIZE (2*32) -/* one packet + one partial conversion: - * worst case is only one active channel converted to 2 bytes per sample, with - * 8*16384 samples per packet - */ -#define CONV_BUFFER_SIZE (2*8*16384 + CONV_BATCH_SIZE) - -/** Private, per-device-instance driver context. */ -struct dev_context { - /* Acquisition settings */ - unsigned int dig_channel_cnt; - uint16_t dig_channel_mask; - uint16_t dig_channel_masks[16]; - uint64_t dig_samplerate; - - /* Operational state */ - uint32_t lfsr; - - /* Temporary state across callbacks */ - unsigned int num_transfers; - unsigned int submitted_transfers; - struct libusb_transfer **transfers; - - /* Conversion buffer */ - uint8_t *conv_buffer; - unsigned int conv_size; - unsigned int batch_index; -}; - -SR_PRIV int saleae_logicpro_init(const struct sr_dev_inst *sdi); -SR_PRIV int saleae_logicpro_prepare(const struct sr_dev_inst *sdi); -SR_PRIV int saleae_logicpro_start(const struct sr_dev_inst *sdi); -SR_PRIV int saleae_logicpro_stop(const struct sr_dev_inst *sdi); -SR_PRIV void LIBUSB_CALL saleae_logicpro_receive_data(struct libusb_transfer *transfer); - -#endif