]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/kingst-la2016/protocol.c
kingst-la2016: complete hardware setup in probe, set features in open
[libsigrok.git] / src / hardware / kingst-la2016 / protocol.c
index 7af07906c813622d352ef5163d5b7b236f5ee420..9ecaa7180961d4c18299705a4916c7a8b23ba24a 100644 (file)
 #include "libsigrok-internal.h"
 #include "protocol.h"
 
-#define UC_FIRMWARE    "kingst-la-%04x.fw"
-#define FPGA_FW_LA2016 "kingst-la2016-fpga.bitstream"
-#define FPGA_FW_LA2016A        "kingst-la2016a1-fpga.bitstream"
-#define FPGA_FW_LA1016 "kingst-la1016-fpga.bitstream"
-#define FPGA_FW_LA1016A        "kingst-la1016a1-fpga.bitstream"
+/* USB PID dependent MCU firmware. Model dependent FPGA bitstream. */
+#define MCU_FWFILE_FMT "kingst-la-%04x.fw"
+#define FPGA_FWFILE_FMT        "kingst-%s-fpga.bitstream"
+
+/*
+ * List of supported devices and their features. See @ref kingst_model
+ * for the fields' type and meaning. Table is sorted by EEPROM magic.
+ *
+ * TODO
+ * - Below LA1016 properties were guessed, need verification.
+ * - Add LA5016 and LA5032 devices when their EEPROM magic is known.
+ * - Does LA1010 fit the driver implementation? Samplerates vary with
+ *   channel counts, lack of local sample memory. Most probably not.
+ */
+static const struct kingst_model models[] = {
+       { 2, "LA2016", "la2016", SR_MHZ(200), 16, 1, },
+       { 3, "LA1016", "la1016", SR_MHZ(100), 16, 1, },
+       { 8, "LA2016", "la2016a1", SR_MHZ(200), 16, 1, },
+       { 9, "LA1016", "la1016a1", SR_MHZ(100), 16, 1, },
+};
 
 /* USB vendor class control requests, executed by the Cypress FX2 MCU. */
 #define CMD_FPGA_ENABLE        0x10
@@ -600,7 +615,7 @@ static int set_trigger_config(const struct sr_dev_inst *sdi)
 static int set_sample_config(const struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
-       double clock_divisor;
+       uint64_t min_samplerate, eff_samplerate;
        uint16_t divider_u16;
        uint64_t limit_samples;
        uint64_t pre_trigger_samples;
@@ -611,22 +626,20 @@ static int set_sample_config(const struct sr_dev_inst *sdi)
 
        devc = sdi->priv;
 
-       if (devc->cur_samplerate > devc->max_samplerate) {
+       if (devc->cur_samplerate > devc->model->samplerate) {
                sr_err("Too high a sample rate: %" PRIu64 ".",
                        devc->cur_samplerate);
                return SR_ERR_ARG;
        }
-       if (devc->cur_samplerate < MIN_SAMPLE_RATE_LA2016) {
+       min_samplerate = devc->model->samplerate;
+       min_samplerate /= 65536;
+       if (devc->cur_samplerate < min_samplerate) {
                sr_err("Too low a sample rate: %" PRIu64 ".",
                        devc->cur_samplerate);
                return SR_ERR_ARG;
        }
-
-       clock_divisor = devc->max_samplerate / (double)devc->cur_samplerate;
-       if (clock_divisor > 65535)
-               return SR_ERR_ARG;
-       divider_u16 = (uint16_t)(clock_divisor + 0.5);
-       devc->cur_samplerate = devc->max_samplerate / divider_u16;
+       divider_u16 = devc->model->samplerate / devc->cur_samplerate;
+       eff_samplerate = devc->model->samplerate / divider_u16;
 
        ret = sr_sw_limits_get_remain(&devc->sw_limits,
                &limit_samples, NULL, NULL, NULL);
@@ -635,12 +648,14 @@ static int set_sample_config(const struct sr_dev_inst *sdi)
                return ret;
        }
        if (limit_samples > LA2016_NUM_SAMPLES_MAX) {
-               sr_err("Too high a sample depth: %" PRIu64 ".", limit_samples);
-               return SR_ERR_ARG;
+               sr_warn("Too high a sample depth: %" PRIu64 ", capping.",
+                       limit_samples);
+               limit_samples = LA2016_NUM_SAMPLES_MAX;
        }
-       if (limit_samples < LA2016_NUM_SAMPLES_MIN) {
-               sr_err("Too low a sample depth: %" PRIu64 ".", limit_samples);
-               return SR_ERR_ARG;
+       if (limit_samples == 0) {
+               limit_samples = LA2016_NUM_SAMPLES_MAX;
+               sr_dbg("Passing %" PRIu64 " to HW for unlimited samples.",
+                       limit_samples);
        }
 
        /*
@@ -655,23 +670,36 @@ static int set_sample_config(const struct sr_dev_inst *sdi)
         * limit the amount of sample memory to use for pre-trigger
         * data. Only the upper 24 bits of that memory size spec get
         * communicated to the device (written to its FPGA register).
+        *
+        * TODO Determine whether the pre-trigger memory size gets
+        * specified in samples or in bytes. A previous implementation
+        * suggests bytes but this is suspicious when every other spec
+        * is in terms of samples.
         */
-       pre_trigger_samples = limit_samples * devc->capture_ratio / 100;
-       pre_trigger_memory = LA2016_PRE_MEM_LIMIT_BASE;
-       pre_trigger_memory *= devc->capture_ratio;
-       pre_trigger_memory /= 100;
+       if (devc->trigger_involved) {
+               pre_trigger_samples = limit_samples;
+               pre_trigger_samples *= devc->capture_ratio;
+               pre_trigger_samples /= 100;
+               pre_trigger_memory = devc->model->memory_bits;
+               pre_trigger_memory *= UINT64_C(1024 * 1024 * 1024);
+               pre_trigger_memory /= 8; /* devc->model->channel_count ? */
+               pre_trigger_memory *= devc->capture_ratio;
+               pre_trigger_memory /= 100;
+       } else {
+               sr_dbg("No trigger setup, skipping pre-trigger config.");
+               pre_trigger_samples = 1;
+               pre_trigger_memory = 0;
+       }
+       /* Ensure non-zero value after LSB shift out in HW reg. */
+       if (pre_trigger_memory < 0x100) {
+               pre_trigger_memory = 0x100;
+       }
 
        sr_dbg("Set sample config: %" PRIu64 "kHz, %" PRIu64 " samples.",
-               devc->cur_samplerate / 1000, limit_samples);
+               eff_samplerate / SR_KHZ(1), limit_samples);
        sr_dbg("Capture ratio %" PRIu64 "%%, count %" PRIu64 ", mem %" PRIu64 ".",
                devc->capture_ratio, pre_trigger_samples, pre_trigger_memory);
 
-       if (!devc->trigger_involved) {
-               sr_dbg("Voiding pre-trigger setup. No trigger involved.");
-               pre_trigger_samples = 1;
-               pre_trigger_memory = 0x100;
-       }
-
        /*
         * The acquisition configuration occupies a total of 16 bytes:
         * - A 34bit total samples count limit (up to 10 billions) that
@@ -838,12 +866,31 @@ static int get_capture_info(const struct sr_dev_inst *sdi)
        return SR_OK;
 }
 
-SR_PRIV int la2016_upload_firmware(struct sr_context *sr_ctx,
-       libusb_device *dev, uint16_t product_id)
+SR_PRIV int la2016_upload_firmware(const struct sr_dev_inst *sdi,
+       struct sr_context *sr_ctx, libusb_device *dev, uint16_t product_id)
 {
-       char fw_file[1024];
-       snprintf(fw_file, sizeof(fw_file), UC_FIRMWARE, product_id);
-       return ezusb_upload_firmware(sr_ctx, dev, USB_CONFIGURATION, fw_file);
+       struct dev_context *devc;
+       char *fw_file;
+       int ret;
+
+       devc = sdi ? sdi->priv : NULL;
+
+       fw_file = g_strdup_printf(MCU_FWFILE_FMT, product_id);
+       sr_info("USB PID %04hx, MCU firmware '%s'.", product_id, fw_file);
+
+       ret = ezusb_upload_firmware(sr_ctx, dev, USB_CONFIGURATION, fw_file);
+       if (ret != SR_OK) {
+               g_free(fw_file);
+               return ret;
+       }
+
+       if (devc) {
+               devc->mcu_firmware = fw_file;
+               fw_file = NULL;
+       }
+       g_free(fw_file);
+
+       return SR_OK;
 }
 
 SR_PRIV int la2016_setup_acquisition(const struct sr_dev_inst *sdi)
@@ -1186,16 +1233,18 @@ SR_PRIV int la2016_receive_data(int fd, int revents, void *cb_data)
        return TRUE;
 }
 
-SR_PRIV int la2016_init_device(const struct sr_dev_inst *sdi)
+SR_PRIV int la2016_identify_device(const struct sr_dev_inst *sdi,
+       gboolean show_message)
 {
        struct dev_context *devc;
-       uint16_t state;
        uint8_t buf[8];
+       size_t rdoff, rdlen;
        const uint8_t *rdptr;
        uint8_t date_yy, date_mm;
        uint8_t dinv_yy, dinv_mm;
        uint8_t magic;
-       const char *bitstream_fn;
+       size_t model_idx;
+       const struct kingst_model *model;
        int ret;
 
        devc = sdi->priv;
@@ -1207,10 +1256,23 @@ SR_PRIV int la2016_init_device(const struct sr_dev_inst *sdi)
         * to 2020-04. This information can help identify the vintage of
         * devices when unknown magic numbers are seen.
         */
-       ret = ctrl_in(sdi, CMD_EEPROM, 0x20, 0, buf, 4 * sizeof(uint8_t));
-       if (ret != SR_OK) {
+       rdoff = 0x20;
+       rdlen = 4 * sizeof(uint8_t);
+       ret = ctrl_in(sdi, CMD_EEPROM, rdoff, 0, buf, rdlen);
+       if (ret != SR_OK && !show_message) {
+               /* Non-fatal weak attempt during probe. Not worth logging. */
+               sr_dbg("Cannot access EEPROM.");
+               return SR_ERR_IO;
+       } else if (ret != SR_OK) {
+               /* Failed attempt in regular use. Non-fatal. Worth logging. */
                sr_err("Cannot read manufacture date in EEPROM.");
        } else {
+               if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+                       GString *txt;
+                       txt = sr_hexdump_new(buf, rdlen);
+                       sr_spew("Manufacture date bytes %s.", txt->str);
+                       sr_hexdump_free(txt);
+               }
                rdptr = &buf[0];
                date_yy = read_u8_inc(&rdptr);
                date_mm = read_u8_inc(&rdptr);
@@ -1259,52 +1321,68 @@ SR_PRIV int la2016_init_device(const struct sr_dev_inst *sdi)
         * do not match the hardware model. An LA1016 won't become a
         * LA2016 by faking its EEPROM content.
         */
-       if ((ret = ctrl_in(sdi, CMD_EEPROM, 0x08, 0, &buf, sizeof(buf))) != SR_OK) {
+       devc->identify_magic = 0;
+       rdoff = 0x08;
+       rdlen = 8 * sizeof(uint8_t);
+       ret = ctrl_in(sdi, CMD_EEPROM, rdoff, 0, &buf, rdlen);
+       if (ret != SR_OK) {
                sr_err("Cannot read EEPROM device identifier bytes.");
                return ret;
        }
+       if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+               GString *txt;
+               txt = sr_hexdump_new(buf, rdlen);
+               sr_spew("EEPROM magic bytes %s.", txt->str);
+               sr_hexdump_free(txt);
+       }
        if ((buf[0] ^ buf[1]) == 0xff) {
                /* Primary copy of magic passes complement check. */
-               sr_dbg("Using primary copy of device type magic number.");
                magic = buf[0];
+               sr_dbg("Using primary magic, value %d.", (int)magic);
        } else if ((buf[4] ^ buf[5]) == 0xff) {
                /* Backup copy of magic passes complement check. */
-               sr_dbg("Using backup copy of device type magic number.");
                magic = buf[4];
+               sr_dbg("Using backup magic, value %d.", (int)magic);
        } else {
                sr_err("Cannot find consistent device type identification.");
                magic = 0;
        }
-       sr_dbg("Device type: magic number is %hhu.", magic);
+       devc->identify_magic = magic;
 
-       /* Select the FPGA bitstream depending on the model. */
-       switch (magic) {
-       case 2:
-               bitstream_fn = FPGA_FW_LA2016;
-               devc->max_samplerate = MAX_SAMPLE_RATE_LA2016;
-               break;
-       case 3:
-               bitstream_fn = FPGA_FW_LA1016;
-               devc->max_samplerate = MAX_SAMPLE_RATE_LA1016;
-               break;
-       case 8:
-               bitstream_fn = FPGA_FW_LA2016A;
-               devc->max_samplerate = MAX_SAMPLE_RATE_LA2016;
-               break;
-       case 9:
-               bitstream_fn = FPGA_FW_LA1016A;
-               devc->max_samplerate = MAX_SAMPLE_RATE_LA1016;
-               break;
-       default:
-               bitstream_fn = NULL;
+       devc->model = NULL;
+       for (model_idx = 0; model_idx < ARRAY_SIZE(models); model_idx++) {
+               model = &models[model_idx];
+               if (model->magic != magic)
+                       continue;
+               devc->model = model;
+               sr_info("Model '%s', %zu channels, max %" PRIu64 "MHz.",
+                       model->name, model->channel_count,
+                       model->samplerate / SR_MHZ(1));
+               devc->fpga_bitstream = g_strdup_printf(FPGA_FWFILE_FMT,
+                       model->fpga_stem);
+               sr_info("FPGA bitstream file '%s'.", devc->fpga_bitstream);
                break;
        }
-       if (!bitstream_fn || !*bitstream_fn) {
+       if (!devc->model) {
                sr_err("Cannot identify as one of the supported models.");
                return SR_ERR;
        }
 
-       if (check_fpga_bitstream(sdi) != SR_OK) {
+       return SR_OK;
+}
+
+SR_PRIV int la2016_init_hardware(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       const char *bitstream_fn;
+       int ret;
+       uint16_t state;
+
+       devc = sdi->priv;
+       bitstream_fn = devc ? devc->fpga_bitstream : "";
+
+       ret = check_fpga_bitstream(sdi);
+       if (ret != SR_OK) {
                ret = upload_fpga_bitstream(sdi, bitstream_fn);
                if (ret != SR_OK) {
                        sr_err("Cannot upload FPGA bitstream.");
@@ -1322,13 +1400,21 @@ SR_PRIV int la2016_init_device(const struct sr_dev_inst *sdi)
                sr_warn("Unexpected run state, want 0x85e9, got 0x%04x.", state);
        }
 
-       if ((ret = ctrl_out(sdi, CMD_BULK_RESET, 0x00, 0, NULL, 0)) != SR_OK) {
+       ret = ctrl_out(sdi, CMD_BULK_RESET, 0x00, 0, NULL, 0);
+       if (ret != SR_OK) {
                sr_err("Cannot reset USB bulk transfer.");
                return ret;
        }
 
        sr_dbg("Device should be initialized.");
 
+       return SR_OK;
+}
+
+SR_PRIV int la2016_init_params(const struct sr_dev_inst *sdi)
+{
+       int ret;
+
        ret = set_defaults(sdi);
        if (ret != SR_OK)
                return ret;
@@ -1336,11 +1422,12 @@ SR_PRIV int la2016_init_device(const struct sr_dev_inst *sdi)
        return SR_OK;
 }
 
-SR_PRIV int la2016_deinit_device(const struct sr_dev_inst *sdi)
+SR_PRIV int la2016_deinit_hardware(const struct sr_dev_inst *sdi)
 {
        int ret;
 
-       if ((ret = ctrl_out(sdi, CMD_FPGA_ENABLE, 0x00, 0, NULL, 0)) != SR_OK) {
+       ret = ctrl_out(sdi, CMD_FPGA_ENABLE, 0x00, 0, NULL, 0);
+       if (ret != SR_OK) {
                sr_err("Cannot deinitialize device's FPGA.");
                return ret;
        }