From: Marcus Comstedt Date: Fri, 2 Aug 2013 22:35:44 +0000 (+0200) Subject: saleae-logic16: Initialize the FPGA. X-Git-Tag: libsigrok-0.2.2~89 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=15abcf0f5888dab4c077af6600fab219342af830;p=libsigrok.git saleae-logic16: Initialize the FPGA. The map_eeprom_data function is currently unknown. The map entries provided were observed via bus-snooping of the vendor software on my device. Other devices may need additional values. --- diff --git a/hardware/saleae-logic16/api.c b/hardware/saleae-logic16/api.c index 2878b16a..30be9b23 100644 --- a/hardware/saleae-logic16/api.c +++ b/hardware/saleae-logic16/api.c @@ -271,6 +271,11 @@ static int logic16_dev_open(struct sr_dev_inst *sdi) break; } + if ((ret = saleae_logic16_init_device(sdi)) != SR_OK) { + sr_err("Failed to init device."); + break; + } + sdi->status = SR_ST_ACTIVE; sr_info("Opened device %d on %d.%d, " "interface %d.", diff --git a/hardware/saleae-logic16/protocol.c b/hardware/saleae-logic16/protocol.c index 048fd19c..d83dc48f 100644 --- a/hardware/saleae-logic16/protocol.c +++ b/hardware/saleae-logic16/protocol.c @@ -19,6 +19,422 @@ #include "protocol.h" +#include +#include +#include +#include +#include +#include +#include +#include "libsigrok.h" +#include "libsigrok-internal.h" + +#define FPGA_FIRMWARE_18 FIRMWARE_DIR"/saleae-logic16-fpga-18.bitstream" +#define FPGA_FIRMWARE_33 FIRMWARE_DIR"/saleae-logic16-fpga-33.bitstream" + +#define COMMAND_START_ACQUISITION 1 +#define COMMAND_ABORT_ACQUISITION_ASYNC 2 +#define COMMAND_WRITE_EEPROM 6 +#define COMMAND_READ_EEPROM 7 +#define COMMAND_WRITE_LED_TABLE 0x7a +#define COMMAND_SET_LED_MODE 0x7b +#define COMMAND_RETURN_TO_BOOTLOADER 0x7c +#define COMMAND_ABORT_ACQUISITION_SYNC 0x7d +#define COMMAND_FPGA_UPLOAD_INIT 0x7e +#define COMMAND_FPGA_UPLOAD_SEND_DATA 0x7f +#define COMMAND_FPGA_WRITE_REGISTER 0x80 +#define COMMAND_FPGA_READ_REGISTER 0x81 +#define COMMAND_GET_REVID 0x82 + +#define WRITE_EEPROM_COOKIE1 0x42 +#define WRITE_EEPROM_COOKIE2 0x55 +#define READ_EEPROM_COOKIE1 0x33 +#define READ_EEPROM_COOKIE2 0x81 +#define ABORT_ACQUISITION_SYNC_PATTERN 0x55 + + +static void encrypt(uint8_t *dest, const uint8_t *src, uint8_t cnt) +{ + uint8_t state1 = 0x9b, state2 = 0x54; + int i; + + for (i=0; iconn; + + if (cmd_len < 1 || cmd_len > 64 || reply_len > 64 || + command == NULL || (reply_len > 0 && reply == NULL)) + return SR_ERR_ARG; + + encrypt(buf, command, cmd_len); + + ret = libusb_bulk_transfer(usb->devhdl, 1, buf, cmd_len, &xfer, 1000); + if (ret != 0) { + sr_dbg("Failed to send EP1 command 0x%02x: %s", + command[0], libusb_error_name(ret)); + return SR_ERR; + } + if (xfer != cmd_len) { + sr_dbg("Failed to send EP1 command 0x%02x: incorrect length %d != %d", + xfer, cmd_len); + return SR_ERR; + } + + if (reply_len == 0) + return SR_OK; + + ret = libusb_bulk_transfer(usb->devhdl, 0x80 | 1, buf, reply_len, &xfer, 1000); + if (ret != 0) { + sr_dbg("Failed to receive reply to EP1 command 0x%02x: %s", + command[0], libusb_error_name(ret)); + return SR_ERR; + } + if (xfer != reply_len) { + sr_dbg("Failed to receive reply to EP1 command 0x%02x: incorrect length %d != %d", + xfer, reply_len); + return SR_ERR; + } + + decrypt(reply, buf, reply_len); + + return SR_OK; +} + +static int read_eeprom(const struct sr_dev_inst *sdi, + uint8_t address, uint8_t length, uint8_t *buf) +{ + uint8_t command[5] = { + COMMAND_READ_EEPROM, + READ_EEPROM_COOKIE1, + READ_EEPROM_COOKIE2, + address, + length, + }; + + return do_ep1_command(sdi, command, 5, buf, length); +} + +static int upload_led_table(const struct sr_dev_inst *sdi, + const uint8_t *table, uint8_t offset, uint8_t cnt) +{ + uint8_t command[64]; + int ret; + + if (cnt < 1 || cnt+offset > 64 || table == NULL) + return SR_ERR_ARG; + + while (cnt > 0) { + uint8_t chunk = (cnt > 32? 32 : cnt); + + command[0] = COMMAND_WRITE_LED_TABLE; + command[1] = offset; + command[2] = chunk; + memcpy(command+3, table, chunk); + + if ((ret = do_ep1_command(sdi, command, 3+chunk, NULL, 0)) != SR_OK) + return ret; + + table += chunk; + offset += chunk; + cnt -= chunk; + } + + return SR_OK; +} + +static int set_led_mode(const struct sr_dev_inst *sdi, + uint8_t animate, uint16_t t2reload, uint8_t div, + uint8_t repeat) +{ + uint8_t command[6] = { + COMMAND_SET_LED_MODE, + animate, + t2reload&0xff, + t2reload>>8, + div, + repeat, + }; + + return do_ep1_command(sdi, command, 6, NULL, 0); +} + +static int read_fpga_register(const struct sr_dev_inst *sdi, + uint8_t address, uint8_t *value) +{ + uint8_t command[3] = { + COMMAND_FPGA_READ_REGISTER, + 1, + address, + }; + + return do_ep1_command(sdi, command, 3, value, 1); +} + +static int write_fpga_registers(const struct sr_dev_inst *sdi, + uint8_t (*regs)[2], uint8_t cnt) +{ + uint8_t command[64]; + int i; + + if (cnt < 1 || cnt > 31) + return SR_ERR_ARG; + + command[0] = COMMAND_FPGA_WRITE_REGISTER; + command[1] = cnt; + for (i=0; i>= 3; + for (i=0; i<2; i++) + for (j=0; jpriv; + + if (devc->cur_voltage_range == vrange) + return SR_OK; + + switch (vrange) { + case VOLTAGE_RANGE_18_33_V: + filename = FPGA_FIRMWARE_18; + break; + case VOLTAGE_RANGE_5_V: + filename = FPGA_FIRMWARE_33; + break; + default: + sr_err("Unsupported voltage range"); + return SR_ERR; + } + + sr_info("Uploading FPGA bitstream at %s", filename); + if ((fw = g_fopen(filename, "rb")) == NULL) { + sr_err("Unable to open bitstream file %s for reading: %s", + filename, strerror(errno)); + return SR_ERR; + } + + buf[0] = COMMAND_FPGA_UPLOAD_INIT; + if ((ret = do_ep1_command(sdi, buf, 1, NULL, 0)) != SR_OK) { + fclose(fw); + return ret; + } + + while (1) { + chunksize = fread(buf, 1, sizeof(buf), fw); + if (chunksize == 0) + break; + + for (offset = 0; offset < chunksize; offset += 62) { + uint8_t command[64]; + uint8_t len = (offset + 62 > chunksize? + chunksize - offset : 62); + command[0] = COMMAND_FPGA_UPLOAD_SEND_DATA; + command[1] = len; + memcpy(command+2, buf+offset, len); + if ((ret = do_ep1_command(sdi, command, len+2, NULL, 0)) != SR_OK) { + fclose(fw); + return ret; + } + } + + sr_info("Uploaded %d bytes", chunksize); + } + fclose(fw); + sr_info("FPGA bitstream upload done"); + + if ((ret = prime_fpga(sdi)) != SR_OK) + return ret; + + if ((ret = configure_led(sdi)) != SR_OK) + return ret; + + /* XXX */ + if ((ret = configure_led(sdi)) != SR_OK) + return ret; + + devc->cur_voltage_range = vrange; + return SR_OK; +} + +SR_PRIV int saleae_logic16_abort_acquisition(const struct sr_dev_inst *sdi) +{ + static const uint8_t command[2] = { + COMMAND_ABORT_ACQUISITION_SYNC, + ABORT_ACQUISITION_SYNC_PATTERN, + }; + uint8_t reply, expected_reply; + int ret; + + if ((ret = do_ep1_command(sdi, command, 2, &reply, 1)) != SR_OK) + return ret; + + expected_reply = ~command[1]; + if (reply != expected_reply) { + sr_err("Invalid response for abort acquisition command: " + "0x%02x != 0x%02x", reply, expected_reply); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int saleae_logic16_init_device(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + int ret; + + devc = sdi->priv; + + devc->cur_voltage_range = VOLTAGE_RANGE_UNKNOWN; + + if ((ret = saleae_logic16_abort_acquisition(sdi)) != SR_OK) + return ret; + + if ((ret = read_eeprom(sdi, 8, 8, devc->eeprom_data)) != SR_OK) + return ret; + + if ((ret = upload_fpga_bitstream(sdi, VOLTAGE_RANGE_18_33_V)) != SR_OK) + return ret; + + return SR_OK; +} + SR_PRIV int saleae_logic16_receive_data(int fd, int revents, void *cb_data) { (void)fd; diff --git a/hardware/saleae-logic16/protocol.h b/hardware/saleae-logic16/protocol.h index a13f1858..d7ddb9a4 100644 --- a/hardware/saleae-logic16/protocol.h +++ b/hardware/saleae-logic16/protocol.h @@ -34,6 +34,12 @@ #define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args) #define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args) +enum voltage_range { + VOLTAGE_RANGE_UNKNOWN, + VOLTAGE_RANGE_18_33_V, /* 1.8V and 3.3V logic */ + VOLTAGE_RANGE_5_V, /* 5V logic */ +}; + /** Private, per-device-instance driver context. */ struct dev_context { /* @@ -46,8 +52,18 @@ struct dev_context { /** The currently configured samplerate of the device. */ uint64_t cur_samplerate; + + /** The currently configured input voltage of the device */ + enum voltage_range cur_voltage_range; + + /* + * EEPROM data from address 8 + */ + uint8_t eeprom_data[8]; }; +SR_PRIV int saleae_logic16_abort_acquisition(const struct sr_dev_inst *sdi); +SR_PRIV int saleae_logic16_init_device(const struct sr_dev_inst *sdi); SR_PRIV int saleae_logic16_receive_data(int fd, int revents, void *cb_data); #endif