/*
* This file is part of the sigrok project.
*
- * Copyright (C) 2010 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <inttypes.h>
#include <glib.h>
#include <libusb.h>
-#include <sigrok.h>
-#include <sigrok-internal.h>
+#include "config.h"
+#include "sigrok.h"
+#include "sigrok-internal.h"
#include "saleae-logic.h"
static struct fx2_profile supported_fx2[] = {
0,
};
+static const char *probe_names[] = {
+ "0",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ NULL,
+};
+
static uint64_t supported_samplerates[] = {
SR_KHZ(200),
SR_KHZ(250),
static GSList *device_instances = NULL;
static libusb_context *usb_context = NULL;
+static int new_saleae_logic_firmware = 0;
+
static int hw_set_configuration(int device_index, int capability, void *value);
static void hw_stop_acquisition(int device_index, gpointer session_device_id);
break;
intf_dsc = &(conf_dsc->interface[0].altsetting[0]);
- if (intf_dsc->bNumEndpoints != 2)
- /* Need 2 endpoints. */
+ if (intf_dsc->bNumEndpoints == 4) {
+ /* The new Saleae Logic firmware has 4 endpoints. */
+ new_saleae_logic_firmware = 1;
+ } else if (intf_dsc->bNumEndpoints == 2) {
+ /* The old Saleae Logic firmware has 2 endpoints. */
+ new_saleae_logic_firmware = 0;
+ } else {
+ /* Other number of endpoints -> not a Saleae Logic. */
break;
+ }
if ((intf_dsc->endpoint[0].bEndpointAddress & 0x8f) !=
(1 | LIBUSB_ENDPOINT_OUT))
/* First endpoint should be 2 (inbound). */
break;
+ /* TODO: The new firmware has 4 endpoints... */
+
/* If we made it here, it must be a Saleae Logic. */
ret = 1;
}
* This device is fully enumerated, so we need to find this
* device by vendor, product, bus and address.
*/
- if (libusb_get_bus_number(devlist[i]) != sdi->usb->bus
- || libusb_get_device_address(devlist[i]) != sdi->usb->address)
+ if (libusb_get_bus_number(devlist[i]) != fx2->usb->bus
+ || libusb_get_device_address(devlist[i]) != fx2->usb->address)
/* this is not the one */
continue;
}
- if (!(err = libusb_open(devlist[i], &sdi->usb->devhdl))) {
- if (sdi->usb->address == 0xff)
+ if (!(err = libusb_open(devlist[i], &fx2->usb->devhdl))) {
+ if (fx2->usb->address == 0xff)
/*
* first time we touch this device after firmware upload,
* so we don't know the address yet.
*/
- sdi->usb->address = libusb_get_device_address(devlist[i]);
+ fx2->usb->address = libusb_get_device_address(devlist[i]);
sdi->status = SR_ST_ACTIVE;
sr_info("saleae: opened device %d on %d.%d interface %d",
- sdi->index, sdi->usb->bus,
- sdi->usb->address, USB_INTERFACE);
+ sdi->index, fx2->usb->bus,
+ fx2->usb->address, USB_INTERFACE);
} else {
sr_warn("failed to open device: %d", err);
}
static void close_device(struct sr_device_instance *sdi)
{
- if (sdi->usb->devhdl == NULL)
+ struct fx2_device *fx2;
+
+ fx2 = sdi->priv;
+
+ if (fx2->usb->devhdl == NULL)
return;
sr_info("saleae: closing device %d on %d.%d interface %d", sdi->index,
- sdi->usb->bus, sdi->usb->address, USB_INTERFACE);
- libusb_release_interface(sdi->usb->devhdl, USB_INTERFACE);
- libusb_close(sdi->usb->devhdl);
- sdi->usb->devhdl = NULL;
+ fx2->usb->bus, fx2->usb->address, USB_INTERFACE);
+ libusb_release_interface(fx2->usb->devhdl, USB_INTERFACE);
+ libusb_close(fx2->usb->devhdl);
+ fx2->usb->devhdl = NULL;
sdi->status = SR_ST_INACTIVE;
}
struct fx2_device *fx2;
if (!(fx2 = g_try_malloc0(sizeof(struct fx2_device)))) {
- sr_err("saleae: %s: saleae malloc failed", __func__);
+ sr_err("saleae: %s: fx2 malloc failed", __func__);
return NULL;
}
fx2->trigger_stage = TRIGGER_FIRED;
+ fx2->usb = NULL;
return fx2;
}
int err, devcnt, i, j;
/* Avoid compiler warnings. */
- deviceinfo = deviceinfo;
+ (void)deviceinfo;
if (libusb_init(&usb_context) != 0) {
sr_warn("Failed to initialize USB.");
if (check_conf_profile(devlist[i])) {
/* Already has the firmware, so fix the new address. */
+ sr_dbg("Found a Saleae Logic with %s firmware.",
+ new_saleae_logic_firmware ? "new" : "old");
sdi->status = SR_ST_INACTIVE;
- sdi->usb = sr_usb_device_instance_new
+ fx2->usb = sr_usb_device_instance_new
(libusb_get_bus_number(devlist[i]),
libusb_get_device_address(devlist[i]), NULL);
} else {
g_get_current_time(&fx2->fw_updated);
else
sr_warn("firmware upload failed for device %d", devcnt);
- sdi->usb = sr_usb_device_instance_new
+ fx2->usb = sr_usb_device_instance_new
(libusb_get_bus_number(devlist[i]), 0xff, NULL);
}
devcnt++;
}
fx2 = sdi->priv;
- err = libusb_claim_interface(sdi->usb->devhdl, USB_INTERFACE);
+ err = libusb_claim_interface(fx2->usb->devhdl, USB_INTERFACE);
if (err != 0) {
sr_warn("Unable to claim interface: %d", err);
return SR_ERR;
static void hw_cleanup(void)
{
GSList *l;
+ struct sr_device_instance *sdi;
+ struct fx2_device *fx2;
- /* Properly close all devices... */
- for (l = device_instances; l; l = l->next)
- close_device((struct sr_device_instance *)l->data);
+ /* Properly close and free all devices. */
+ for (l = device_instances; l; l = l->next) {
+ sdi = l->data;
+ fx2 = sdi->priv;
+ close_device(sdi);
+ sr_usb_device_instance_free(fx2->usb);
+ sr_device_instance_free(sdi);
+ }
- /* ...and free all their memory. */
- for (l = device_instances; l; l = l->next)
- g_free(l->data);
g_slist_free(device_instances);
device_instances = NULL;
case SR_DI_NUM_PROBES:
info = GINT_TO_POINTER(fx2->profile->num_probes);
break;
+ case SR_DI_PROBE_NAMES:
+ info = probe_names;
+ break;
case SR_DI_SAMPLERATES:
info = &samplerates;
break;
return capabilities;
}
+static uint8_t new_firmware_divider_value(uint64_t samplerate)
+{
+ switch (samplerate) {
+ case SR_MHZ(24):
+ return 0xe0;
+ break;
+ case SR_MHZ(16):
+ return 0xd5;
+ break;
+ case SR_MHZ(12):
+ return 0xe2;
+ break;
+ case SR_MHZ(8):
+ return 0xd4;
+ break;
+ case SR_MHZ(4):
+ return 0xda;
+ break;
+ case SR_MHZ(2):
+ return 0xe6;
+ break;
+ case SR_MHZ(1):
+ return 0x8e;
+ break;
+ case SR_KHZ(500):
+ return 0xfe;
+ break;
+ case SR_KHZ(250):
+ return 0x9e;
+ break;
+ case SR_KHZ(200):
+ return 0x4e;
+ break;
+ }
+
+ /* Shouldn't happen. */
+ sr_err("saleae: %s: Invalid samplerate %" PRIu64 "",
+ __func__, samplerate);
+ return 0;
+}
+
static int set_configuration_samplerate(struct sr_device_instance *sdi,
uint64_t samplerate)
{
if (supported_samplerates[i] == 0)
return SR_ERR_SAMPLERATE;
- divider = (uint8_t) (48 / (samplerate / 1000000.0)) - 1;
+ if (new_saleae_logic_firmware)
+ divider = new_firmware_divider_value(samplerate);
+ else
+ divider = (uint8_t) (48 / (samplerate / 1000000.0)) - 1;
sr_info("saleae: setting samplerate to %" PRIu64 " Hz (divider %d)",
samplerate, divider);
- buf[0] = 0x01;
+
+ buf[0] = (new_saleae_logic_firmware) ? 0xd5 : 0x01;
buf[1] = divider;
- ret = libusb_bulk_transfer(sdi->usb->devhdl, 1 | LIBUSB_ENDPOINT_OUT,
+ ret = libusb_bulk_transfer(fx2->usb->devhdl, 1 | LIBUSB_ENDPOINT_OUT,
buf, 2, &result, 500);
if (ret != 0) {
sr_warn("failed to set samplerate: %d", ret);
return SR_ERR;
}
fx2->cur_samplerate = samplerate;
- fx2->period_ps = 1000000000000 / samplerate;
return SR_OK;
}
struct timeval tv;
/* Avoid compiler warnings. */
- fd = fd;
- revents = revents;
- user_data = user_data;
+ (void)fd;
+ (void)revents;
+ (void)user_data;
tv.tv_sec = tv.tv_usec = 0;
libusb_handle_events_timeout(usb_context, &tv);
return TRUE;
}
-void receive_transfer(struct libusb_transfer *transfer)
+static void receive_transfer(struct libusb_transfer *transfer)
{
/* TODO: these statics have to move to fx2_device struct */
static int num_samples = 0;
/* Match on this trigger stage. */
fx2->trigger_buffer[fx2->trigger_stage] = cur_buf[i];
fx2->trigger_stage++;
+
if (fx2->trigger_stage == NUM_TRIGGER_STAGES || fx2->trigger_mask[fx2->trigger_stage] == 0) {
/* Match on all trigger stages, we're done. */
trigger_offset = i + 1;
* Tell the frontend we hit the trigger here.
*/
packet.type = SR_DF_TRIGGER;
- packet.timeoffset = (num_samples - fx2->trigger_stage) * fx2->period_ps;
- packet.duration = 0;
packet.payload = NULL;
sr_session_bus(fx2->session_data, &packet);
* skipping past them.
*/
packet.type = SR_DF_LOGIC;
- packet.timeoffset = (num_samples - fx2->trigger_stage) * fx2->period_ps;
- packet.duration = fx2->trigger_stage * fx2->period_ps;
packet.payload = &logic;
logic.length = fx2->trigger_stage;
logic.unitsize = 1;
if (fx2->trigger_stage == TRIGGER_FIRED) {
/* Send the incoming transfer to the session bus. */
packet.type = SR_DF_LOGIC;
- packet.timeoffset = num_samples * fx2->period_ps;
- packet.duration = cur_buflen * fx2->period_ps;
packet.payload = &logic;
logic.length = cur_buflen - trigger_offset;
logic.unitsize = 1;
return SR_ERR_MALLOC;
}
transfer = libusb_alloc_transfer(0);
- libusb_fill_bulk_transfer(transfer, sdi->usb->devhdl,
+ libusb_fill_bulk_transfer(transfer, fx2->usb->devhdl,
2 | LIBUSB_ENDPOINT_IN, buf, size,
receive_transfer, fx2, 40);
if (libusb_submit_transfer(transfer) != 0) {
gettimeofday(&header->starttime, NULL);
header->samplerate = fx2->cur_samplerate;
header->num_logic_probes = fx2->profile->num_probes;
- header->num_analog_probes = 0;
sr_session_bus(session_data, packet);
g_free(header);
g_free(packet);
struct sr_datafeed_packet packet;
/* Avoid compiler warnings. */
- device_index = device_index;
+ (void)device_index;
packet.type = SR_DF_END;
sr_session_bus(session_data, &packet);
/* TODO: Need to cancel and free any queued up transfers. */
}
-struct sr_device_plugin saleae_logic_plugin_info = {
+SR_PRIV struct sr_device_plugin saleae_logic_plugin_info = {
.name = "saleae-logic",
.longname = "Saleae Logic",
.api_version = 1,