2010-04-02 18:18:27 +00:00
|
|
|
/*
|
2013-04-23 20:24:30 +00:00
|
|
|
* This file is part of the libsigrok project.
|
2010-04-02 18:18:27 +00:00
|
|
|
*
|
2012-02-13 13:31:51 +00:00
|
|
|
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
|
2010-04-02 18:18:27 +00:00
|
|
|
*
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2013-01-28 16:43:04 +00:00
|
|
|
#include "protocol.h"
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2012-05-30 20:55:03 +00:00
|
|
|
#define VENDOR_NAME "ZEROPLUS"
|
2010-04-02 18:18:27 +00:00
|
|
|
#define USB_INTERFACE 0
|
|
|
|
#define USB_CONFIGURATION 1
|
|
|
|
#define NUM_TRIGGER_STAGES 4
|
2013-01-25 10:52:27 +00:00
|
|
|
#define TRIGGER_TYPE "01"
|
2010-04-15 20:59:43 +00:00
|
|
|
#define PACKET_SIZE 2048 /* ?? */
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2012-11-05 07:06:14 +00:00
|
|
|
//#define ZP_EXPERIMENTAL
|
|
|
|
|
2013-02-08 21:18:55 +00:00
|
|
|
struct zp_model {
|
|
|
|
uint16_t vid;
|
|
|
|
uint16_t pid;
|
2012-07-22 00:08:59 +00:00
|
|
|
char *model_name;
|
2010-04-02 18:18:27 +00:00
|
|
|
unsigned int channels;
|
2010-04-15 20:59:43 +00:00
|
|
|
unsigned int sample_depth; /* In Ksamples/channel */
|
2010-04-02 18:18:27 +00:00
|
|
|
unsigned int max_sampling_freq;
|
2013-02-08 21:18:55 +00:00
|
|
|
};
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2010-04-15 20:59:43 +00:00
|
|
|
/*
|
|
|
|
* Note -- 16032, 16064 and 16128 *usually* -- but not always -- have the
|
|
|
|
* same 128K sample depth.
|
|
|
|
*/
|
2013-02-08 21:18:55 +00:00
|
|
|
static const struct zp_model zeroplus_models[] = {
|
2013-04-13 21:27:07 +00:00
|
|
|
{0x0c12, 0x7002, "LAP-16128U", 16, 128, 200},
|
2012-07-22 00:08:59 +00:00
|
|
|
{0x0c12, 0x7009, "LAP-C(16064)", 16, 64, 100},
|
2013-02-08 21:18:55 +00:00
|
|
|
{0x0c12, 0x700a, "LAP-C(16128)", 16, 128, 200},
|
2013-12-03 05:25:10 +00:00
|
|
|
{0x0c12, 0x700b, "LAP-C(32128)", 32, 128, 200},
|
|
|
|
{0x0c12, 0x700c, "LAP-C(321000)", 32, 1024, 200},
|
|
|
|
{0x0c12, 0x700d, "LAP-C(322000)", 32, 2048, 200},
|
2013-02-08 21:18:55 +00:00
|
|
|
{0x0c12, 0x700e, "LAP-C(16032)", 16, 32, 100},
|
2012-07-22 00:08:59 +00:00
|
|
|
{0x0c12, 0x7016, "LAP-C(162000)", 16, 2048, 200},
|
|
|
|
{ 0, 0, 0, 0, 0, 0 }
|
2010-04-02 18:18:27 +00:00
|
|
|
};
|
|
|
|
|
2013-03-30 18:48:38 +00:00
|
|
|
static const int32_t hwcaps[] = {
|
2013-01-21 22:22:47 +00:00
|
|
|
SR_CONF_LOGIC_ANALYZER,
|
|
|
|
SR_CONF_SAMPLERATE,
|
|
|
|
SR_CONF_CAPTURE_RATIO,
|
2013-12-03 07:29:04 +00:00
|
|
|
SR_CONF_VOLTAGE_THRESHOLD,
|
2013-01-21 22:22:47 +00:00
|
|
|
SR_CONF_LIMIT_SAMPLES,
|
2010-04-02 18:18:27 +00:00
|
|
|
};
|
|
|
|
|
2012-02-28 00:09:29 +00:00
|
|
|
/*
|
|
|
|
* ZEROPLUS LAP-C (16032) numbers the 16 probes A0-A7 and B0-B7.
|
|
|
|
* We currently ignore other untested/unsupported devices here.
|
|
|
|
*/
|
2013-02-08 21:18:55 +00:00
|
|
|
static const char *probe_names[] = {
|
2012-12-25 23:12:52 +00:00
|
|
|
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
|
|
|
|
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7",
|
2013-12-03 05:25:10 +00:00
|
|
|
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7",
|
|
|
|
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
|
2011-12-29 16:04:31 +00:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2012-07-13 11:43:41 +00:00
|
|
|
SR_PRIV struct sr_dev_driver zeroplus_logic_cube_driver_info;
|
2012-12-17 23:52:39 +00:00
|
|
|
static struct sr_dev_driver *di = &zeroplus_logic_cube_driver_info;
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2010-04-15 20:59:43 +00:00
|
|
|
/*
|
|
|
|
* The hardware supports more samplerates than these, but these are the
|
|
|
|
* options hardcoded into the vendor's Windows GUI.
|
|
|
|
*/
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2013-03-30 18:48:38 +00:00
|
|
|
static const uint64_t samplerates_100[] = {
|
2013-02-08 22:13:33 +00:00
|
|
|
SR_HZ(100),
|
|
|
|
SR_HZ(500),
|
|
|
|
SR_KHZ(1),
|
|
|
|
SR_KHZ(5),
|
|
|
|
SR_KHZ(25),
|
|
|
|
SR_KHZ(50),
|
|
|
|
SR_KHZ(100),
|
|
|
|
SR_KHZ(200),
|
|
|
|
SR_KHZ(400),
|
|
|
|
SR_KHZ(800),
|
|
|
|
SR_MHZ(1),
|
|
|
|
SR_MHZ(10),
|
|
|
|
SR_MHZ(25),
|
|
|
|
SR_MHZ(50),
|
|
|
|
SR_MHZ(80),
|
|
|
|
SR_MHZ(100),
|
|
|
|
};
|
|
|
|
|
2013-03-30 18:48:38 +00:00
|
|
|
const uint64_t samplerates_200[] = {
|
2011-02-22 17:05:16 +00:00
|
|
|
SR_HZ(100),
|
|
|
|
SR_HZ(500),
|
2011-02-22 16:57:03 +00:00
|
|
|
SR_KHZ(1),
|
|
|
|
SR_KHZ(5),
|
|
|
|
SR_KHZ(25),
|
|
|
|
SR_KHZ(50),
|
|
|
|
SR_KHZ(100),
|
|
|
|
SR_KHZ(200),
|
|
|
|
SR_KHZ(400),
|
|
|
|
SR_KHZ(800),
|
|
|
|
SR_MHZ(1),
|
|
|
|
SR_MHZ(10),
|
|
|
|
SR_MHZ(25),
|
|
|
|
SR_MHZ(50),
|
|
|
|
SR_MHZ(80),
|
|
|
|
SR_MHZ(100),
|
|
|
|
SR_MHZ(150),
|
|
|
|
SR_MHZ(200),
|
2012-01-29 18:14:25 +00:00
|
|
|
};
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2013-05-10 17:37:54 +00:00
|
|
|
static int dev_close(struct sr_dev_inst *sdi);
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2012-11-05 07:06:14 +00:00
|
|
|
#if 0
|
2012-08-05 16:56:12 +00:00
|
|
|
static int configure_probes(const struct sr_dev_inst *sdi)
|
2010-04-02 18:18:27 +00:00
|
|
|
{
|
2012-08-02 23:01:38 +00:00
|
|
|
struct dev_context *devc;
|
2012-05-07 14:02:02 +00:00
|
|
|
const struct sr_probe *probe;
|
|
|
|
const GSList *l;
|
2010-04-02 18:18:27 +00:00
|
|
|
int probe_bit, stage, i;
|
|
|
|
char *tc;
|
|
|
|
|
2012-01-29 18:14:25 +00:00
|
|
|
/* Note: sdi and sdi->priv are non-NULL, the caller checked this. */
|
2012-08-02 23:01:38 +00:00
|
|
|
devc = sdi->priv;
|
2012-01-29 18:14:25 +00:00
|
|
|
|
2012-08-02 23:01:38 +00:00
|
|
|
devc->probe_mask = 0;
|
2010-04-15 20:59:43 +00:00
|
|
|
for (i = 0; i < NUM_TRIGGER_STAGES; i++) {
|
2012-08-02 23:01:38 +00:00
|
|
|
devc->trigger_mask[i] = 0;
|
|
|
|
devc->trigger_value[i] = 0;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
stage = -1;
|
2012-08-05 16:56:12 +00:00
|
|
|
for (l = sdi->probes; l; l = l->next) {
|
2011-02-08 16:47:38 +00:00
|
|
|
probe = (struct sr_probe *)l->data;
|
2010-04-15 20:59:43 +00:00
|
|
|
if (probe->enabled == FALSE)
|
2010-04-02 18:18:27 +00:00
|
|
|
continue;
|
2012-07-24 15:13:25 +00:00
|
|
|
probe_bit = 1 << (probe->index);
|
2012-08-02 23:01:38 +00:00
|
|
|
devc->probe_mask |= probe_bit;
|
2010-04-15 20:59:43 +00:00
|
|
|
|
|
|
|
if (probe->trigger) {
|
2010-04-02 18:18:27 +00:00
|
|
|
stage = 0;
|
2010-04-15 20:59:43 +00:00
|
|
|
for (tc = probe->trigger; *tc; tc++) {
|
2012-08-02 23:01:38 +00:00
|
|
|
devc->trigger_mask[stage] |= probe_bit;
|
2010-04-15 20:59:43 +00:00
|
|
|
if (*tc == '1')
|
2012-08-02 23:01:38 +00:00
|
|
|
devc->trigger_value[stage] |= probe_bit;
|
2010-04-02 18:18:27 +00:00
|
|
|
stage++;
|
2010-04-15 20:59:43 +00:00
|
|
|
if (stage > NUM_TRIGGER_STAGES)
|
2011-01-29 15:23:12 +00:00
|
|
|
return SR_ERR;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-29 15:23:12 +00:00
|
|
|
return SR_OK;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
2012-11-05 07:06:14 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
static int configure_probes(const struct sr_dev_inst *sdi)
|
|
|
|
{
|
|
|
|
struct dev_context *devc;
|
|
|
|
const GSList *l;
|
|
|
|
const struct sr_probe *probe;
|
|
|
|
char *tc;
|
|
|
|
int type;
|
|
|
|
|
|
|
|
/* Note: sdi and sdi->priv are non-NULL, the caller checked this. */
|
|
|
|
devc = sdi->priv;
|
|
|
|
|
|
|
|
for (l = sdi->probes; l; l = l->next) {
|
|
|
|
probe = (struct sr_probe *)l->data;
|
|
|
|
if (probe->enabled == FALSE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((tc = probe->trigger)) {
|
|
|
|
switch (*tc) {
|
|
|
|
case '1':
|
|
|
|
type = TRIGGER_HIGH;
|
|
|
|
break;
|
|
|
|
case '0':
|
|
|
|
type = TRIGGER_LOW;
|
|
|
|
break;
|
|
|
|
#if 0
|
|
|
|
case 'r':
|
|
|
|
type = TRIGGER_POSEDGE;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
type = TRIGGER_NEGEDGE;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
type = TRIGGER_ANYEDGE;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
return SR_ERR;
|
|
|
|
}
|
|
|
|
analyzer_add_trigger(probe->index, type);
|
|
|
|
devc->trigger = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SR_OK;
|
|
|
|
}
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2013-03-31 18:47:01 +00:00
|
|
|
SR_PRIV int zp_set_samplerate(struct dev_context *devc, uint64_t samplerate)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; ARRAY_SIZE(samplerates_200); i++)
|
|
|
|
if (samplerate == samplerates_200[i])
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (i == ARRAY_SIZE(samplerates_200) || samplerate > devc->max_samplerate) {
|
|
|
|
sr_err("Unsupported samplerate: %" PRIu64 "Hz.", samplerate);
|
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
sr_info("Setting samplerate to %" PRIu64 "Hz.", samplerate);
|
|
|
|
|
|
|
|
if (samplerate >= SR_MHZ(1))
|
|
|
|
analyzer_set_freq(samplerate / SR_MHZ(1), FREQ_SCALE_MHZ);
|
|
|
|
else if (samplerate >= SR_KHZ(1))
|
|
|
|
analyzer_set_freq(samplerate / SR_KHZ(1), FREQ_SCALE_KHZ);
|
|
|
|
else
|
|
|
|
analyzer_set_freq(samplerate, FREQ_SCALE_HZ);
|
|
|
|
|
|
|
|
devc->cur_samplerate = samplerate;
|
|
|
|
|
|
|
|
return SR_OK;
|
|
|
|
}
|
|
|
|
|
2013-05-10 17:37:54 +00:00
|
|
|
static int init(struct sr_context *sr_ctx)
|
2012-07-05 09:27:48 +00:00
|
|
|
{
|
2013-05-31 13:46:57 +00:00
|
|
|
return std_init(sr_ctx, di, LOG_PREFIX);
|
2012-07-05 09:27:48 +00:00
|
|
|
}
|
|
|
|
|
2013-05-10 17:37:54 +00:00
|
|
|
static GSList *scan(GSList *options)
|
2010-04-02 18:18:27 +00:00
|
|
|
{
|
2012-02-17 20:02:52 +00:00
|
|
|
struct sr_dev_inst *sdi;
|
2012-07-22 00:08:59 +00:00
|
|
|
struct sr_probe *probe;
|
2012-08-02 23:01:38 +00:00
|
|
|
struct drv_context *drvc;
|
|
|
|
struct dev_context *devc;
|
2013-02-08 21:18:55 +00:00
|
|
|
const struct zp_model *prof;
|
2010-04-02 18:18:27 +00:00
|
|
|
struct libusb_device_descriptor des;
|
|
|
|
libusb_device **devlist;
|
2012-07-22 00:08:59 +00:00
|
|
|
GSList *devices;
|
|
|
|
int ret, devcnt, i, j;
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2012-07-14 10:45:07 +00:00
|
|
|
(void)options;
|
2012-11-11 08:30:42 +00:00
|
|
|
|
2012-12-17 23:52:39 +00:00
|
|
|
drvc = di->priv;
|
2013-01-28 19:00:54 +00:00
|
|
|
|
2012-07-14 10:45:07 +00:00
|
|
|
devices = NULL;
|
|
|
|
|
2012-05-30 20:55:03 +00:00
|
|
|
/* Find all ZEROPLUS analyzers and add them to device list. */
|
2010-04-02 18:18:27 +00:00
|
|
|
devcnt = 0;
|
2012-12-03 02:33:24 +00:00
|
|
|
libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); /* TODO: Errors. */
|
2010-04-15 20:59:43 +00:00
|
|
|
|
|
|
|
for (i = 0; devlist[i]; i++) {
|
2012-03-20 16:51:18 +00:00
|
|
|
ret = libusb_get_device_descriptor(devlist[i], &des);
|
|
|
|
if (ret != 0) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("Failed to get device descriptor: %s.",
|
2012-12-04 20:11:25 +00:00
|
|
|
libusb_error_name(ret));
|
2010-04-02 18:18:27 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-07-22 00:08:59 +00:00
|
|
|
prof = NULL;
|
|
|
|
for (j = 0; j < zeroplus_models[j].vid; j++) {
|
|
|
|
if (des.idVendor == zeroplus_models[j].vid &&
|
|
|
|
des.idProduct == zeroplus_models[j].pid) {
|
|
|
|
prof = &zeroplus_models[j];
|
2012-01-29 18:14:25 +00:00
|
|
|
}
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
2013-02-08 21:18:55 +00:00
|
|
|
/* Skip if the device was not found. */
|
2012-07-22 00:08:59 +00:00
|
|
|
if (!prof)
|
|
|
|
continue;
|
2013-02-08 21:18:55 +00:00
|
|
|
sr_info("Found ZEROPLUS %s.", prof->model_name);
|
2012-07-22 00:08:59 +00:00
|
|
|
|
|
|
|
/* Register the device with libsigrok. */
|
|
|
|
if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE,
|
|
|
|
VENDOR_NAME, prof->model_name, NULL))) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("%s: sr_dev_inst_new failed", __func__);
|
2012-07-22 00:08:59 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2012-12-17 23:52:39 +00:00
|
|
|
sdi->driver = di;
|
2012-07-22 00:08:59 +00:00
|
|
|
|
|
|
|
/* Allocate memory for our private driver context. */
|
2012-08-02 23:01:38 +00:00
|
|
|
if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("Device context malloc failed.");
|
2012-10-30 19:20:22 +00:00
|
|
|
return NULL;
|
2012-07-22 00:08:59 +00:00
|
|
|
}
|
2013-02-08 21:18:55 +00:00
|
|
|
|
2012-08-02 23:01:38 +00:00
|
|
|
sdi->priv = devc;
|
2013-02-08 22:13:33 +00:00
|
|
|
devc->prof = prof;
|
2012-08-02 23:01:38 +00:00
|
|
|
devc->num_channels = prof->channels;
|
2012-11-05 07:06:14 +00:00
|
|
|
#ifdef ZP_EXPERIMENTAL
|
2013-12-03 05:51:53 +00:00
|
|
|
devc->max_sample_depth = 128 * 1024;
|
2012-11-05 07:06:14 +00:00
|
|
|
devc->max_samplerate = 200;
|
|
|
|
#else
|
2013-12-03 05:51:53 +00:00
|
|
|
devc->max_sample_depth = prof->sample_depth * 1024;
|
2012-11-05 07:06:14 +00:00
|
|
|
devc->max_samplerate = prof->max_sampling_freq;
|
|
|
|
#endif
|
|
|
|
devc->max_samplerate *= SR_MHZ(1);
|
|
|
|
devc->memory_size = MEMORY_SIZE_8K;
|
2012-08-02 23:01:38 +00:00
|
|
|
// memset(devc->trigger_buffer, 0, NUM_TRIGGER_STAGES);
|
2012-07-22 00:08:59 +00:00
|
|
|
|
|
|
|
/* Fill in probelist according to this device's profile. */
|
2012-08-02 23:01:38 +00:00
|
|
|
for (j = 0; j < devc->num_channels; j++) {
|
2012-07-22 00:08:59 +00:00
|
|
|
if (!(probe = sr_probe_new(j, SR_PROBE_LOGIC, TRUE,
|
|
|
|
probe_names[j])))
|
|
|
|
return NULL;
|
|
|
|
sdi->probes = g_slist_append(sdi->probes, probe);
|
|
|
|
}
|
|
|
|
|
|
|
|
devices = g_slist_append(devices, sdi);
|
2012-08-02 23:01:38 +00:00
|
|
|
drvc->instances = g_slist_append(drvc->instances, sdi);
|
2013-05-10 17:16:25 +00:00
|
|
|
sdi->inst_type = SR_INST_USB;
|
2013-04-22 13:00:04 +00:00
|
|
|
sdi->conn = sr_usb_dev_inst_new(
|
2012-07-22 00:08:59 +00:00
|
|
|
libusb_get_bus_number(devlist[i]),
|
|
|
|
libusb_get_device_address(devlist[i]), NULL);
|
|
|
|
devcnt++;
|
|
|
|
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
libusb_free_device_list(devlist, 1);
|
|
|
|
|
2012-07-14 10:45:07 +00:00
|
|
|
return devices;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
|
2013-05-10 17:37:54 +00:00
|
|
|
static GSList *dev_list(void)
|
2012-08-05 22:59:25 +00:00
|
|
|
{
|
2013-02-02 18:52:26 +00:00
|
|
|
return ((struct drv_context *)(di->priv))->instances;
|
2012-08-05 22:59:25 +00:00
|
|
|
}
|
|
|
|
|
2013-05-10 17:37:54 +00:00
|
|
|
static int dev_open(struct sr_dev_inst *sdi)
|
2010-04-02 18:18:27 +00:00
|
|
|
{
|
2012-08-02 23:01:38 +00:00
|
|
|
struct dev_context *devc;
|
2013-02-08 21:18:55 +00:00
|
|
|
struct drv_context *drvc;
|
2013-04-22 13:00:04 +00:00
|
|
|
struct sr_usb_dev_inst *usb;
|
2012-07-22 00:08:59 +00:00
|
|
|
libusb_device **devlist, *dev;
|
|
|
|
struct libusb_device_descriptor des;
|
|
|
|
int device_count, ret, i;
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2013-02-08 21:18:55 +00:00
|
|
|
drvc = di->priv;
|
2013-04-22 13:00:04 +00:00
|
|
|
usb = sdi->conn;
|
2013-02-08 21:18:55 +00:00
|
|
|
|
2012-08-02 23:01:38 +00:00
|
|
|
if (!(devc = sdi->priv)) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("%s: sdi->priv was NULL", __func__);
|
2012-01-29 18:14:25 +00:00
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
|
|
|
|
2012-12-03 02:33:24 +00:00
|
|
|
device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx,
|
|
|
|
&devlist);
|
2012-07-22 00:08:59 +00:00
|
|
|
if (device_count < 0) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("Failed to retrieve device list.");
|
2012-07-22 00:08:59 +00:00
|
|
|
return SR_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev = NULL;
|
|
|
|
for (i = 0; i < device_count; i++) {
|
|
|
|
if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("Failed to get device descriptor: %s.",
|
2012-12-04 20:11:25 +00:00
|
|
|
libusb_error_name(ret));
|
2012-07-22 00:08:59 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-04-22 13:00:04 +00:00
|
|
|
if (libusb_get_bus_number(devlist[i]) == usb->bus
|
|
|
|
&& libusb_get_device_address(devlist[i]) == usb->address) {
|
2012-07-22 00:08:59 +00:00
|
|
|
dev = devlist[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!dev) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("Device on bus %d address %d disappeared!",
|
2013-04-22 13:00:04 +00:00
|
|
|
usb->bus, usb->address);
|
2012-07-22 00:08:59 +00:00
|
|
|
return SR_ERR;
|
|
|
|
}
|
|
|
|
|
2013-04-22 13:00:04 +00:00
|
|
|
if (!(ret = libusb_open(dev, &(usb->devhdl)))) {
|
2012-07-22 00:08:59 +00:00
|
|
|
sdi->status = SR_ST_ACTIVE;
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_info("Opened device %d on %d.%d interface %d.",
|
2013-04-22 13:00:04 +00:00
|
|
|
sdi->index, usb->bus, usb->address, USB_INTERFACE);
|
2012-07-22 00:08:59 +00:00
|
|
|
} else {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("Failed to open device: %s.", libusb_error_name(ret));
|
2012-07-22 00:08:59 +00:00
|
|
|
return SR_ERR;
|
|
|
|
}
|
|
|
|
|
2013-04-22 13:00:04 +00:00
|
|
|
ret = libusb_set_configuration(usb->devhdl, USB_CONFIGURATION);
|
2012-03-20 16:51:18 +00:00
|
|
|
if (ret < 0) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("Unable to set USB configuration %d: %s.",
|
2012-12-04 20:11:25 +00:00
|
|
|
USB_CONFIGURATION, libusb_error_name(ret));
|
2012-02-02 20:08:33 +00:00
|
|
|
return SR_ERR;
|
|
|
|
}
|
|
|
|
|
2013-04-22 13:00:04 +00:00
|
|
|
ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
|
2012-03-20 16:51:18 +00:00
|
|
|
if (ret != 0) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("Unable to claim interface: %s.",
|
2012-12-04 20:11:25 +00:00
|
|
|
libusb_error_name(ret));
|
2011-01-29 15:23:12 +00:00
|
|
|
return SR_ERR;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
2012-02-02 20:08:33 +00:00
|
|
|
|
2013-02-08 21:18:55 +00:00
|
|
|
/* Set default configuration after power on. */
|
2013-04-22 13:00:04 +00:00
|
|
|
if (analyzer_read_status(usb->devhdl) == 0)
|
|
|
|
analyzer_configure(usb->devhdl);
|
2012-11-05 07:06:14 +00:00
|
|
|
|
2013-04-22 13:00:04 +00:00
|
|
|
analyzer_reset(usb->devhdl);
|
|
|
|
analyzer_initialize(usb->devhdl);
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2012-11-05 07:06:14 +00:00
|
|
|
//analyzer_set_memory_size(MEMORY_SIZE_512K);
|
2010-04-15 20:59:43 +00:00
|
|
|
// analyzer_set_freq(g_freq, g_freq_scale);
|
2010-04-02 18:18:27 +00:00
|
|
|
analyzer_set_trigger_count(1);
|
2010-04-15 21:21:30 +00:00
|
|
|
// analyzer_set_ramsize_trigger_address((((100 - g_pre_trigger)
|
|
|
|
// * get_memory_size(g_memory_size)) / 100) >> 2);
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2010-04-15 20:59:43 +00:00
|
|
|
#if 0
|
|
|
|
if (g_double_mode == 1)
|
2010-04-02 18:18:27 +00:00
|
|
|
analyzer_set_compression(COMPRESSION_DOUBLE);
|
|
|
|
else if (g_compression == 1)
|
|
|
|
analyzer_set_compression(COMPRESSION_ENABLE);
|
2010-04-15 20:59:43 +00:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
analyzer_set_compression(COMPRESSION_NONE);
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2012-08-02 23:01:38 +00:00
|
|
|
if (devc->cur_samplerate == 0) {
|
2012-11-05 07:06:14 +00:00
|
|
|
/* Samplerate hasn't been set. Default to 1MHz. */
|
|
|
|
analyzer_set_freq(1, FREQ_SCALE_MHZ);
|
|
|
|
devc->cur_samplerate = SR_MHZ(1);
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
|
2013-12-03 07:29:04 +00:00
|
|
|
if (devc->cur_threshold == 0)
|
|
|
|
set_voltage_threshold(devc, 1.5);
|
|
|
|
|
2011-01-29 15:23:12 +00:00
|
|
|
return SR_OK;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
|
2013-05-10 17:37:54 +00:00
|
|
|
static int dev_close(struct sr_dev_inst *sdi)
|
2010-04-02 18:18:27 +00:00
|
|
|
{
|
2013-04-22 13:00:04 +00:00
|
|
|
struct sr_usb_dev_inst *usb;
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2013-04-22 13:00:04 +00:00
|
|
|
usb = sdi->conn;
|
2011-05-04 17:34:12 +00:00
|
|
|
|
2013-04-22 13:00:04 +00:00
|
|
|
if (!usb->devhdl)
|
2012-07-21 20:04:47 +00:00
|
|
|
return SR_ERR;
|
|
|
|
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_info("Closing device %d on %d.%d interface %d.", sdi->index,
|
2013-04-22 13:00:04 +00:00
|
|
|
usb->bus, usb->address, USB_INTERFACE);
|
|
|
|
libusb_release_interface(usb->devhdl, USB_INTERFACE);
|
|
|
|
libusb_reset_device(usb->devhdl);
|
|
|
|
libusb_close(usb->devhdl);
|
|
|
|
usb->devhdl = NULL;
|
2012-07-21 20:04:47 +00:00
|
|
|
sdi->status = SR_ST_INACTIVE;
|
2011-05-04 17:34:12 +00:00
|
|
|
|
|
|
|
return SR_OK;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
|
2013-05-10 17:37:54 +00:00
|
|
|
static int cleanup(void)
|
2010-04-02 18:18:27 +00:00
|
|
|
{
|
2014-02-26 20:37:18 +00:00
|
|
|
return std_dev_clear(di, NULL);
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
|
2013-04-20 00:00:49 +00:00
|
|
|
static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
|
|
|
|
const struct sr_probe_group *probe_group)
|
2010-04-02 18:18:27 +00:00
|
|
|
{
|
2012-08-02 23:01:38 +00:00
|
|
|
struct dev_context *devc;
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2013-04-20 00:00:49 +00:00
|
|
|
(void)probe_group;
|
|
|
|
|
2013-01-24 18:19:09 +00:00
|
|
|
switch (id) {
|
2013-01-25 02:17:36 +00:00
|
|
|
case SR_CONF_SAMPLERATE:
|
2012-07-15 01:53:09 +00:00
|
|
|
if (sdi) {
|
2012-08-02 23:01:38 +00:00
|
|
|
devc = sdi->priv;
|
2013-03-30 18:48:38 +00:00
|
|
|
*data = g_variant_new_uint64(devc->cur_samplerate);
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_spew("Returning samplerate: %" PRIu64 "Hz.",
|
|
|
|
devc->cur_samplerate);
|
2012-07-15 01:53:09 +00:00
|
|
|
} else
|
2014-01-09 13:30:20 +00:00
|
|
|
return SR_ERR_ARG;
|
2012-01-29 18:14:25 +00:00
|
|
|
break;
|
2013-12-30 15:05:17 +00:00
|
|
|
case SR_CONF_CAPTURE_RATIO:
|
|
|
|
if (sdi) {
|
|
|
|
devc = sdi->priv;
|
|
|
|
*data = g_variant_new_uint64(devc->capture_ratio);
|
|
|
|
} else
|
2014-01-09 13:30:20 +00:00
|
|
|
return SR_ERR_ARG;
|
2013-12-30 15:05:17 +00:00
|
|
|
break;
|
2013-12-03 07:29:04 +00:00
|
|
|
case SR_CONF_VOLTAGE_THRESHOLD:
|
|
|
|
if (sdi) {
|
|
|
|
GVariant *range[2];
|
|
|
|
devc = sdi->priv;
|
|
|
|
range[0] = g_variant_new_double(devc->cur_threshold);
|
|
|
|
range[1] = g_variant_new_double(devc->cur_threshold);
|
|
|
|
*data = g_variant_new_tuple(range, 2);
|
2014-01-09 13:30:20 +00:00
|
|
|
} else
|
|
|
|
return SR_ERR_ARG;
|
|
|
|
break;
|
2012-01-29 18:14:25 +00:00
|
|
|
default:
|
2013-04-16 00:33:03 +00:00
|
|
|
return SR_ERR_NA;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
|
2012-07-15 01:53:09 +00:00
|
|
|
return SR_OK;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
|
2013-04-20 00:00:49 +00:00
|
|
|
static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
|
|
|
|
const struct sr_probe_group *probe_group)
|
2010-04-02 18:18:27 +00:00
|
|
|
{
|
2012-08-02 23:01:38 +00:00
|
|
|
struct dev_context *devc;
|
2013-12-03 07:29:04 +00:00
|
|
|
gdouble low, high;
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2013-04-20 00:00:49 +00:00
|
|
|
(void)probe_group;
|
|
|
|
|
2013-04-23 13:14:42 +00:00
|
|
|
if (sdi->status != SR_ST_ACTIVE)
|
|
|
|
return SR_ERR_DEV_CLOSED;
|
2012-11-05 07:06:14 +00:00
|
|
|
|
2012-08-02 23:01:38 +00:00
|
|
|
if (!(devc = sdi->priv)) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("%s: sdi->priv was NULL", __func__);
|
2012-01-29 18:14:25 +00:00
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2013-01-24 18:19:09 +00:00
|
|
|
switch (id) {
|
2013-01-21 22:22:47 +00:00
|
|
|
case SR_CONF_SAMPLERATE:
|
2013-03-30 18:48:38 +00:00
|
|
|
return zp_set_samplerate(devc, g_variant_get_uint64(data));
|
2013-01-21 22:22:47 +00:00
|
|
|
case SR_CONF_LIMIT_SAMPLES:
|
2013-03-30 18:48:38 +00:00
|
|
|
return set_limit_samples(devc, g_variant_get_uint64(data));
|
2013-01-21 22:22:47 +00:00
|
|
|
case SR_CONF_CAPTURE_RATIO:
|
2013-03-30 18:48:38 +00:00
|
|
|
return set_capture_ratio(devc, g_variant_get_uint64(data));
|
2013-12-03 07:29:04 +00:00
|
|
|
case SR_CONF_VOLTAGE_THRESHOLD:
|
|
|
|
g_variant_get(data, "(dd)", &low, &high);
|
|
|
|
return set_voltage_threshold(devc, (low + high) / 2.0);
|
2010-04-15 20:59:43 +00:00
|
|
|
default:
|
2013-04-16 00:33:03 +00:00
|
|
|
return SR_ERR_NA;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
2013-02-08 21:18:55 +00:00
|
|
|
|
|
|
|
return SR_OK;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
|
2013-04-20 00:00:49 +00:00
|
|
|
static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
|
|
|
|
const struct sr_probe_group *probe_group)
|
2013-01-25 01:32:05 +00:00
|
|
|
{
|
2013-02-08 22:13:33 +00:00
|
|
|
struct dev_context *devc;
|
2014-01-19 16:18:59 +00:00
|
|
|
GVariant *gvar, *grange[2];
|
2013-03-30 18:48:38 +00:00
|
|
|
GVariantBuilder gvb;
|
2013-12-03 07:29:04 +00:00
|
|
|
double v;
|
|
|
|
GVariant *range[2];
|
2013-01-25 01:32:05 +00:00
|
|
|
|
2013-04-20 00:00:49 +00:00
|
|
|
(void)probe_group;
|
|
|
|
|
2013-01-25 01:32:05 +00:00
|
|
|
switch (key) {
|
2013-01-25 14:01:49 +00:00
|
|
|
case SR_CONF_DEVICE_OPTIONS:
|
2013-03-30 18:48:38 +00:00
|
|
|
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
|
|
|
|
hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
|
2013-01-25 14:01:49 +00:00
|
|
|
break;
|
2013-01-25 01:32:05 +00:00
|
|
|
case SR_CONF_SAMPLERATE:
|
2013-02-08 22:13:33 +00:00
|
|
|
devc = sdi->priv;
|
2013-03-30 18:48:38 +00:00
|
|
|
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
|
2013-02-08 22:13:33 +00:00
|
|
|
if (devc->prof->max_sampling_freq == 100) {
|
2013-03-30 18:48:38 +00:00
|
|
|
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
|
|
|
|
samplerates_100, ARRAY_SIZE(samplerates_100),
|
|
|
|
sizeof(uint64_t));
|
2013-02-08 22:13:33 +00:00
|
|
|
} else if (devc->prof->max_sampling_freq == 200) {
|
2013-03-30 18:48:38 +00:00
|
|
|
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
|
|
|
|
samplerates_200, ARRAY_SIZE(samplerates_200),
|
|
|
|
sizeof(uint64_t));
|
2013-02-08 22:13:33 +00:00
|
|
|
} else {
|
|
|
|
sr_err("Internal error: Unknown max. samplerate: %d.",
|
|
|
|
devc->prof->max_sampling_freq);
|
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
2013-03-30 18:48:38 +00:00
|
|
|
g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
|
|
|
|
*data = g_variant_builder_end(&gvb);
|
2013-01-25 01:32:05 +00:00
|
|
|
break;
|
2013-01-25 10:52:27 +00:00
|
|
|
case SR_CONF_TRIGGER_TYPE:
|
2013-03-30 18:48:38 +00:00
|
|
|
*data = g_variant_new_string(TRIGGER_TYPE);
|
2013-01-25 10:52:27 +00:00
|
|
|
break;
|
2013-12-03 07:29:04 +00:00
|
|
|
case SR_CONF_VOLTAGE_THRESHOLD:
|
|
|
|
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
|
|
|
|
for (v = -6.0; v <= 6.0; v += 0.1) {
|
|
|
|
range[0] = g_variant_new_double(v);
|
|
|
|
range[1] = g_variant_new_double(v);
|
|
|
|
gvar = g_variant_new_tuple(range, 2);
|
|
|
|
g_variant_builder_add_value(&gvb, gvar);
|
|
|
|
}
|
|
|
|
*data = g_variant_builder_end(&gvb);
|
|
|
|
break;
|
2014-01-19 16:18:59 +00:00
|
|
|
case SR_CONF_LIMIT_SAMPLES:
|
|
|
|
if (!sdi)
|
|
|
|
return SR_ERR_ARG;
|
|
|
|
devc = sdi->priv;
|
|
|
|
grange[0] = g_variant_new_uint64(0);
|
|
|
|
grange[1] = g_variant_new_uint64(devc->max_sample_depth);
|
|
|
|
*data = g_variant_new_tuple(grange, 2);
|
|
|
|
break;
|
2013-01-25 01:32:05 +00:00
|
|
|
default:
|
2013-04-16 00:33:03 +00:00
|
|
|
return SR_ERR_NA;
|
2013-01-25 01:32:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return SR_OK;
|
|
|
|
}
|
|
|
|
|
2013-05-10 17:37:54 +00:00
|
|
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi,
|
2012-07-21 20:41:58 +00:00
|
|
|
void *cb_data)
|
2010-04-02 18:18:27 +00:00
|
|
|
{
|
2013-04-22 13:00:04 +00:00
|
|
|
struct dev_context *devc;
|
|
|
|
struct sr_usb_dev_inst *usb;
|
2011-01-29 16:03:26 +00:00
|
|
|
struct sr_datafeed_packet packet;
|
2011-06-19 12:28:50 +00:00
|
|
|
struct sr_datafeed_logic logic;
|
zeroplus: Major rework of sample buffer processing
The sample buffer is a still a bit of a mystery, but this should help.
The variables in play:
triggerbar/ramsize_trigger - These two variables added together indicate
how many samples we want captured. ramsize_trigger - triggerbar
indicades how many samples must be captured. The ratio between the two
is determined by capture ratio.
memory_size - This indicates the number of samples in the circular
capture buffer. stop_address, now_address, and trigger_address are
pointers within the zeroplus that wrap based on this size.
now_address - The address that the zeroplus was about to write to when
it finished capturing, and now the address that will be read from when
reads are done from the capture buffer
stop_address - The address that the zeroplus last wrote to when it
completed capture.
trigger_address - The sample address for which the trigger occured.
status - This one is a bit tricky. Some testing has shown that if the
zeroplus has captured memory_size or less samples, the STATUS_READY bit
is set. For all captures generated with more samples than this,
STATUS_READY was cleared. However, boundary conditions are difficult to
test and values such as, memory_size + 1 have not been tested. We use
this to determine if the capture has wrapped through the sample buffer.
More testing is required, but this improves behavior in a number of
cases, specifically capturing sample amounts that are not a power of 2
of the sample buffer size. Before, random data was passed to libsigrok.
Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
2013-12-30 15:12:49 +00:00
|
|
|
unsigned int samples_read;
|
2010-04-02 18:18:27 +00:00
|
|
|
int res;
|
2013-02-08 21:18:55 +00:00
|
|
|
unsigned int packet_num, n;
|
2010-04-02 18:18:27 +00:00
|
|
|
unsigned char *buf;
|
zeroplus: Major rework of sample buffer processing
The sample buffer is a still a bit of a mystery, but this should help.
The variables in play:
triggerbar/ramsize_trigger - These two variables added together indicate
how many samples we want captured. ramsize_trigger - triggerbar
indicades how many samples must be captured. The ratio between the two
is determined by capture ratio.
memory_size - This indicates the number of samples in the circular
capture buffer. stop_address, now_address, and trigger_address are
pointers within the zeroplus that wrap based on this size.
now_address - The address that the zeroplus was about to write to when
it finished capturing, and now the address that will be read from when
reads are done from the capture buffer
stop_address - The address that the zeroplus last wrote to when it
completed capture.
trigger_address - The sample address for which the trigger occured.
status - This one is a bit tricky. Some testing has shown that if the
zeroplus has captured memory_size or less samples, the STATUS_READY bit
is set. For all captures generated with more samples than this,
STATUS_READY was cleared. However, boundary conditions are difficult to
test and values such as, memory_size + 1 have not been tested. We use
this to determine if the capture has wrapped through the sample buffer.
More testing is required, but this improves behavior in a number of
cases, specifically capturing sample amounts that are not a power of 2
of the sample buffer size. Before, random data was passed to libsigrok.
Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
2013-12-30 15:12:49 +00:00
|
|
|
unsigned int status;
|
|
|
|
unsigned int stop_address;
|
|
|
|
unsigned int now_address;
|
|
|
|
unsigned int trigger_address;
|
|
|
|
unsigned int trigger_offset;
|
|
|
|
unsigned int triggerbar;
|
|
|
|
unsigned int ramsize_trigger;
|
|
|
|
unsigned int memory_size;
|
|
|
|
unsigned int valid_samples;
|
|
|
|
unsigned int discard;
|
|
|
|
int trigger_now;
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2013-04-23 13:14:42 +00:00
|
|
|
if (sdi->status != SR_ST_ACTIVE)
|
|
|
|
return SR_ERR_DEV_CLOSED;
|
|
|
|
|
2012-08-02 23:01:38 +00:00
|
|
|
if (!(devc = sdi->priv)) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("%s: sdi->priv was NULL", __func__);
|
2012-01-29 18:14:25 +00:00
|
|
|
return SR_ERR_ARG;
|
|
|
|
}
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2012-08-05 16:56:12 +00:00
|
|
|
if (configure_probes(sdi) != SR_OK) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("Failed to configure probes.");
|
2012-08-05 16:56:12 +00:00
|
|
|
return SR_ERR;
|
|
|
|
}
|
|
|
|
|
2013-04-22 13:00:04 +00:00
|
|
|
usb = sdi->conn;
|
|
|
|
|
2012-11-05 07:06:14 +00:00
|
|
|
set_triggerbar(devc);
|
|
|
|
|
2013-02-08 21:18:55 +00:00
|
|
|
/* Push configured settings to device. */
|
2013-04-22 13:00:04 +00:00
|
|
|
analyzer_configure(usb->devhdl);
|
2010-08-12 02:57:09 +00:00
|
|
|
|
2013-04-22 13:00:04 +00:00
|
|
|
analyzer_start(usb->devhdl);
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_info("Waiting for data.");
|
2013-04-22 13:00:04 +00:00
|
|
|
analyzer_wait_data(usb->devhdl);
|
2010-04-02 18:18:27 +00:00
|
|
|
|
zeroplus: Major rework of sample buffer processing
The sample buffer is a still a bit of a mystery, but this should help.
The variables in play:
triggerbar/ramsize_trigger - These two variables added together indicate
how many samples we want captured. ramsize_trigger - triggerbar
indicades how many samples must be captured. The ratio between the two
is determined by capture ratio.
memory_size - This indicates the number of samples in the circular
capture buffer. stop_address, now_address, and trigger_address are
pointers within the zeroplus that wrap based on this size.
now_address - The address that the zeroplus was about to write to when
it finished capturing, and now the address that will be read from when
reads are done from the capture buffer
stop_address - The address that the zeroplus last wrote to when it
completed capture.
trigger_address - The sample address for which the trigger occured.
status - This one is a bit tricky. Some testing has shown that if the
zeroplus has captured memory_size or less samples, the STATUS_READY bit
is set. For all captures generated with more samples than this,
STATUS_READY was cleared. However, boundary conditions are difficult to
test and values such as, memory_size + 1 have not been tested. We use
this to determine if the capture has wrapped through the sample buffer.
More testing is required, but this improves behavior in a number of
cases, specifically capturing sample amounts that are not a power of 2
of the sample buffer size. Before, random data was passed to libsigrok.
Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
2013-12-30 15:12:49 +00:00
|
|
|
status = analyzer_read_status(usb->devhdl);
|
|
|
|
stop_address = analyzer_get_stop_address(usb->devhdl);
|
|
|
|
now_address = analyzer_get_now_address(usb->devhdl);
|
|
|
|
trigger_address = analyzer_get_trigger_address(usb->devhdl);
|
|
|
|
|
|
|
|
triggerbar = analyzer_get_triggerbar_address();
|
|
|
|
ramsize_trigger = analyzer_get_ramsize_trigger_address();
|
|
|
|
|
|
|
|
n = get_memory_size(devc->memory_size);
|
|
|
|
memory_size = n / 4;
|
|
|
|
|
|
|
|
sr_info("Status = 0x%x.", status);
|
|
|
|
sr_info("Stop address = 0x%x.", stop_address);
|
|
|
|
sr_info("Now address = 0x%x.", now_address);
|
|
|
|
sr_info("Trigger address = 0x%x.", trigger_address);
|
|
|
|
sr_info("Triggerbar address = 0x%x.", triggerbar);
|
|
|
|
sr_info("Ramsize trigger = 0x%x.", ramsize_trigger);
|
|
|
|
sr_info("Memory size = 0x%x.", memory_size);
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2013-02-06 18:57:32 +00:00
|
|
|
/* Send header packet to the session bus. */
|
2013-05-03 19:59:32 +00:00
|
|
|
std_session_send_df_header(cb_data, LOG_PREFIX);
|
2012-04-22 18:06:19 +00:00
|
|
|
|
zeroplus: Major rework of sample buffer processing
The sample buffer is a still a bit of a mystery, but this should help.
The variables in play:
triggerbar/ramsize_trigger - These two variables added together indicate
how many samples we want captured. ramsize_trigger - triggerbar
indicades how many samples must be captured. The ratio between the two
is determined by capture ratio.
memory_size - This indicates the number of samples in the circular
capture buffer. stop_address, now_address, and trigger_address are
pointers within the zeroplus that wrap based on this size.
now_address - The address that the zeroplus was about to write to when
it finished capturing, and now the address that will be read from when
reads are done from the capture buffer
stop_address - The address that the zeroplus last wrote to when it
completed capture.
trigger_address - The sample address for which the trigger occured.
status - This one is a bit tricky. Some testing has shown that if the
zeroplus has captured memory_size or less samples, the STATUS_READY bit
is set. For all captures generated with more samples than this,
STATUS_READY was cleared. However, boundary conditions are difficult to
test and values such as, memory_size + 1 have not been tested. We use
this to determine if the capture has wrapped through the sample buffer.
More testing is required, but this improves behavior in a number of
cases, specifically capturing sample amounts that are not a power of 2
of the sample buffer size. Before, random data was passed to libsigrok.
Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
2013-12-30 15:12:49 +00:00
|
|
|
/* Check for empty capture */
|
|
|
|
if ((status & STATUS_READY) && !stop_address) {
|
|
|
|
packet.type = SR_DF_END;
|
|
|
|
sr_session_send(cb_data, &packet);
|
|
|
|
return SR_OK;
|
|
|
|
}
|
|
|
|
|
2011-04-16 12:17:51 +00:00
|
|
|
if (!(buf = g_try_malloc(PACKET_SIZE))) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("Packet buffer malloc failed.");
|
2011-04-16 12:17:51 +00:00
|
|
|
return SR_ERR_MALLOC;
|
|
|
|
}
|
|
|
|
|
zeroplus: Major rework of sample buffer processing
The sample buffer is a still a bit of a mystery, but this should help.
The variables in play:
triggerbar/ramsize_trigger - These two variables added together indicate
how many samples we want captured. ramsize_trigger - triggerbar
indicades how many samples must be captured. The ratio between the two
is determined by capture ratio.
memory_size - This indicates the number of samples in the circular
capture buffer. stop_address, now_address, and trigger_address are
pointers within the zeroplus that wrap based on this size.
now_address - The address that the zeroplus was about to write to when
it finished capturing, and now the address that will be read from when
reads are done from the capture buffer
stop_address - The address that the zeroplus last wrote to when it
completed capture.
trigger_address - The sample address for which the trigger occured.
status - This one is a bit tricky. Some testing has shown that if the
zeroplus has captured memory_size or less samples, the STATUS_READY bit
is set. For all captures generated with more samples than this,
STATUS_READY was cleared. However, boundary conditions are difficult to
test and values such as, memory_size + 1 have not been tested. We use
this to determine if the capture has wrapped through the sample buffer.
More testing is required, but this improves behavior in a number of
cases, specifically capturing sample amounts that are not a power of 2
of the sample buffer size. Before, random data was passed to libsigrok.
Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
2013-12-30 15:12:49 +00:00
|
|
|
/* Check if the trigger is in the samples we are throwing away */
|
|
|
|
trigger_now = now_address == trigger_address ||
|
|
|
|
((now_address + 1) % memory_size) == trigger_address;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* STATUS_READY doesn't clear until now_address advances past
|
|
|
|
* addr 0, but for our logic, clear it in that case
|
|
|
|
*/
|
|
|
|
if (!now_address)
|
|
|
|
status &= ~STATUS_READY;
|
|
|
|
|
2013-04-22 13:00:04 +00:00
|
|
|
analyzer_read_start(usb->devhdl);
|
zeroplus: Major rework of sample buffer processing
The sample buffer is a still a bit of a mystery, but this should help.
The variables in play:
triggerbar/ramsize_trigger - These two variables added together indicate
how many samples we want captured. ramsize_trigger - triggerbar
indicades how many samples must be captured. The ratio between the two
is determined by capture ratio.
memory_size - This indicates the number of samples in the circular
capture buffer. stop_address, now_address, and trigger_address are
pointers within the zeroplus that wrap based on this size.
now_address - The address that the zeroplus was about to write to when
it finished capturing, and now the address that will be read from when
reads are done from the capture buffer
stop_address - The address that the zeroplus last wrote to when it
completed capture.
trigger_address - The sample address for which the trigger occured.
status - This one is a bit tricky. Some testing has shown that if the
zeroplus has captured memory_size or less samples, the STATUS_READY bit
is set. For all captures generated with more samples than this,
STATUS_READY was cleared. However, boundary conditions are difficult to
test and values such as, memory_size + 1 have not been tested. We use
this to determine if the capture has wrapped through the sample buffer.
More testing is required, but this improves behavior in a number of
cases, specifically capturing sample amounts that are not a power of 2
of the sample buffer size. Before, random data was passed to libsigrok.
Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
2013-12-30 15:12:49 +00:00
|
|
|
|
|
|
|
/* Calculate how much data to discard */
|
|
|
|
discard = 0;
|
|
|
|
if (status & STATUS_READY) {
|
|
|
|
/*
|
|
|
|
* We haven't wrapped around, we need to throw away data from
|
|
|
|
* our current position to the end of the buffer.
|
|
|
|
* Additionally, the first two samples captured are always
|
|
|
|
* bogus.
|
|
|
|
*/
|
|
|
|
discard += memory_size - now_address + 2;
|
|
|
|
now_address = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we have more samples than we need, discard them */
|
|
|
|
valid_samples = (stop_address - now_address) % memory_size;
|
|
|
|
if (valid_samples > ramsize_trigger + triggerbar) {
|
|
|
|
discard += valid_samples - (ramsize_trigger + triggerbar);
|
|
|
|
now_address += valid_samples - (ramsize_trigger + triggerbar);
|
|
|
|
}
|
|
|
|
|
|
|
|
sr_info("Need to discard %d samples.", discard);
|
|
|
|
|
|
|
|
/* Calculate how far in the trigger is */
|
|
|
|
if (trigger_now)
|
|
|
|
trigger_offset = 0;
|
|
|
|
else
|
|
|
|
trigger_offset = (trigger_address - now_address) % memory_size;
|
|
|
|
|
|
|
|
/* Recalculate the number of samples available */
|
|
|
|
valid_samples = (stop_address - now_address) % memory_size;
|
|
|
|
|
2010-04-15 20:59:43 +00:00
|
|
|
/* Send the incoming transfer to the session bus. */
|
zeroplus: Major rework of sample buffer processing
The sample buffer is a still a bit of a mystery, but this should help.
The variables in play:
triggerbar/ramsize_trigger - These two variables added together indicate
how many samples we want captured. ramsize_trigger - triggerbar
indicades how many samples must be captured. The ratio between the two
is determined by capture ratio.
memory_size - This indicates the number of samples in the circular
capture buffer. stop_address, now_address, and trigger_address are
pointers within the zeroplus that wrap based on this size.
now_address - The address that the zeroplus was about to write to when
it finished capturing, and now the address that will be read from when
reads are done from the capture buffer
stop_address - The address that the zeroplus last wrote to when it
completed capture.
trigger_address - The sample address for which the trigger occured.
status - This one is a bit tricky. Some testing has shown that if the
zeroplus has captured memory_size or less samples, the STATUS_READY bit
is set. For all captures generated with more samples than this,
STATUS_READY was cleared. However, boundary conditions are difficult to
test and values such as, memory_size + 1 have not been tested. We use
this to determine if the capture has wrapped through the sample buffer.
More testing is required, but this improves behavior in a number of
cases, specifically capturing sample amounts that are not a power of 2
of the sample buffer size. Before, random data was passed to libsigrok.
Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
2013-12-30 15:12:49 +00:00
|
|
|
samples_read = 0;
|
2012-11-05 07:06:14 +00:00
|
|
|
for (packet_num = 0; packet_num < n / PACKET_SIZE; packet_num++) {
|
zeroplus: Major rework of sample buffer processing
The sample buffer is a still a bit of a mystery, but this should help.
The variables in play:
triggerbar/ramsize_trigger - These two variables added together indicate
how many samples we want captured. ramsize_trigger - triggerbar
indicades how many samples must be captured. The ratio between the two
is determined by capture ratio.
memory_size - This indicates the number of samples in the circular
capture buffer. stop_address, now_address, and trigger_address are
pointers within the zeroplus that wrap based on this size.
now_address - The address that the zeroplus was about to write to when
it finished capturing, and now the address that will be read from when
reads are done from the capture buffer
stop_address - The address that the zeroplus last wrote to when it
completed capture.
trigger_address - The sample address for which the trigger occured.
status - This one is a bit tricky. Some testing has shown that if the
zeroplus has captured memory_size or less samples, the STATUS_READY bit
is set. For all captures generated with more samples than this,
STATUS_READY was cleared. However, boundary conditions are difficult to
test and values such as, memory_size + 1 have not been tested. We use
this to determine if the capture has wrapped through the sample buffer.
More testing is required, but this improves behavior in a number of
cases, specifically capturing sample amounts that are not a power of 2
of the sample buffer size. Before, random data was passed to libsigrok.
Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
2013-12-30 15:12:49 +00:00
|
|
|
unsigned int len;
|
|
|
|
unsigned int buf_offset;
|
|
|
|
|
2013-04-22 13:00:04 +00:00
|
|
|
res = analyzer_read_data(usb->devhdl, buf, PACKET_SIZE);
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_info("Tried to read %d bytes, actually read %d bytes.",
|
2011-04-14 07:46:53 +00:00
|
|
|
PACKET_SIZE, res);
|
2010-04-02 18:18:27 +00:00
|
|
|
|
zeroplus: Major rework of sample buffer processing
The sample buffer is a still a bit of a mystery, but this should help.
The variables in play:
triggerbar/ramsize_trigger - These two variables added together indicate
how many samples we want captured. ramsize_trigger - triggerbar
indicades how many samples must be captured. The ratio between the two
is determined by capture ratio.
memory_size - This indicates the number of samples in the circular
capture buffer. stop_address, now_address, and trigger_address are
pointers within the zeroplus that wrap based on this size.
now_address - The address that the zeroplus was about to write to when
it finished capturing, and now the address that will be read from when
reads are done from the capture buffer
stop_address - The address that the zeroplus last wrote to when it
completed capture.
trigger_address - The sample address for which the trigger occured.
status - This one is a bit tricky. Some testing has shown that if the
zeroplus has captured memory_size or less samples, the STATUS_READY bit
is set. For all captures generated with more samples than this,
STATUS_READY was cleared. However, boundary conditions are difficult to
test and values such as, memory_size + 1 have not been tested. We use
this to determine if the capture has wrapped through the sample buffer.
More testing is required, but this improves behavior in a number of
cases, specifically capturing sample amounts that are not a power of 2
of the sample buffer size. Before, random data was passed to libsigrok.
Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
2013-12-30 15:12:49 +00:00
|
|
|
if (discard >= PACKET_SIZE / 4) {
|
|
|
|
discard -= PACKET_SIZE / 4;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = PACKET_SIZE - discard * 4;
|
|
|
|
buf_offset = discard * 4;
|
|
|
|
discard = 0;
|
|
|
|
|
|
|
|
/* Check if we've read all the samples */
|
|
|
|
if (samples_read + len / 4 >= valid_samples)
|
|
|
|
len = (valid_samples - samples_read) * 4;
|
|
|
|
if (!len)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (samples_read < trigger_offset &&
|
|
|
|
samples_read + len / 4 > trigger_offset) {
|
|
|
|
/* Send out samples remaining before trigger */
|
|
|
|
packet.type = SR_DF_LOGIC;
|
|
|
|
packet.payload = &logic;
|
|
|
|
logic.length = (trigger_offset - samples_read) * 4;
|
|
|
|
logic.unitsize = 4;
|
|
|
|
logic.data = buf + buf_offset;
|
|
|
|
sr_session_send(cb_data, &packet);
|
|
|
|
len -= logic.length;
|
|
|
|
samples_read += logic.length / 4;
|
|
|
|
buf_offset += logic.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (samples_read == trigger_offset) {
|
|
|
|
/* Send out trigger */
|
|
|
|
packet.type = SR_DF_TRIGGER;
|
|
|
|
packet.payload = NULL;
|
|
|
|
sr_session_send(cb_data, &packet);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send out data (or data after trigger) */
|
2011-01-30 16:58:41 +00:00
|
|
|
packet.type = SR_DF_LOGIC;
|
2011-06-19 12:28:50 +00:00
|
|
|
packet.payload = &logic;
|
zeroplus: Major rework of sample buffer processing
The sample buffer is a still a bit of a mystery, but this should help.
The variables in play:
triggerbar/ramsize_trigger - These two variables added together indicate
how many samples we want captured. ramsize_trigger - triggerbar
indicades how many samples must be captured. The ratio between the two
is determined by capture ratio.
memory_size - This indicates the number of samples in the circular
capture buffer. stop_address, now_address, and trigger_address are
pointers within the zeroplus that wrap based on this size.
now_address - The address that the zeroplus was about to write to when
it finished capturing, and now the address that will be read from when
reads are done from the capture buffer
stop_address - The address that the zeroplus last wrote to when it
completed capture.
trigger_address - The sample address for which the trigger occured.
status - This one is a bit tricky. Some testing has shown that if the
zeroplus has captured memory_size or less samples, the STATUS_READY bit
is set. For all captures generated with more samples than this,
STATUS_READY was cleared. However, boundary conditions are difficult to
test and values such as, memory_size + 1 have not been tested. We use
this to determine if the capture has wrapped through the sample buffer.
More testing is required, but this improves behavior in a number of
cases, specifically capturing sample amounts that are not a power of 2
of the sample buffer size. Before, random data was passed to libsigrok.
Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
2013-12-30 15:12:49 +00:00
|
|
|
logic.length = len;
|
2011-06-19 12:28:50 +00:00
|
|
|
logic.unitsize = 4;
|
zeroplus: Major rework of sample buffer processing
The sample buffer is a still a bit of a mystery, but this should help.
The variables in play:
triggerbar/ramsize_trigger - These two variables added together indicate
how many samples we want captured. ramsize_trigger - triggerbar
indicades how many samples must be captured. The ratio between the two
is determined by capture ratio.
memory_size - This indicates the number of samples in the circular
capture buffer. stop_address, now_address, and trigger_address are
pointers within the zeroplus that wrap based on this size.
now_address - The address that the zeroplus was about to write to when
it finished capturing, and now the address that will be read from when
reads are done from the capture buffer
stop_address - The address that the zeroplus last wrote to when it
completed capture.
trigger_address - The sample address for which the trigger occured.
status - This one is a bit tricky. Some testing has shown that if the
zeroplus has captured memory_size or less samples, the STATUS_READY bit
is set. For all captures generated with more samples than this,
STATUS_READY was cleared. However, boundary conditions are difficult to
test and values such as, memory_size + 1 have not been tested. We use
this to determine if the capture has wrapped through the sample buffer.
More testing is required, but this improves behavior in a number of
cases, specifically capturing sample amounts that are not a power of 2
of the sample buffer size. Before, random data was passed to libsigrok.
Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
2013-12-30 15:12:49 +00:00
|
|
|
logic.data = buf + buf_offset;
|
2012-03-03 08:56:49 +00:00
|
|
|
sr_session_send(cb_data, &packet);
|
zeroplus: Major rework of sample buffer processing
The sample buffer is a still a bit of a mystery, but this should help.
The variables in play:
triggerbar/ramsize_trigger - These two variables added together indicate
how many samples we want captured. ramsize_trigger - triggerbar
indicades how many samples must be captured. The ratio between the two
is determined by capture ratio.
memory_size - This indicates the number of samples in the circular
capture buffer. stop_address, now_address, and trigger_address are
pointers within the zeroplus that wrap based on this size.
now_address - The address that the zeroplus was about to write to when
it finished capturing, and now the address that will be read from when
reads are done from the capture buffer
stop_address - The address that the zeroplus last wrote to when it
completed capture.
trigger_address - The sample address for which the trigger occured.
status - This one is a bit tricky. Some testing has shown that if the
zeroplus has captured memory_size or less samples, the STATUS_READY bit
is set. For all captures generated with more samples than this,
STATUS_READY was cleared. However, boundary conditions are difficult to
test and values such as, memory_size + 1 have not been tested. We use
this to determine if the capture has wrapped through the sample buffer.
More testing is required, but this improves behavior in a number of
cases, specifically capturing sample amounts that are not a power of 2
of the sample buffer size. Before, random data was passed to libsigrok.
Signed-off-by: Russ Dill <Russ.Dill@gmail.com>
2013-12-30 15:12:49 +00:00
|
|
|
samples_read += len / 4;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
2013-04-22 13:00:04 +00:00
|
|
|
analyzer_read_stop(usb->devhdl);
|
2010-04-02 18:18:27 +00:00
|
|
|
g_free(buf);
|
|
|
|
|
2011-01-30 16:58:41 +00:00
|
|
|
packet.type = SR_DF_END;
|
2012-03-03 08:56:49 +00:00
|
|
|
sr_session_send(cb_data, &packet);
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2011-01-29 15:23:12 +00:00
|
|
|
return SR_OK;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
|
2012-03-03 08:56:49 +00:00
|
|
|
/* TODO: This stops acquisition on ALL devices, ignoring dev_index. */
|
2013-05-10 17:37:54 +00:00
|
|
|
static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
|
2010-04-02 18:18:27 +00:00
|
|
|
{
|
2012-08-02 23:01:38 +00:00
|
|
|
struct dev_context *devc;
|
2013-04-22 13:00:04 +00:00
|
|
|
struct sr_usb_dev_inst *usb;
|
|
|
|
struct sr_datafeed_packet packet;
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2011-01-30 16:58:41 +00:00
|
|
|
packet.type = SR_DF_END;
|
2012-03-03 08:56:49 +00:00
|
|
|
sr_session_send(cb_data, &packet);
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2012-08-02 23:01:38 +00:00
|
|
|
if (!(devc = sdi->priv)) {
|
2013-01-28 16:43:04 +00:00
|
|
|
sr_err("%s: sdi->priv was NULL", __func__);
|
2012-02-12 12:31:58 +00:00
|
|
|
return SR_ERR_BUG;
|
2012-01-29 22:06:10 +00:00
|
|
|
}
|
2010-04-02 18:18:27 +00:00
|
|
|
|
2013-04-22 13:00:04 +00:00
|
|
|
usb = sdi->conn;
|
|
|
|
analyzer_reset(usb->devhdl);
|
2010-04-15 20:59:43 +00:00
|
|
|
/* TODO: Need to cancel and free any queued up transfers. */
|
2012-02-12 12:31:58 +00:00
|
|
|
|
|
|
|
return SR_OK;
|
2010-04-02 18:18:27 +00:00
|
|
|
}
|
|
|
|
|
2012-02-28 22:52:30 +00:00
|
|
|
SR_PRIV struct sr_dev_driver zeroplus_logic_cube_driver_info = {
|
2011-04-18 22:14:15 +00:00
|
|
|
.name = "zeroplus-logic-cube",
|
2012-05-30 20:55:03 +00:00
|
|
|
.longname = "ZEROPLUS Logic Cube LAP-C series",
|
2011-04-18 22:14:15 +00:00
|
|
|
.api_version = 1,
|
2013-05-10 17:37:54 +00:00
|
|
|
.init = init,
|
|
|
|
.cleanup = cleanup,
|
|
|
|
.scan = scan,
|
|
|
|
.dev_list = dev_list,
|
2014-02-26 20:37:18 +00:00
|
|
|
.dev_clear = NULL,
|
2013-01-24 18:19:09 +00:00
|
|
|
.config_get = config_get,
|
|
|
|
.config_set = config_set,
|
2013-01-25 01:32:05 +00:00
|
|
|
.config_list = config_list,
|
2013-05-10 17:37:54 +00:00
|
|
|
.dev_open = dev_open,
|
|
|
|
.dev_close = dev_close,
|
|
|
|
.dev_acquisition_start = dev_acquisition_start,
|
|
|
|
.dev_acquisition_stop = dev_acquisition_stop,
|
2012-08-02 23:01:38 +00:00
|
|
|
.priv = NULL,
|
2010-04-02 18:18:27 +00:00
|
|
|
};
|