]> sigrok.org Git - libsigrok.git/blob - output/ols.c
a77dc6277b35e17e122d4c20839f3777489daa08
[libsigrok.git] / output / ols.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
5  * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20  */
21
22 /*
23  * This implements version 1.3 of the output format for the OpenBench Logic
24  * Sniffer "Alternative" Java client. Details:
25  * https://github.com/jawi/ols/wiki/OLS-data-file-format
26  */
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <glib.h>
31 #include "libsigrok.h"
32 #include "libsigrok-internal.h"
33
34 /* Message logging helpers with driver-specific prefix string. */
35 #define DRIVER_LOG_DOMAIN "output/ols: "
36 #define sr_log(l, s, args...) sr_log(l, DRIVER_LOG_DOMAIN s, ## args)
37 #define sr_spew(s, args...) sr_spew(DRIVER_LOG_DOMAIN s, ## args)
38 #define sr_dbg(s, args...) sr_dbg(DRIVER_LOG_DOMAIN s, ## args)
39 #define sr_info(s, args...) sr_info(DRIVER_LOG_DOMAIN s, ## args)
40 #define sr_warn(s, args...) sr_warn(DRIVER_LOG_DOMAIN s, ## args)
41 #define sr_err(s, args...) sr_err(DRIVER_LOG_DOMAIN s, ## args)
42
43 struct context {
44     uint64_t samplerate;
45         uint64_t num_samples;
46 };
47
48 static int init(struct sr_output *o)
49 {
50         struct context *ctx;
51
52         if (!(ctx = g_try_malloc(sizeof(struct context)))) {
53                 sr_err("%s: ctx malloc failed", __func__);
54                 return SR_ERR_MALLOC;
55         }
56         o->internal = ctx;
57
58     ctx->samplerate = 0;
59         ctx->num_samples = 0;
60
61         return SR_OK;
62 }
63
64 static GString *gen_header(const struct sr_dev_inst *sdi, struct context *ctx)
65 {
66         struct sr_probe *probe;
67         GSList *l;
68         GString *s;
69         GVariant *gvar;
70         int num_enabled_probes;
71
72     if (!ctx->samplerate && sr_config_get(sdi->driver, SR_CONF_SAMPLERATE,
73                         &gvar, sdi) == SR_OK) {
74                 ctx->samplerate = g_variant_get_uint64(gvar);
75                 g_variant_unref(gvar);
76         }
77
78         num_enabled_probes = 0;
79         for (l = sdi->probes; l; l = l->next) {
80                 probe = l->data;
81                 if (probe->enabled)
82                         num_enabled_probes++;
83         }
84
85         s = g_string_sized_new(512);
86         g_string_append_printf(s, ";Rate: %"PRIu64"\n", ctx->samplerate);
87         g_string_append_printf(s, ";Channels: %d\n", num_enabled_probes);
88         g_string_append_printf(s, ";EnabledChannels: -1\n");
89         g_string_append_printf(s, ";Compressed: true\n");
90         g_string_append_printf(s, ";CursorEnabled: false\n");
91
92         return s;
93 }
94
95 static GString *receive(struct sr_output *o, const struct sr_dev_inst *sdi,
96                 const struct sr_datafeed_packet *packet)
97 {
98         struct context *ctx;
99         const struct sr_datafeed_meta *meta;
100         const struct sr_datafeed_logic *logic;
101         const struct sr_config *src;
102         GSList *l;
103         GString *out;
104         unsigned int i, j;
105         uint8_t c;
106
107         if (!o || !o->sdi)
108                 return NULL;
109         ctx = o->internal;
110
111         out = NULL;
112         switch (packet->type) {
113     case SR_DF_META:
114                 meta = packet->payload;
115                 for (l = meta->config; l; l = l->next) {
116                         src = l->data;
117                         if (src->key == SR_CONF_SAMPLERATE)
118                                 ctx->samplerate = g_variant_get_uint64(src->data);
119                 }
120         break;
121     case SR_DF_LOGIC:
122                 logic = packet->payload;
123                 if (ctx->num_samples == 0) {
124                         /* First logic packet in the feed. */
125                         out = gen_header(sdi, ctx);
126                 } else
127                         out = g_string_sized_new(512);
128                 for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
129                         for (j = 0; j < logic->unitsize; j++) {
130                                 /* The OLS format wants the samples presented MSB first. */
131                                 c = *((uint8_t *)logic->data + i + logic->unitsize - 1 - j);
132                                 g_string_append_printf(out, "%02x", c);
133                         }
134                         g_string_append_printf(out, "@%"PRIu64"\n", ctx->num_samples++);
135                 }
136                 break;
137         }
138
139     return out;
140 }
141
142 static int cleanup(struct sr_output *o)
143 {
144         struct context *ctx;
145
146         if (!o || !o->sdi)
147                 return SR_ERR_ARG;
148
149         ctx = o->internal;
150     g_free(ctx);
151     o->internal = NULL;
152
153         return SR_OK;
154 }
155
156 SR_PRIV struct sr_output_format output_ols = {
157         .id = "ols",
158         .description = "OpenBench Logic Sniffer",
159         .df_type = SR_DF_LOGIC,
160         .init = init,
161         .recv = receive,
162         .cleanup = cleanup
163 };