]> sigrok.org Git - libsigrok.git/blame - output/hex.c
build: Portability fixes.
[libsigrok.git] / output / hex.c
CommitLineData
8d3af2e8
BV
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <stdlib.h>
21#include <string.h>
22#include <glib.h>
23#include "libsigrok.h"
24#include "libsigrok-internal.h"
25
26#define LOG_PREFIX "output/hex"
27
28#define DEFAULT_SAMPLES_PER_LINE 192
29
30struct context {
31 unsigned int num_enabled_channels;
32 int samples_per_line;
33 int bit_cnt;
34 int spl_cnt;
35 int trigger;
7bcbbfae 36 uint64_t samplerate;
8d3af2e8
BV
37 int *channel_index;
38 char **channel_names;
39 char **line_values;
40 uint8_t *sample_buf;
7bcbbfae 41 gboolean header_done;
8d3af2e8 42 GString **lines;
8d3af2e8
BV
43};
44
45static int init(struct sr_output *o)
46{
47 struct context *ctx;
48 struct sr_channel *ch;
49 GSList *l;
dba3e682
BV
50 GHashTableIter iter;
51 gpointer key, value;
8d3af2e8 52 unsigned int i, j;
7bcbbfae 53 int spl;
8d3af2e8
BV
54
55 if (!o || !o->sdi)
56 return SR_ERR_ARG;
dba3e682
BV
57
58 spl = DEFAULT_SAMPLES_PER_LINE;
59 g_hash_table_iter_init(&iter, o->params);
60 while (g_hash_table_iter_next(&iter, &key, &value)) {
61 if (!strcmp(key, "width")) {
62 if ((spl = strtoul(value, NULL, 10)) < 1) {
63 sr_err("Invalid width.");
64 return SR_ERR_ARG;
65 }
66 } else {
67 sr_err("Unknown parameter '%s'.", key);
68 return SR_ERR_ARG;
69 }
70 }
71
8d3af2e8
BV
72 ctx = g_malloc0(sizeof(struct context));
73 o->internal = ctx;
74 ctx->trigger = -1;
8d3af2e8
BV
75 ctx->samples_per_line = spl;
76
77 for (l = o->sdi->channels; l; l = l->next) {
78 ch = l->data;
79 if (ch->type != SR_CHANNEL_LOGIC)
80 continue;
81 if (!ch->enabled)
82 continue;
83 ctx->num_enabled_channels++;
84 }
85 ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
86 ctx->channel_names = g_malloc(sizeof(char *) * ctx->num_enabled_channels);
87 ctx->lines = g_malloc(sizeof(GString *) * ctx->num_enabled_channels);
88 ctx->sample_buf = g_malloc(ctx->num_enabled_channels);
89
90 j = 0;
91 for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
92 ch = l->data;
93 if (ch->type != SR_CHANNEL_LOGIC)
94 continue;
95 if (!ch->enabled)
96 continue;
97 ctx->channel_index[j] = ch->index;
98 ctx->channel_names[j] = ch->name;
99 ctx->lines[j] = g_string_sized_new(80);
100 ctx->sample_buf[j] = 0;
101 g_string_printf(ctx->lines[j], "%s:", ch->name);
102 j++;
103 }
104
7bcbbfae
BV
105 return SR_OK;
106}
107
108static GString *gen_header(struct sr_output *o)
109{
110 struct context *ctx;
111 GVariant *gvar;
112 GString *header;
113 int num_channels;
114 char *samplerate_s;
115
116 ctx = o->internal;
117 if (ctx->samplerate == 0) {
118 if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
119 &gvar) == SR_OK) {
120 ctx->samplerate = g_variant_get_uint64(gvar);
121 g_variant_unref(gvar);
122 }
123 }
124
125 header = g_string_sized_new(512);
126 g_string_printf(header, "%s\n", PACKAGE_STRING);
8d3af2e8 127 num_channels = g_slist_length(o->sdi->channels);
7bcbbfae
BV
128 g_string_append_printf(header, "Acquisition with %d/%d channels",
129 ctx->num_enabled_channels, num_channels);
130 if (ctx->samplerate != 0) {
131 samplerate_s = sr_samplerate_string(ctx->samplerate);
132 g_string_append_printf(header, " at %s", samplerate_s);
8d3af2e8 133 g_free(samplerate_s);
8d3af2e8 134 }
7bcbbfae 135 g_string_append_printf(header, "\n");
8d3af2e8 136
7bcbbfae 137 return header;
8d3af2e8
BV
138}
139
dba3e682
BV
140static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
141 GString **out)
8d3af2e8 142{
7bcbbfae 143 const struct sr_datafeed_meta *meta;
8d3af2e8 144 const struct sr_datafeed_logic *logic;
7bcbbfae
BV
145 const struct sr_config *src;
146 GSList *l;
8d3af2e8
BV
147 struct context *ctx;
148 int idx, pos, offset;
149 uint64_t i, j;
150 gchar *p;
151
8d3af2e8
BV
152 *out = NULL;
153 if (!o || !o->sdi)
154 return SR_ERR_ARG;
155 if (!(ctx = o->internal))
156 return SR_ERR_ARG;
157
158 switch (packet->type) {
7bcbbfae
BV
159 case SR_DF_META:
160 meta = packet->payload;
161 for (l = meta->config; l; l = l->next) {
162 src = l->data;
163 if (src->key != SR_CONF_SAMPLERATE)
164 continue;
165 ctx->samplerate = g_variant_get_uint64(src->data);
166 }
167 break;
8d3af2e8
BV
168 case SR_DF_TRIGGER:
169 ctx->trigger = ctx->spl_cnt;
170 break;
171 case SR_DF_LOGIC:
7bcbbfae
BV
172 if (!ctx->header_done) {
173 *out = gen_header(o);
174 ctx->header_done = TRUE;
8d3af2e8
BV
175 } else
176 *out = g_string_sized_new(512);
177
178 logic = packet->payload;
179 for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
180 ctx->spl_cnt++;
181 pos = ctx->spl_cnt & 7;
182 for (j = 0; j < ctx->num_enabled_channels; j++) {
183 idx = ctx->channel_index[j];
184 p = logic->data + i + idx / 8;
185 ctx->sample_buf[j] <<= 1;
186 if (*p & (1 << (idx % 8)))
187 ctx->sample_buf[j] |= 1;
188 if (ctx->spl_cnt && pos == 0) {
189 /* Buffered a byte's worth, output hex. */
190 g_string_append_printf(ctx->lines[j], "%.2x ",
191 ctx->sample_buf[j]);
192 ctx->sample_buf[j] = 0;
193 }
194
195 if (ctx->spl_cnt == ctx->samples_per_line) {
196 /* Flush line buffers. */
197 g_string_append_len(*out, ctx->lines[j]->str, ctx->lines[j]->len);
198 g_string_append_c(*out, '\n');
199 if (j == ctx->num_enabled_channels - 1 && ctx->trigger > -1) {
200 offset = ctx->trigger + ctx->trigger / 8;
201 g_string_append_printf(*out, "T:%*s^ %d\n", offset, "", ctx->trigger);
202 ctx->trigger = -1;
203 }
204 g_string_printf(ctx->lines[j], "%s:", ctx->channel_names[j]);
205 }
206 }
207 if (ctx->spl_cnt == ctx->samples_per_line)
208 /* Line buffers were already flushed. */
209 ctx->spl_cnt = 0;
210 }
211 break;
212 case SR_DF_END:
213 if (ctx->spl_cnt) {
214 /* Line buffers need flushing. */
215 *out = g_string_sized_new(512);
216 for (i = 0; i < ctx->num_enabled_channels; i++) {
217 if (ctx->spl_cnt & 7)
218 g_string_append_printf(ctx->lines[i], "%.2x ",
219 ctx->sample_buf[i] << (8 - (ctx->spl_cnt & 7)));
220 g_string_append_len(*out, ctx->lines[i]->str, ctx->lines[i]->len);
221 g_string_append_c(*out, '\n');
222 }
223 }
224 break;
225 }
226
227 return SR_OK;
228}
229
230static int cleanup(struct sr_output *o)
231{
232 struct context *ctx;
233 unsigned int i;
234
235 if (!o)
236 return SR_ERR_ARG;
237
238 if (!(ctx = o->internal))
239 return SR_OK;
240
8d3af2e8
BV
241 g_free(ctx->channel_index);
242 g_free(ctx->sample_buf);
243 g_free(ctx->channel_names);
244 for (i = 0; i < ctx->num_enabled_channels; i++)
245 g_string_free(ctx->lines[i], TRUE);
246 g_free(ctx->lines);
8d3af2e8
BV
247 g_free(ctx);
248 o->internal = NULL;
249
250 return SR_OK;
251}
252
253SR_PRIV struct sr_output_format output_hex = {
254 .id = "hex",
255 .description = "Hexadecimal",
256 .init = init,
257 .receive = receive,
258 .cleanup = cleanup,
259};
260