From: Kumar Abhishek <abhis...@theembeddedkitchen.net>

Tested on a BeagleBone Black

Signed-off-by: Kumar Abhishek <abhis...@theembeddedkitchen.net>
---
 hardware/beaglelogic/api.c      | 311 ++++++++++++++++++++++++++++++++++++----
 hardware/beaglelogic/protocol.c |  82 ++++++++++-
 hardware/beaglelogic/protocol.h |  31 +++-
 3 files changed, 385 insertions(+), 39 deletions(-)

diff --git a/hardware/beaglelogic/api.c b/hardware/beaglelogic/api.c
index f2b528c..9eb0c4d 100644
--- a/hardware/beaglelogic/api.c
+++ b/hardware/beaglelogic/api.c
@@ -18,19 +18,81 @@
  */
 
 #include "protocol.h"
+#include "beaglelogic.h"
 
 SR_PRIV struct sr_dev_driver beaglelogic_driver_info;
 static struct sr_dev_driver *di = &beaglelogic_driver_info;
 
+/* Hardware options */
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+};
+
+/* Hardware capabiities */
+static const int32_t hwcaps[] = {
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_TRIGGER_MATCH,
+
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_CONTINUOUS,
+       /* SR_CONF_EXTERNAL_CLOCK, TODO in a future BeagleLogic firmware */
+
+       SR_CONF_NUM_LOGIC_CHANNELS,
+};
+
+/* Trigger matching capabilities */
+static const int32_t soft_trigger_matches[] = {
+       SR_TRIGGER_ZERO,
+       SR_TRIGGER_ONE,
+       SR_TRIGGER_RISING,
+       SR_TRIGGER_FALLING,
+       SR_TRIGGER_EDGE,
+};
+
+/* Channels are numbered 0-31 (on the PCB silkscreen). */
+SR_PRIV const char *beaglelogic_channel_names[NUM_CHANNELS + 1] = {
+       "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
+       "13", NULL,
+};
+
+/* Possible sample rates : 10 Hz to 100 MHz = (100 / x) MHz */
+static const uint64_t samplerates[] = {
+               SR_HZ(10),
+               SR_MHZ(100),
+               SR_HZ(1),
+};
+
 static int init(struct sr_context *sr_ctx)
 {
        return std_init(sr_ctx, di, LOG_PREFIX);
 }
 
+static struct dev_context * beaglelogic_devc_alloc(void)
+{
+       struct dev_context *devc;
+
+       /* Allocate the zeroed structure */
+       if (!(devc = g_try_malloc0(sizeof(*devc)))) {
+               sr_err("Device context alloc failed.");
+               return NULL;
+       }
+
+       /* Default non-zero values (if any) */
+       devc->fd = -1;
+       devc->limit_samples = (uint64_t)-1;
+
+       return devc;
+}
+
 static GSList *scan(GSList *options)
 {
        struct drv_context *drvc;
        GSList *devices;
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       int i, fd, maxch;
 
        (void)options;
 
@@ -38,8 +100,37 @@ static GSList *scan(GSList *options)
        drvc = di->priv;
        drvc->instances = NULL;
 
-       /* TODO: scan for devices, either based on a SR_CONF_CONN option
-        * or on a USB scan. */
+       /* Probe for /dev/beaglelogic */
+       if (!g_file_test(BEAGLELOGIC_DEV_NODE, G_FILE_TEST_EXISTS))
+               return NULL;
+
+       /* Get a little information from BeagleLogic */
+       if ((fd = beaglelogic_open()) == -1)
+               return NULL;
+       beaglelogic_get_sampleunit(fd, (uint32_t *)&i);
+       beaglelogic_close(fd);
+       maxch = (i == BL_SAMPLEUNIT_8_BITS) ? 8 : NUM_CHANNELS;
+
+       sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, NULL, "BeagleLogic", "1.0");
+       sdi->driver = di;
+
+       /* Signal */
+       sr_info("BeagleLogic device found at "BEAGLELOGIC_DEV_NODE);
+
+       /* Fill the channels */
+       for (i = 0; i < maxch; i++) {
+               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+                               beaglelogic_channel_names[i])))
+                       return NULL;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       }
+
+       /* Allocate the device context */
+       devc = beaglelogic_devc_alloc();
+       sdi->priv = devc;
+
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
 
        return devices;
 }
@@ -56,31 +147,76 @@ static int dev_clear(void)
 
 static int dev_open(struct sr_dev_inst *sdi)
 {
-       (void)sdi;
-
-       /* TODO: get handle from sdi->conn and open it. */
+       int fd;
+       struct dev_context *devc = sdi->priv;
+
+       /* Open BeagleLogic */
+       fd = beaglelogic_open_nonblock();
+       if (fd == -1)
+               return SR_ERR;
+
+       /* Set fd and local attributes */
+       devc->fd = fd;
+       devc->pollfd.fd = fd;
+       devc->pollfd.events = G_IO_IN;
+
+       /* Get default attributes */
+       beaglelogic_get_samplerate(fd, (uint32_t *)&devc->cur_samplerate);
+       beaglelogic_get_sampleunit(fd, (void *)&devc->sampleunit);
+       beaglelogic_get_triggerflags(fd, &devc->triggerflags);
+       beaglelogic_get_buffersize(fd, &devc->buffersize);
+
+       /* Buffer size and sample limit */
+       devc->bufunitsize = beaglelogic_get_bufunitsize(fd);
+       devc->limit_samples =
+               devc->buffersize * SAMPLEUNIT_TO_BYTES(devc->sampleunit);
+
+       /* Map the kernel capture FIFO for reads, saves 1 level of memcpy */
+       if ((devc->sample_buf = beaglelogic_mmap(fd)) == MAP_FAILED) {
+               sr_err("Unable to map capture buffer");
+               beaglelogic_close(fd);
+               return SR_ERR;
+       }
 
+       /* We're good to go now */
        sdi->status = SR_ST_ACTIVE;
-
        return SR_OK;
 }
 
 static int dev_close(struct sr_dev_inst *sdi)
 {
-       (void)sdi;
-
-       /* TODO: get handle from sdi->conn and close it. */
+       struct dev_context *devc = sdi->priv;
 
+       if (sdi->status == SR_ST_ACTIVE) {
+               /* Close the memory mapping and the file */
+               beaglelogic_munmap(devc->fd, devc->sample_buf);
+               beaglelogic_close(devc->fd);
+       }
        sdi->status = SR_ST_INACTIVE;
-
        return SR_OK;
 }
 
 static int cleanup(void)
 {
-       dev_clear();
+       struct drv_context *drvc;
+       struct sr_dev_inst *sdi;
+       GSList *l;
+
+       /* unused driver */
+       if (!(drvc = di->priv))
+               return SR_OK;
+
+       /* Clean up the instances */
+       for (l = drvc->instances; l; l = l->next) {
+               sdi = l->data;
+               di->dev_close(sdi);
+               g_free(sdi->priv);
+               sr_dev_inst_free(sdi);
+       }
+       g_slist_free(drvc->instances);
+       drvc->instances = NULL;
 
-       /* TODO: free other driver resources, if any. */
+       di->priv = NULL;
 
        return SR_OK;
 }
@@ -88,47 +224,99 @@ static int cleanup(void)
 static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
                const struct sr_channel_group *cg)
 {
-       int ret;
-
-       (void)sdi;
-       (void)data;
+       struct dev_context *devc = sdi->priv;
        (void)cg;
 
-       ret = SR_OK;
        switch (key) {
-       /* TODO */
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+
+       case SR_CONF_SAMPLERATE:
+               *data = g_variant_new_uint64(devc->cur_samplerate);
+               break;
+
        default:
                return SR_ERR_NA;
        }
 
-       return ret;
+       return SR_OK;
 }
 
+/* Define maximum possible feasible buffer size on the BeagleBone Black
+ * May be extended to >= 300 MB, but may leave system unstable
+ * Change this to 128 MB if compiling for the BeagleBone White */
+#define MAX_MEM                (256 * 1024 * 1024)
+
 static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
                const struct sr_channel_group *cg)
 {
-       int ret;
-
-       (void)data;
+       struct dev_context *devc = sdi->priv;
+       uint64_t tmp_u64;
        (void)cg;
 
        if (sdi->status != SR_ST_ACTIVE)
                return SR_ERR_DEV_CLOSED;
 
-       ret = SR_OK;
        switch (key) {
-       /* TODO */
+       case SR_CONF_SAMPLERATE:
+               tmp_u64 = g_variant_get_uint64(data);
+               if (beaglelogic_set_samplerate(devc->fd, tmp_u64))
+                       return SR_ERR;
+               devc->cur_samplerate = tmp_u64;
+               break;
+
+       case SR_CONF_LIMIT_SAMPLES:
+               tmp_u64 = g_variant_get_uint64(data);
+               devc->limit_samples = tmp_u64;
+
+               /* Check if we have sufficient buffer size */
+               tmp_u64 *= SAMPLEUNIT_TO_BYTES(devc->sampleunit);
+               beaglelogic_set_triggerflags(devc->fd, BL_TRIGGERFLAGS_ONESHOT);
+#if 0
+               /* Try to allocate that buffer statically if possible. If not, 
then
+                * set continous mode on and fall back to 64 MB buffers */
+               if (tmp_u64 <= MAX_MEM && devc->buffersize < tmp_u64) {
+                       beaglelogic_munmap(devc->fd, devc->sample_buf);
+
+                       if (beaglelogic_set_buffersize(devc->fd, tmp_u64)) {
+                               /* Restore previous state */
+                               beaglelogic_set_buffersize(devc->fd,
+                                               devc->buffersize);
+                               beaglelogic_set_triggerflags(devc->fd,
+                                               BL_TRIGGERFLAGS_CONTINUOUS);
+                               return SR_ERR;
+                       }
+                       /* Remap sample buffer */
+                       devc->sample_buf = beaglelogic_mmap(devc->fd);
+                       beaglelogic_get_buffersize(devc->fd, &devc->buffersize);
+
+               } else {
+                       /* Use 64 MB buffers and continuous mode */
+                       sr_warn("insufficient memory available, check kernel "\
+                                       "logs to see if any buffer was "\
+                                       "dropped during continuous 
acquisition.");
+
+                       beaglelogic_set_buffersize(devc->fd, 64 * 1024 * 1024);
+                       beaglelogic_set_triggerflags(devc->fd,
+                                       BL_TRIGGERFLAGS_CONTINUOUS);
+               }
+#endif
+               break;
+
        default:
-               ret = SR_ERR_NA;
+               return SR_ERR_NA;
        }
 
-       return ret;
+       return SR_OK;
 }
 
 static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
                const struct sr_channel_group *cg)
 {
        int ret;
+       GVariant *gvar;
+       GVariantBuilder gvb;
 
        (void)sdi;
        (void)data;
@@ -136,7 +324,26 @@ static int config_list(int key, GVariant **data, const 
struct sr_dev_inst *sdi,
 
        ret = SR_OK;
        switch (key) {
-       /* TODO */
+       case SR_CONF_SCAN_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_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}", "samplerate-steps", gvar);
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TRIGGER_MATCH:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               soft_trigger_matches, 
ARRAY_SIZE(soft_trigger_matches),
+                               sizeof(int32_t));
+               break;
        default:
                return SR_ERR_NA;
        }
@@ -144,29 +351,71 @@ static int config_list(int key, GVariant **data, const 
struct sr_dev_inst *sdi,
        return ret;
 }
 
+/* get a sane timeout for poll() */
+#define BUFUNIT_TIMEOUT_MS(x)  (100 + (uint32_t)((x->bufunitsize * 1000) /  \
+                                       (x->cur_samplerate)))
+
 static int dev_acquisition_start(const struct sr_dev_inst *sdi,
                                    void *cb_data)
 {
-       (void)sdi;
        (void)cb_data;
+       struct dev_context *devc = sdi->priv;
+       struct sr_channel *ch;
+       struct sr_trigger *trigger;
+       GSList *l;
 
        if (sdi->status != SR_ST_ACTIVE)
                return SR_ERR_DEV_CLOSED;
 
-       /* TODO: configure hardware, reset acquisition state, set up
-        * callbacks and send header packet. */
+       /* Save user pointer */
+       devc->cb_data = cb_data;
+
+       /* Configure channels */
+       beaglelogic_set_sampleunit(devc->fd, BL_SAMPLEUNIT_8_BITS);
+       for (l = sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->index >= 8 && ch->enabled) {
+                       beaglelogic_set_sampleunit(devc->fd,
+                                       BL_SAMPLEUNIT_16_BITS);
+                       break;
+               }
+       }
+       beaglelogic_get_sampleunit(devc->fd, &devc->sampleunit);
+
+       /* Configure triggers & send header packet */
+       if ((trigger = sr_session_trigger_get())) {
+               devc->stl = soft_trigger_logic_new(sdi, trigger);
+               devc->trigger_fired = FALSE;
+       } else
+               devc->trigger_fired = TRUE;
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Trigger and add poll on file */
+       beaglelogic_start(devc->fd);
+       sr_session_source_add_pollfd(&devc->pollfd, -1,
+                       beaglelogic_receive_data, (void *)sdi);
 
        return SR_OK;
 }
 
 static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
 {
+       struct dev_context *devc = sdi->priv;
+       struct sr_datafeed_packet pkt;
+
        (void)cb_data;
 
        if (sdi->status != SR_ST_ACTIVE)
                return SR_ERR_DEV_CLOSED;
 
-       /* TODO: stop acquisition. */
+       /* Execute a stop on BeagleLogic */
+       beaglelogic_stop(devc->fd);
+
+       /* Remove session source and send EOT packet */
+       sr_session_source_remove_pollfd(&devc->pollfd);
+       pkt.type = SR_DF_END;
+       pkt.payload = NULL;
+       sr_session_send(sdi, &pkt);
 
        return SR_OK;
 }
diff --git a/hardware/beaglelogic/protocol.c b/hardware/beaglelogic/protocol.c
index f765a95..9dc2c0b 100644
--- a/hardware/beaglelogic/protocol.c
+++ b/hardware/beaglelogic/protocol.c
@@ -18,22 +18,94 @@
  */
 
 #include "protocol.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
+/* sigrok-cli supports this at max */
+#define COPY_SIZE      (512 * 1024)
+
+#define min(a,b)       ((a) < (b) ? (a) : (b))
+
+/* This implementation is zero copy from the libsigrok side.
+ * It does not copy any data, just passes a pointer from the mmap'ed
+ * kernel buffers appropriately. It is up to the application which is
+ * using libsigrok to decide how to deal with the data.
+ *
+ * TODO: Implement soft triggers
+ */
 SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data)
 {
        const struct sr_dev_inst *sdi;
        struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
 
-       (void)fd;
+       int trigger_offset;
+       uint32_t copysize;
 
-       if (!(sdi = cb_data))
+       if (!(sdi = cb_data) || !(devc = sdi->priv))
                return TRUE;
 
-       if (!(devc = sdi->priv))
-               return TRUE;
+       copysize = COPY_SIZE;
+
+       sr_info("In callback (), offset=%d", devc->offset);
+       logic.unitsize = SAMPLEUNIT_TO_BYTES(devc->sampleunit);
 
        if (revents == G_IO_IN) {
-               /* TODO */
+               /* Configure data packet */
+               packet.type = SR_DF_LOGIC;
+               packet.payload = &logic;
+               logic.data = devc->sample_buf + devc->offset;
+               logic.length = min(copysize, devc->limit_samples * 
logic.unitsize - devc->bytes_read);
+
+               if (devc->trigger_fired) {
+                       /* Send the incoming transfer to the session bus. */
+                       sr_session_send(devc->cb_data, &packet);
+               } else {
+                       /* Check for trigger */
+                       trigger_offset = soft_trigger_logic_check(devc->stl,
+                                               logic.data,
+                                               copysize);
+
+                       if (trigger_offset > -1) {
+                               trigger_offset *= logic.unitsize;
+                               logic.length -= trigger_offset;
+                               logic.data += trigger_offset;
+
+                               sr_session_send(devc->cb_data, &packet);
+
+                               devc->trigger_fired = TRUE;
+                       }
+               }
+
+               /* Dummy read the data into a null pointer. The kernel
+                * module detects this and just updates its internal
+                * read cursor for poll() to work properly */
+               read(fd, NULL, copysize);
+
+               /* Update byte count and offset (roll over if needed) */
+               devc->bytes_read += logic.length;
+               if ((devc->offset += copysize) >= devc->buffersize) {
+                       /* One shot capture, we abort and settle with less than
+                        * the required number of samples */
+                       if (devc->triggerflags)
+                               devc->offset = 0;
+                       else
+                               copysize = 0;
+               }
+
+       }
+
+       /* EOF Received or we have reached the limit */
+       if (devc->bytes_read >= devc->limit_samples * logic.unitsize || 
copysize == 0) {
+               /* Send EOA Packet, stop polling */
+               packet.type = SR_DF_END;
+               packet.payload = NULL;
+               sr_session_send(sdi, &packet);
+
+               sr_session_source_remove_pollfd(&devc->pollfd);
        }
 
        return TRUE;
diff --git a/hardware/beaglelogic/protocol.h b/hardware/beaglelogic/protocol.h
index 07d3bf2..c477e59 100644
--- a/hardware/beaglelogic/protocol.h
+++ b/hardware/beaglelogic/protocol.h
@@ -1,5 +1,5 @@
 /*
- * This file is part of the libsigrok project.
+ * This file is part of the libsigrok and the BeagleLogic project.
  *
  * Copyright (C) 2014 Kumar Abhishek <abhis...@theembeddedkitchen.net>
  *
@@ -27,16 +27,41 @@
 
 #define LOG_PREFIX "beaglelogic"
 
+#define NUM_CHANNELS            14
+#define DEFAULT_SAMPLERATE      SR_MHZ(50)
+
+#define SAMPLEUNIT_TO_BYTES(x) ((x) == 1 ? 1 : 2)
+
 /** Private, per-device-instance driver context. */
 struct dev_context {
        /* Model-specific information */
+       int max_channels;
+       uint32_t fw_ver;
 
-       /* Acquisition settings */
+       /* Acquisition settings: see beaglelogic.h */
+       uint64_t cur_samplerate;
+       uint64_t limit_samples;
+       uint32_t sampleunit;
+       uint32_t triggerflags;
+
+       /* Buffers: size of each buffer block and the total buffer area */
+       uint32_t bufunitsize;
+       uint32_t buffersize;
 
        /* Operational state */
+       int fd;
+       GPollFD pollfd;
+
+       uint64_t bytes_read;
+       uint64_t sent_samples;
+       uint32_t offset;
+       uint8_t *sample_buf;    /* mmap'd kernel buffer here */
 
-       /* Temporary state across callbacks */
+       void *cb_data;
 
+       /* Trigger logic */
+       struct soft_trigger_logic *stl;
+       gboolean trigger_fired;
 };
 
 SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data);
-- 
1.9.1


------------------------------------------------------------------------------
Open source business process management suite built on Java and Eclipse
Turn processes into business applications with Bonita BPM Community Edition
Quickly connect people, data, and systems into organized workflows
Winner of BOSSIE, CODIE, OW2 and Gartner awards
http://p.sf.net/sfu/Bonitasoft
_______________________________________________
sigrok-devel mailing list
sigrok-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sigrok-devel

Reply via email to