nexus-osciprime: basic scanning functionality

Unfortunately the device doesn't have an EEPROM on board at all, and so
initially enumerates with the default Cypress FX2 VID:PID (04b4:8613).
Since we already support using plain FX2* as basic logic analyzers using
the fx2lafw firmware, we cannot support that same VID:PID for the
OsciPrime. Therefore a USB conn is required for the initial scan.

However, once the firmware is uploaded the device re-enumerates as
04b4:1004, which we do detect for scanning automatically.

Thus, the OsciPrime driver requires one scan with conn parameter to get
the firmware uploaded, but it will then keep working until powered off.
This commit is contained in:
Bert Vermeulen 2012-12-25 19:09:12 +01:00
parent 35a078bce5
commit 523dfc2497
3 changed files with 161 additions and 11 deletions

View File

@ -19,6 +19,8 @@
if HW_NEXUS_OSCIPRIME
AM_CPPFLAGS = -DFIRMWARE_DIR='"$(FIRMWARE_DIR)"'
# Local lib, this is NOT meant to be installed!
noinst_LTLIBRARIES = libsigrok_hw_nexus_osciprime.la

View File

@ -17,13 +17,98 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <glib.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
#include "protocol.h"
#define OSCI_VENDOR "Nexus Computing"
#define OSCI_MODEL "OsciPrime"
#define OSCI_VERSION "1.0"
#define OSCI_FIRMWARE FIRMWARE_DIR "/nexus-osciprime.fw"
#define OSCI_VIDPID "04b4.1004"
static const int hwopts[] = {
SR_HWOPT_CONN,
SR_HWOPT_SERIALCOMM,
0,
};
static const int hwcaps[] = {
SR_HWCAP_OSCILLOSCOPE,
SR_HWCAP_LIMIT_SAMPLES,
SR_HWCAP_CONTINUOUS,
SR_HWCAP_TIMEBASE,
SR_HWCAP_VDIV,
0,
};
static const struct sr_rational timebases[] = {
/* 24 MHz */
{ 42, 1e9 },
/* 12 MHz */
{ 83, 1e9 },
/* 6 MHz */
{ 167, 1e9 },
/* 3 MHz */
{ 333, 1e9 },
/* 1.5 MHz */
{ 667, 1e9 },
/* 750 kHz */
{ 1333, 1e9 },
/* 375 kHz */
{ 2667, 1e9 },
/* 187.5 kHz */
{ 5333, 1e9 },
/* 93.25 kHz */
{ 10724, 1e9 },
/* 46.875 kHz */
{ 21333, 1e9 },
/* 23.4375 kHz */
{ 42666, 1e9 },
/* 11.718 kHz */
{ 85339, 1e9 },
/* 5.859 kHz */
{ 170678, 1e9 },
/* 2.929 kHz */
{ 341413, 1e9 },
/* 1.465 kHz */
{ 682594, 1e9 },
/* 732 Hz */
{ 1366, 1e6 },
/* 366 Hz */
{ 2732, 1e6 },
/* 183 Hz */
{ 5464, 1e6 },
/* 91 Hz */
{ 10989, 1e6 },
/* 46 Hz */
{ 21739, 1e6 },
/* 23 Hz */
{ 43478, 1e6 },
/* 12 Hz */
{ 83333, 1e6 },
};
static const char *probe_names[] = {
"CHA",
"CHB",
NULL,
};
static const struct sr_rational vdivs[] = {
{ 1, 1 },
{ 2, 1 },
{ 5, 2 },
{ 5, 1 },
{ 10, 1 },
};
SR_PRIV struct sr_dev_driver nexus_osciprime_driver_info;
static struct sr_dev_driver *di = &nexus_osciprime_driver_info;
static int hw_dev_close(struct sr_dev_inst *sdi);
/* Properly close and free all devices. */
static int clear_instances(void)
@ -42,8 +127,8 @@ static int clear_instances(void)
if (!(devc = sdi->priv))
continue;
/* TODO */
hw_dev_close(sdi);
sr_usb_dev_inst_free(devc->usb);
sr_dev_inst_free(sdi);
}
@ -53,7 +138,7 @@ static int clear_instances(void)
return SR_OK;
}
static int hw_init(void)
static int hw_init(struct sr_context *sr_ctx)
{
struct drv_context *drvc;
@ -62,8 +147,7 @@ static int hw_init(void)
return SR_ERR_MALLOC;
}
/* TODO */
drvc->sr_ctx = sr_ctx;
di->priv = drvc;
return SR_OK;
@ -72,15 +156,76 @@ static int hw_init(void)
static GSList *hw_scan(GSList *options)
{
struct drv_context *drvc;
GSList *devices;
struct dev_context *devc;
struct sr_dev_inst *sdi;
struct sr_usb_dev_inst *usb;
struct sr_hwopt *opt;
struct sr_probe *probe;
libusb_device *dev;
GSList *usb_devices, *devices, *l;
int i;
const char *conn;
(void)options;
devices = NULL;
drvc = di->priv;
drvc->instances = NULL;
if (!(drvc = di->priv)) {
sr_err("Driver was not initialized.");
return NULL;
}
/* TODO */
/* USB scan is always authoritative. */
clear_instances();
conn = NULL;
for (l = options; l; l = l->next) {
opt = l->data;
switch (opt->hwopt) {
case SR_HWOPT_CONN:
conn = opt->value;
break;
}
}
if (!conn)
conn = OSCI_VIDPID;
devices = NULL;
if ((usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) {
for (l = usb_devices; l; l = l->next) {
usb = l->data;
if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
OSCI_VENDOR, OSCI_MODEL, OSCI_VERSION)))
return NULL;
sdi->driver = di;
for (i = 0; probe_names[i]; i++) {
if (!(probe = sr_probe_new(i, SR_PROBE_ANALOG, TRUE,
probe_names[i])))
return NULL;
sdi->probes = g_slist_append(sdi->probes, probe);
}
if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
return NULL;
sdi->priv = devc;
devc->usb = usb;
if (strcmp(conn, OSCI_VIDPID)) {
if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
break;
dev = libusb_get_device(usb->devhdl);
if (ezusb_upload_firmware(dev, 0, OSCI_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 for device "
"at bus %d address %d.", usb->bus, usb->address);
}
drvc->instances = g_slist_append(drvc->instances, sdi);
devices = g_slist_append(devices, sdi);
}
g_slist_free(usb_devices);
} else
g_slist_free_full(usb_devices, g_free);
return devices;
}
@ -175,7 +320,7 @@ static int hw_dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
SR_PRIV struct sr_dev_driver nexus_osciprime_driver_info = {
.name = "nexus-osciprime",
.longname = "Nexus Osciprime",
.longname = "Nexus OsciPrime",
.api_version = 1,
.init = hw_init,
.cleanup = hw_cleanup,

View File

@ -46,6 +46,9 @@ struct dev_context {
/** The current number of already received samples. */
uint64_t num_samples;
struct sr_usb_dev_inst *usb;
int usbfd[10];
int64_t fw_updated;
};
SR_PRIV int nexus_osciprime_receive_data(int fd, int revents, void *cb_data);