hantek-6xxx: Initial driver implementation.

Note: This commit is based on the initial implementation by
Christer Ekholm (but stashed into one commit), with some adaptations
(forward porting, coding style and consistency fixes) by Uwe Hermann.
This commit is contained in:
Chriter 2015-09-16 22:18:07 +03:00 committed by Uwe Hermann
parent 6c6bc80a99
commit f2a66a8ee6
4 changed files with 1003 additions and 82 deletions

View File

@ -236,7 +236,7 @@ SR_DRIVER([fx2lafw], [fx2lafw], [libusb])
SR_DRIVER([GMC MH 1x/2x], [gmc-mh-1x-2x], [libserialport]) SR_DRIVER([GMC MH 1x/2x], [gmc-mh-1x-2x], [libserialport])
SR_DRIVER([GW Instek GDS-800], [gwinstek-gds-800], [libserialport]) SR_DRIVER([GW Instek GDS-800], [gwinstek-gds-800], [libserialport])
SR_DRIVER([Hameg HMO], [hameg-hmo], [libserialport]) SR_DRIVER([Hameg HMO], [hameg-hmo], [libserialport])
SR_DRIVER([Hantek 6xxx], [hantek-6xxx]) SR_DRIVER([Hantek 6xxx], [hantek-6xxx], [libusb])
SR_DRIVER([Hantek DSO], [hantek-dso], [libusb]) SR_DRIVER([Hantek DSO], [hantek-dso], [libusb])
SR_DRIVER([Hung-Chang DSO-2100], [hung-chang-dso-2100], [libieee1284]) SR_DRIVER([Hung-Chang DSO-2100], [hung-chang-dso-2100], [libieee1284])
SR_DRIVER([Ikalogic Scanalogic-2], [ikalogic-scanalogic2], [libusb]) SR_DRIVER([Ikalogic Scanalogic-2], [ikalogic-scanalogic2], [libusb])

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the libsigrok project. * This file is part of the libsigrok project.
* *
* Copyright (C) 2015 Chriter <christerekholm@gmail.com> * Copyright (C) 2015 Christer Ekholm <christerekholm@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -20,8 +20,138 @@
#include <config.h> #include <config.h>
#include "protocol.h" #include "protocol.h"
/* Max time in ms before we want to check on USB events */
#define TICK 200
#define RANGE(ch) (((float)vdivs[devc->voltage[ch]][0] / vdivs[devc->voltage[ch]][1]) * VDIV_MULTIPLIER)
static const uint32_t scanopts[] = {
SR_CONF_CONN,
};
static const uint32_t drvopts[] = {
SR_CONF_OSCILLOSCOPE,
};
static const uint32_t devopts[] = {
SR_CONF_CONN | SR_CONF_GET,
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_NUM_VDIV | SR_CONF_GET,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
};
static const uint32_t devopts_cg[] = {
SR_CONF_VDIV | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
};
static const char *channel_names[] = {
"CH1", "CH2",
};
static const struct hantek_6xxx_profile dev_profiles[] = {
{
0x04b4, 0x6022, 0x04b5, 0x6022,
"Hantek", "6022BE", "hantek-6022be.fw",
},
ALL_ZERO
};
static const uint64_t samplerates[] = {
SAMPLERATE_VALUES
};
static const uint64_t vdivs[][2] = {
VDIV_VALUES
};
SR_PRIV struct sr_dev_driver hantek_6xxx_driver_info; SR_PRIV struct sr_dev_driver hantek_6xxx_driver_info;
static int read_channel(const struct sr_dev_inst *sdi, uint32_t amount);
static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
static struct sr_dev_inst *hantek_6xxx_dev_new(const struct hantek_6xxx_profile *prof)
{
struct sr_dev_inst *sdi;
struct sr_channel *ch;
struct sr_channel_group *cg;
struct drv_context *drvc;
struct dev_context *devc;
unsigned int i;
sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi->status = SR_ST_INITIALIZING;
sdi->vendor = g_strdup(prof->vendor);
sdi->model = g_strdup(prof->model);
sdi->driver = &hantek_6xxx_driver_info;
for (i = 0; i < ARRAY_SIZE(channel_names); i++) {
ch = sr_channel_new(sdi, i, SR_CHANNEL_ANALOG, TRUE, channel_names[i]);
cg = g_malloc0(sizeof(struct sr_channel_group));
cg->name = g_strdup(channel_names[i]);
cg->channels = g_slist_append(cg->channels, ch);
sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
}
devc = g_malloc0(sizeof(struct dev_context));
for (i = 0; i < NUM_CHANNELS; i++) {
devc->ch_enabled[i] = TRUE;
devc->voltage[i] = DEFAULT_VOLTAGE;
}
devc->sample_buf = NULL;
devc->sample_buf_write = 0;
devc->sample_buf_size = 0;
devc->profile = prof;
devc->dev_state = IDLE;
devc->samplerate = DEFAULT_SAMPLERATE;
sdi->priv = devc;
drvc = sdi->driver->context;
drvc->instances = g_slist_append(drvc->instances, sdi);
return sdi;
}
static int configure_channels(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
const GSList *l;
int p;
struct sr_channel *ch;
devc = sdi->priv;
g_slist_free(devc->enabled_channels);
devc->enabled_channels = NULL;
memset(devc->ch_enabled, 0, sizeof(devc->ch_enabled));
for (l = sdi->channels, p = 0; l; l = l->next, p++) {
ch = l->data;
if (p < NUM_CHANNELS) {
devc->ch_enabled[p] = ch->enabled;
devc->enabled_channels = g_slist_append(devc->enabled_channels, ch);
}
}
return SR_OK;
}
static void clear_dev_context(void *priv)
{
struct dev_context *devc;
devc = priv;
g_slist_free(devc->enabled_channels);
}
static int dev_clear(const struct sr_dev_driver *di)
{
return std_dev_clear(di, clear_dev_context);
}
static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx) static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx)
{ {
return std_init(sr_ctx, di, LOG_PREFIX); return std_init(sr_ctx, di, LOG_PREFIX);
@ -30,16 +160,102 @@ static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx)
static GSList *scan(struct sr_dev_driver *di, GSList *options) static GSList *scan(struct sr_dev_driver *di, GSList *options)
{ {
struct drv_context *drvc; struct drv_context *drvc;
GSList *devices; struct dev_context *devc;
struct sr_dev_inst *sdi;
struct sr_usb_dev_inst *usb;
struct sr_config *src;
const struct hantek_6xxx_profile *prof;
GSList *l, *devices, *conn_devices;
struct libusb_device_descriptor des;
libusb_device **devlist;
int i, j;
const char *conn;
char connection_id[64];
(void)options;
devices = NULL;
drvc = di->context; drvc = di->context;
drvc->instances = NULL;
/* TODO: scan for devices, either based on a SR_CONF_CONN option devices = 0;
* or on a USB scan. */
conn = NULL;
for (l = options; l; l = l->next) {
src = l->data;
if (src->key == 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;
/* Find all Hantek 60xx devices and upload firmware to all of them. */
libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
for (i = 0; devlist[i]; i++) {
if (conn) {
usb = NULL;
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;
}
if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
sr_err("Failed to get device descriptor: %s.",
libusb_error_name(ret));
continue;
}
usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
prof = NULL;
for (j = 0; j < (int)ARRAY_SIZE(dev_profiles); j++) {
if (des.idVendor == dev_profiles[j].orig_vid
&& des.idProduct == dev_profiles[j].orig_pid) {
/* Device matches the pre-firmware profile. */
prof = &dev_profiles[j];
sr_dbg("Found a %s %s.", prof->vendor, prof->model);
sdi = hantek_6xxx_dev_new(prof);
sdi->connection_id = g_strdup(connection_id);
devices = g_slist_append(devices, sdi);
devc = sdi->priv;
if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i],
USB_CONFIGURATION, prof->firmware) == SR_OK)
/* Remember when the firmware on this device was updated. */
devc->fw_updated = g_get_monotonic_time();
else
sr_err("Firmware upload failed.");
/* Dummy USB address of 0xff will get overwritten later. */
sdi->conn = sr_usb_dev_inst_new(
libusb_get_bus_number(devlist[i]), 0xff, NULL);
break;
} else if (des.idVendor == dev_profiles[j].fw_vid
&& des.idProduct == dev_profiles[j].fw_pid) {
/* Device matches the post-firmware profile. */
prof = &dev_profiles[j];
sr_dbg("Found a %s %s.", prof->vendor, prof->model);
sdi = hantek_6xxx_dev_new(prof);
sdi->connection_id = g_strdup(connection_id);
sdi->status = SR_ST_INACTIVE;
devices = g_slist_append(devices, sdi);
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);
break;
}
}
if (!prof)
/* Not a supported VID/PID. */
continue;
}
libusb_free_device_list(devlist, 1);
return devices; return devices;
} }
@ -49,77 +265,185 @@ static GSList *dev_list(const struct sr_dev_driver *di)
return ((struct drv_context *)(di->context))->instances; return ((struct drv_context *)(di->context))->instances;
} }
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) static int dev_open(struct sr_dev_inst *sdi)
{ {
(void)sdi; struct dev_context *devc;
struct sr_usb_dev_inst *usb;
int64_t timediff_us, timediff_ms;
int err;
/* TODO: get handle from sdi->conn and open it. */ devc = sdi->priv;
usb = sdi->conn;
sdi->status = SR_ST_ACTIVE; /*
* If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS
* for the FX2 to renumerate.
*/
err = SR_ERR;
if (devc->fw_updated > 0) {
sr_info("Waiting for device to reset.");
/* Takes >= 300ms for the FX2 to be gone from the USB bus. */
g_usleep(300 * 1000);
timediff_ms = 0;
while (timediff_ms < MAX_RENUM_DELAY_MS) {
if ((err = hantek_6xxx_open(sdi)) == SR_OK)
break;
g_usleep(100 * 1000);
timediff_us = g_get_monotonic_time() - devc->fw_updated;
timediff_ms = timediff_us / 1000;
sr_spew("Waited %" PRIi64 " ms.", timediff_ms);
}
if (timediff_ms < MAX_RENUM_DELAY_MS)
sr_info("Device came back after %"PRIu64" ms.", timediff_ms);
} else {
err = hantek_6xxx_open(sdi);
}
if (err != SR_OK) {
sr_err("Unable to open device.");
return SR_ERR;
}
err = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
if (err != 0) {
sr_err("Unable to claim interface: %s.",
libusb_error_name(err));
return SR_ERR;
}
return SR_OK; return SR_OK;
} }
static int dev_close(struct sr_dev_inst *sdi) static int dev_close(struct sr_dev_inst *sdi)
{ {
(void)sdi; hantek_6xxx_close(sdi);
/* TODO: get handle from sdi->conn and close it. */
sdi->status = SR_ST_INACTIVE;
return SR_OK; return SR_OK;
} }
static int cleanup(const struct sr_dev_driver *di) static int cleanup(const struct sr_dev_driver *di)
{ {
dev_clear(di); return dev_clear(di);
/* TODO: free other driver resources, if any. */
return SR_OK;
} }
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
int ret; struct dev_context *devc;
struct sr_usb_dev_inst *usb;
char str[128];
const uint64_t *vdiv;
int ch_idx;
(void)sdi;
(void)data;
(void)cg;
ret = SR_OK;
switch (key) { switch (key) {
/* TODO */ case SR_CONF_NUM_VDIV:
default: *data = g_variant_new_int32(ARRAY_SIZE(vdivs));
return SR_ERR_NA; break;
} }
return ret; if (!sdi)
return SR_ERR_ARG;
devc = sdi->priv;
if (!cg) {
switch (key) {
case SR_CONF_SAMPLERATE:
*data = g_variant_new_uint64(devc->samplerate);
break;
case SR_CONF_LIMIT_MSEC:
*data = g_variant_new_uint64(devc->limit_msec);
break;
case SR_CONF_LIMIT_SAMPLES:
*data = g_variant_new_uint64(devc->limit_samples);
break;
case SR_CONF_CONN:
if (!sdi->conn)
return SR_ERR_ARG;
usb = sdi->conn;
if (usb->address == 255)
/* Device still needs to re-enumerate after firmware
* upload, so we don't know its (future) address. */
return SR_ERR;
snprintf(str, 128, "%d.%d", usb->bus, usb->address);
*data = g_variant_new_string(str);
break;
default:
return SR_ERR_NA;
}
} else {
if (sdi->channel_groups->data == cg)
ch_idx = 0;
else if (sdi->channel_groups->next->data == cg)
ch_idx = 1;
else
return SR_ERR_ARG;
switch (key) {
case SR_CONF_VDIV:
vdiv = vdivs[devc->voltage[ch_idx]];
*data = g_variant_new("(tt)", vdiv[0], vdiv[1]);
break;
}
}
return SR_OK;
} }
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi, static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
int ret; struct dev_context *devc;
uint64_t p, q;
(void)data; int tmp_int, ch_idx, ret;
(void)cg; unsigned int i;
if (sdi->status != SR_ST_ACTIVE) if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED; return SR_ERR_DEV_CLOSED;
ret = SR_OK; ret = SR_OK;
switch (key) { devc = sdi->priv;
/* TODO */ if (!cg) {
default: switch (key) {
ret = SR_ERR_NA; case SR_CONF_SAMPLERATE:
devc->samplerate = g_variant_get_uint64(data);
hantek_6xxx_update_samplerate(sdi);
break;
case SR_CONF_LIMIT_MSEC:
devc->limit_msec = g_variant_get_uint64(data);
break;
case SR_CONF_LIMIT_SAMPLES:
devc->limit_samples = g_variant_get_uint64(data);
break;
default:
ret = SR_ERR_NA;
break;
}
} else {
if (sdi->channel_groups->data == cg)
ch_idx = 0;
else if (sdi->channel_groups->next->data == cg)
ch_idx = 1;
else
return SR_ERR_ARG;
switch (key) {
case SR_CONF_VDIV:
g_variant_get(data, "(tt)", &p, &q);
tmp_int = -1;
for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
if (vdivs[i][0] == p && vdivs[i][1] == q) {
tmp_int = i;
break;
}
}
if (tmp_int >= 0) {
devc->voltage[ch_idx] = tmp_int;
hantek_6xxx_update_vdiv(sdi);
} else
ret = SR_ERR_ARG;
break;
default:
ret = SR_ERR_NA;
break;
}
} }
return ret; return ret;
@ -128,45 +452,349 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
int ret; GVariant *tuple, *rational[2];
GVariantBuilder gvb;
unsigned int i;
GVariant *gvar;
(void)sdi; if (key == SR_CONF_SCAN_OPTIONS) {
(void)data; *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
(void)cg; scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
return SR_OK;
ret = SR_OK; } else if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
switch (key) { *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
/* TODO */ drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
default: return SR_OK;
return SR_ERR_NA;
} }
if (!sdi)
return SR_ERR_ARG;
if (!cg) {
switch (key) {
case SR_CONF_DEVICE_OPTIONS:
*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;
}
} else {
switch (key) {
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(uint32_t));
break;
case SR_CONF_VDIV:
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
rational[0] = g_variant_new_uint64(vdivs[i][0]);
rational[1] = g_variant_new_uint64(vdivs[i][1]);
tuple = g_variant_new_tuple(rational, 2);
g_variant_builder_add_value(&gvb, tuple);
}
*data = g_variant_builder_end(&gvb);
break;
default:
return SR_ERR_NA;
}
}
return SR_OK;
}
/* Minimise data amount for limit_samples and limit_msec limits. */
static uint32_t data_amount(const struct sr_dev_inst *sdi)
{
struct dev_context *devc = sdi->priv;
uint32_t data_left;
int32_t time_left;
if (devc->limit_msec) {
time_left = devc->limit_msec - (g_get_monotonic_time() - devc->aq_started) / 1000;
data_left = devc->samplerate * MAX(time_left, 0) * NUM_CHANNELS / 1000;
} else if (devc->limit_samples) {
data_left = (devc->limit_samples - devc->samp_received) * NUM_CHANNELS;
} else {
data_left = devc->samplerate * NUM_CHANNELS;
}
data_left += MIN_PACKET_SIZE; /* Driver does not handle small buffers. */
sr_spew("data_amount %u", data_left);
return data_left;
}
static void send_chunk(struct sr_dev_inst *sdi, unsigned char *buf,
int num_samples)
{
struct sr_datafeed_packet packet;
struct sr_datafeed_analog_old analog;
struct dev_context *devc = sdi->priv;
int num_channels, data_offset, i;
const float ch1_bit = RANGE(0) / 255;
const float ch2_bit = RANGE(1) / 255;
const float ch1_center = RANGE(0) / 2;
const float ch2_center = RANGE(1) / 2;
const gboolean ch1_ena = !!devc->ch_enabled[0];
const gboolean ch2_ena = !!devc->ch_enabled[1];
num_channels = (ch1_ena && ch2_ena) ? 2 : 1;
packet.type = SR_DF_ANALOG_OLD;
packet.payload = &analog;
analog.channels = devc->enabled_channels;
analog.num_samples = num_samples;
analog.mq = SR_MQ_VOLTAGE;
analog.unit = SR_UNIT_VOLT;
analog.mqflags = 0;
analog.data = g_try_malloc(analog.num_samples * sizeof(float) * num_channels);
if (!analog.data) {
sr_err("Analog data buffer malloc failed.");
devc->dev_state = STOPPING;
return;
}
data_offset = 0;
for (i = 0; i < num_samples; i++) {
/*
* The device always sends data for both channels. If a channel
* is disabled, it contains a copy of the enabled channel's
* data. However, we only send the requested channels to
* the bus.
*
* Voltage values are encoded as a value 0-255, where the
* value is a point in the range represented by the vdiv
* setting. There are 10 vertical divs, so e.g. 500mV/div
* represents 5V peak-to-peak where 0 = -2.5V and 255 = +2.5V.
*/
if (ch1_ena)
analog.data[data_offset++] = (ch1_bit * *(buf + i * 2) - ch1_center);
if (ch2_ena)
analog.data[data_offset++] = (ch2_bit * *(buf + i * 2 + 1) - ch2_center);
}
sr_session_send(devc->cb_data, &packet);
g_free(analog.data);
}
static void send_data(struct sr_dev_inst *sdi, struct libusb_transfer *buf[], uint64_t samples)
{
int i = 0;
uint64_t send = 0;
uint32_t chunk;
while (send < samples) {
chunk = MIN(samples - send, (uint64_t)(buf[i]->actual_length / NUM_CHANNELS));
send += chunk;
send_chunk(sdi, buf[i]->buffer, chunk);
/*
* Everything in this transfer was either copied to the buffer
* or sent to the session bus.
*/
g_free(buf[i]->buffer);
libusb_free_transfer(buf[i]);
i++;
}
}
/*
* Called by libusb (as triggered by handle_event()) when a transfer comes in.
* Only channel data comes in asynchronously, and all transfers for this are
* queued up beforehand, so this just needs to chuck the incoming data onto
* the libsigrok session bus.
*/
static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer)
{
struct sr_dev_inst *sdi;
struct dev_context *devc;
sdi = transfer->user_data;
devc = sdi->priv;
if (devc->dev_state == FLUSH) {
devc->dev_state = CAPTURE;
devc->aq_started = g_get_monotonic_time();
read_channel(sdi, data_amount(sdi));
return;
}
if (devc->dev_state != CAPTURE)
return;
if (!devc->sample_buf) {
devc->sample_buf_size = 10;
devc->sample_buf = g_try_malloc(devc->sample_buf_size * sizeof(transfer));
devc->sample_buf_write = 0;
}
if (devc->sample_buf_write >= devc->sample_buf_size) {
devc->sample_buf_size += 10;
devc->sample_buf = g_try_realloc(devc->sample_buf,
devc->sample_buf_size * sizeof(transfer));
if (!devc->sample_buf) {
sr_err("Sample buffer malloc failed.");
devc->dev_state = STOPPING;
return;
}
}
devc->sample_buf[devc->sample_buf_write++] = transfer;
devc->samp_received = transfer->actual_length / NUM_CHANNELS;
sr_spew("receive_transfer(): calculated samplerate == %" PRIu64 "ks/s",
(uint64_t)(transfer->actual_length * 1000 /
(g_get_monotonic_time() - devc->read_start_ts + 1) /
NUM_CHANNELS));
sr_spew("receive_transfer(): status %s received %d bytes.",
libusb_error_name(transfer->status), transfer->actual_length);
if (transfer->actual_length == 0)
/* Nothing to send to the bus. */
return;
if (devc->limit_samples && devc->samp_received >= devc->limit_samples) {
sr_info("Requested number of samples reached, stopping. %"
PRIu64 " <= %" PRIu64, devc->limit_samples,
devc->samp_received);
send_data(sdi, devc->sample_buf, devc->limit_samples);
sdi->driver->dev_acquisition_stop(sdi, NULL);
} else if (devc->limit_msec && (g_get_monotonic_time() -
devc->aq_started) / 1000 >= devc->limit_msec) {
sr_info("Requested time limit reached, stopping. %d <= %d",
(uint32_t)devc->limit_msec,
(uint32_t)(g_get_monotonic_time() - devc->aq_started) / 1000);
send_data(sdi, devc->sample_buf, devc->samp_received);
g_free(devc->sample_buf);
devc->sample_buf = NULL;
sdi->driver->dev_acquisition_stop(sdi, NULL);
} else {
read_channel(sdi, data_amount(sdi));
}
}
static int read_channel(const struct sr_dev_inst *sdi, uint32_t amount)
{
int ret;
struct dev_context *devc;
devc = sdi->priv;
amount = MIN(amount, MAX_PACKET_SIZE);
ret = hantek_6xxx_get_channeldata(sdi, receive_transfer, amount);
devc->read_start_ts = g_get_monotonic_time();
devc->read_data_amount = amount;
return ret; return ret;
} }
static int dev_acquisition_start(const struct sr_dev_inst *sdi, static int handle_event(int fd, int revents, void *cb_data)
void *cb_data)
{ {
(void)sdi; const struct sr_dev_inst *sdi;
(void)cb_data; struct sr_datafeed_packet packet;
struct timeval tv;
struct sr_dev_driver *di;
struct dev_context *devc;
struct drv_context *drvc;
(void)fd;
(void)revents;
sdi = cb_data;
di = sdi->driver;
drvc = di->context;
devc = sdi->priv;
/* Always handle pending libusb events. */
tv.tv_sec = tv.tv_usec = 0;
libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
if (devc->dev_state == STOPPING) {
/* We've been told to wind up the acquisition. */
sr_dbg("Stopping acquisition.");
hantek_6xxx_stop_data_collecting(sdi);
/*
* TODO: Doesn't really cancel pending transfers so they might
* come in after SR_DF_END is sent.
*/
usb_source_remove(sdi->session, drvc->sr_ctx);
packet.type = SR_DF_END;
packet.payload = NULL;
sr_session_send(sdi, &packet);
devc->dev_state = IDLE;
return TRUE;
}
return TRUE;
}
static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
{
struct dev_context *devc;
struct sr_dev_driver *di = sdi->driver;
struct drv_context *drvc = di->context;
if (sdi->status != SR_ST_ACTIVE) if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED; return SR_ERR_DEV_CLOSED;
/* TODO: configure hardware, reset acquisition state, set up devc = sdi->priv;
* callbacks and send header packet. */ devc->cb_data = cb_data;
if (configure_channels(sdi) != SR_OK) {
sr_err("Failed to configure channels.");
return SR_ERR;
}
if (hantek_6xxx_init(sdi) != SR_OK)
return SR_ERR;
/* Send header packet to the session bus. */
std_session_send_df_header(cb_data, LOG_PREFIX);
devc->samp_received = 0;
devc->dev_state = FLUSH;
usb_source_add(sdi->session, drvc->sr_ctx, TICK,
handle_event, (void *)sdi);
hantek_6xxx_start_data_collecting(sdi);
read_channel(sdi, FLUSH_PACKET_SIZE);
return SR_OK; return SR_OK;
} }
static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
{ {
struct dev_context *devc;
(void)cb_data; (void)cb_data;
if (sdi->status != SR_ST_ACTIVE) if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED; return SR_ERR;
/* TODO: stop acquisition. */ devc = sdi->priv;
devc->dev_state = STOPPING;
g_free(devc->sample_buf); devc->sample_buf = NULL;
return SR_OK; return SR_OK;
} }

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the libsigrok project. * This file is part of the libsigrok project.
* *
* Copyright (C) 2015 Chriter <christerekholm@gmail.com> * Copyright (C) 2015 Christer Ekholm <christerekholm@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -20,22 +20,221 @@
#include <config.h> #include <config.h>
#include "protocol.h" #include "protocol.h"
SR_PRIV int hantek_6xxx_receive_data(int fd, int revents, void *cb_data) SR_PRIV int hantek_6xxx_open(struct sr_dev_inst *sdi)
{ {
const struct sr_dev_inst *sdi;
struct dev_context *devc; struct dev_context *devc;
struct drv_context *drvc = sdi->driver->context;
struct sr_usb_dev_inst *usb;
struct libusb_device_descriptor des;
libusb_device **devlist;
int err, i;
char connection_id[64];
(void)fd; devc = sdi->priv;
usb = sdi->conn;
if (!(sdi = cb_data)) if (sdi->status == SR_ST_ACTIVE)
return TRUE; /* Already in use. */
return SR_ERR;
if (!(devc = sdi->priv)) libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
return TRUE; for (i = 0; devlist[i]; i++) {
if ((err = libusb_get_device_descriptor(devlist[i], &des))) {
sr_err("Failed to get device descriptor: %s.",
libusb_error_name(err));
continue;
}
if (revents == G_IO_IN) { if (des.idVendor != devc->profile->fw_vid
/* TODO */ || des.idProduct != devc->profile->fw_pid)
continue;
if ((sdi->status == SR_ST_INITIALIZING) ||
(sdi->status == SR_ST_INACTIVE)) {
/*
* Check device by its physical USB bus/port address.
*/
usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
if (strcmp(sdi->connection_id, connection_id))
/* This is not the one. */
continue;
}
if (!(err = libusb_open(devlist[i], &usb->devhdl))) {
if (usb->address == 0xff) {
/*
* First time we touch this device after firmware upload,
* so we don't know the address yet.
*/
usb->address = libusb_get_device_address(devlist[i]);
}
sdi->status = SR_ST_ACTIVE;
sr_info("Opened device on %d.%d (logical) / "
"%s (physical) interface %d.",
usb->bus, usb->address,
sdi->connection_id, USB_INTERFACE);
} else {
sr_err("Failed to open device: %s.",
libusb_error_name(err));
}
/* If we made it here, we handled the device (somehow). */
break;
} }
return TRUE; libusb_free_device_list(devlist, 1);
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR;
return SR_OK;
}
SR_PRIV void hantek_6xxx_close(struct sr_dev_inst *sdi)
{
struct sr_usb_dev_inst *usb;
usb = sdi->conn;
if (!usb->devhdl)
return;
sr_info("Closing device on %d.%d (logical) / %s (physical) interface %d.",
usb->bus, usb->address, sdi->connection_id, USB_INTERFACE);
libusb_release_interface(usb->devhdl, USB_INTERFACE);
libusb_close(usb->devhdl);
usb->devhdl = NULL;
sdi->status = SR_ST_INACTIVE;
}
SR_PRIV int hantek_6xxx_get_channeldata(const struct sr_dev_inst *sdi,
libusb_transfer_cb_fn cb, uint32_t data_amount)
{
struct sr_usb_dev_inst *usb;
struct libusb_transfer *transfer;
int ret;
unsigned char *buf;
sr_dbg("Request channel data.");
usb = sdi->conn;
if (!(buf = g_try_malloc(data_amount))) {
sr_err("Failed to malloc USB endpoint buffer.");
return SR_ERR_MALLOC;
}
transfer = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(transfer, usb->devhdl, HANTEK_EP_IN, buf,
data_amount, cb, (void *)sdi, 4000);
if ((ret = libusb_submit_transfer(transfer)) != 0) {
sr_err("Failed to submit transfer: %s.",
libusb_error_name(ret));
/* TODO: Free them all. */
libusb_free_transfer(transfer);
g_free(buf);
return SR_ERR;
}
return SR_OK;
}
static uint8_t samplerate_to_reg(uint64_t samplerate)
{
const uint64_t samplerate_values[] = {SAMPLERATE_VALUES};
const uint8_t samplerate_regs[] = {SAMPLERATE_REGS};
uint32_t i;
for (i = 0; i < ARRAY_SIZE(samplerate_values); i++) {
if (samplerate_values[i] == samplerate)
return samplerate_regs[i];
}
sr_err("Failed to convert samplerate: %" PRIu64 ".", samplerate);
return samplerate_regs[ARRAY_SIZE(samplerate_values) - 1];
}
static uint8_t voltage_to_reg(uint8_t state)
{
const uint8_t vdiv_reg[] = {VDIV_REG};
if (state < ARRAY_SIZE(vdiv_reg)) {
return vdiv_reg[state];
} else {
sr_err("Failed to convert vdiv: %d.", state);
return vdiv_reg[ARRAY_SIZE(vdiv_reg) - 1];
}
}
static int write_control(const struct sr_dev_inst *sdi,
enum control_requests reg, uint8_t value)
{
struct sr_usb_dev_inst *usb = sdi->conn;
int ret;
sr_spew("hantek_6xxx_write_control: 0x%x 0x%x", reg, value);
if ((ret = libusb_control_transfer(usb->devhdl,
LIBUSB_REQUEST_TYPE_VENDOR, (uint8_t)reg,
0, 0, &value, 1, 100)) <= 0) {
sr_err("Failed to control transfer: 0x%x: %s.", reg,
libusb_error_name(ret));
return ret;
}
return 0;
}
SR_PRIV int hantek_6xxx_start_data_collecting(const struct sr_dev_inst *sdi)
{
sr_dbg("trigger");
return write_control(sdi, TRIGGER_REG, 1);
}
SR_PRIV int hantek_6xxx_stop_data_collecting(const struct sr_dev_inst *sdi)
{
return write_control(sdi, TRIGGER_REG, 0);
}
SR_PRIV int hantek_6xxx_update_samplerate(const struct sr_dev_inst *sdi)
{
struct dev_context *devc = sdi->priv;
sr_dbg("update samplerate %d", samplerate_to_reg(devc->samplerate));
return write_control(sdi, SAMPLERATE_REG, samplerate_to_reg(devc->samplerate));
}
SR_PRIV int hantek_6xxx_update_vdiv(const struct sr_dev_inst *sdi)
{
struct dev_context *devc = sdi->priv;
int ret1, ret2;
sr_dbg("update vdiv %d %d", voltage_to_reg(devc->voltage[0]),
voltage_to_reg(devc->voltage[1]));
ret1 = write_control(sdi, VDIV_CH1_REG, voltage_to_reg(devc->voltage[0]));
ret2 = write_control(sdi, VDIV_CH2_REG, voltage_to_reg(devc->voltage[1]));
return MIN(ret1, ret2);
}
SR_PRIV int hantek_6xxx_update_channels(const struct sr_dev_inst *sdi)
{
struct dev_context *devc = sdi->priv;
uint8_t chan = devc->ch_enabled[1] ? 2 : 1;
sr_dbg("update channels amount %d", chan);
return write_control(sdi, CHANNELS_REG, chan);
}
SR_PRIV int hantek_6xxx_init(const struct sr_dev_inst *sdi)
{
sr_dbg("Initializing");
hantek_6xxx_update_samplerate(sdi);
hantek_6xxx_update_vdiv(sdi);
// hantek_6xxx_update_channels(sdi); /* Only 2 channel mode supported. */
return SR_OK;
} }

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the libsigrok project. * This file is part of the libsigrok project.
* *
* Copyright (C) 2015 Chriter <christerekholm@gmail.com> * Copyright (C) 2015 Christer Ekholm <christerekholm@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -21,24 +21,118 @@
#define LIBSIGROK_HARDWARE_HANTEK_6XXX_PROTOCOL_H #define LIBSIGROK_HARDWARE_HANTEK_6XXX_PROTOCOL_H
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include <glib.h> #include <glib.h>
#include <libsigrok/libsigrok.h> #include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h" #include "libsigrok-internal.h"
#define LOG_PREFIX "hantek-6xxx" #define LOG_PREFIX "hantek-6xxx"
/** Private, per-device-instance driver context. */ #define MAX_RENUM_DELAY_MS 3000
struct dev_context {
/* Model-specific information */
/* Acquisition settings */ #define DEFAULT_VOLTAGE 2
#define DEFAULT_SAMPLERATE SR_MHZ(8)
/* Operational state */ #define NUM_CHANNELS 2
/* Temporary state across callbacks */ #define SAMPLERATE_VALUES \
SR_MHZ(48), SR_MHZ(30), SR_MHZ(24), \
SR_MHZ(16), SR_MHZ(8), SR_MHZ(4), \
SR_MHZ(1), SR_KHZ(500), SR_KHZ(200), \
SR_KHZ(100),
#define SAMPLERATE_REGS \
48, 30, 24, 16, 8, 4, 1, 50, 20, 10,
#define VDIV_VALUES \
{ 100, 1000 }, \
{ 250, 1000 }, \
{ 500, 1000 }, \
{ 1, 1 },
#define VDIV_REG \
10, 5, 2, 1,
#define VDIV_MULTIPLIER 10
/* Weird flushing needed for filtering glitch away. */
#define FLUSH_PACKET_SIZE 2600
#define MIN_PACKET_SIZE 600
#define MAX_PACKET_SIZE (12 * 1024 * 1024)
#define HANTEK_EP_IN 0x86
#define USB_INTERFACE 0
#define USB_CONFIGURATION 1
enum control_requests {
VDIV_CH1_REG = 0xe0,
VDIV_CH2_REG = 0xe1,
SAMPLERATE_REG = 0xe2,
TRIGGER_REG = 0xe3,
CHANNELS_REG = 0xe4,
}; };
SR_PRIV int hantek_6xxx_receive_data(int fd, int revents, void *cb_data); enum states {
IDLE,
FLUSH,
CAPTURE,
STOPPING,
};
struct hantek_6xxx_profile {
/* VID/PID after cold boot */
uint16_t orig_vid;
uint16_t orig_pid;
/* VID/PID after firmware upload */
uint16_t fw_vid;
uint16_t fw_pid;
const char *vendor;
const char *model;
const char *firmware;
};
struct dev_context {
const struct hantek_6xxx_profile *profile;
void *cb_data;
GSList *enabled_channels;
/*
* We can't keep track of an FX2-based device after upgrading
* the firmware (it re-enumerates into a different device address
* after the upgrade) this is like a global lock. No device will open
* until a proper delay after the last device was upgraded.
*/
int64_t fw_updated;
int dev_state;
uint64_t samp_received;
uint64_t aq_started;
uint64_t read_start_ts;
uint32_t read_data_amount;
struct libusb_transfer **sample_buf;
uint32_t sample_buf_write;
uint32_t sample_buf_size;
gboolean ch_enabled[NUM_CHANNELS];
int voltage[NUM_CHANNELS];
uint64_t samplerate;
uint64_t limit_msec;
uint64_t limit_samples;
};
SR_PRIV int hantek_6xxx_open(struct sr_dev_inst *sdi);
SR_PRIV void hantek_6xxx_close(struct sr_dev_inst *sdi);
SR_PRIV int hantek_6xxx_get_channeldata(const struct sr_dev_inst *sdi,
libusb_transfer_cb_fn cb, uint32_t data_amount);
SR_PRIV int hantek_6xxx_start_data_collecting(const struct sr_dev_inst *sdi);
SR_PRIV int hantek_6xxx_stop_data_collecting(const struct sr_dev_inst *sdi);
SR_PRIV int hantek_6xxx_update_samplerate(const struct sr_dev_inst *sdi);
SR_PRIV int hantek_6xxx_update_vdiv(const struct sr_dev_inst *sdi);
SR_PRIV int hantek_6xxx_update_channels(const struct sr_dev_inst *sdi);
SR_PRIV int hantek_6xxx_init(const struct sr_dev_inst *sdi);
#endif #endif