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:
parent
35a078bce5
commit
523dfc2497
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue