X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=hardware%2Fsaleae-logic16%2Fprotocol.c;h=d83dc48f3dc44719a64a1fcc3581ff221360a757;hb=15abcf0f5888dab4c077af6600fab219342af830;hp=048fd19c2c7baa17bcc68a38d6528d4fa5425f77;hpb=5eea4305ad108b8549257170985688004e65d00b;p=libsigrok.git 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;