]> sigrok.org Git - libsigrok.git/blob - src/output/chronovu_la8.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / output / chronovu_la8.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) 2014 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, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <glib.h>
25 #include <libsigrok/libsigrok.h>
26 #include "libsigrok-internal.h"
27
28 #define LOG_PREFIX "output/chronovu-la8"
29
30 struct context {
31         unsigned int num_enabled_channels;
32         gboolean triggered;
33         uint64_t samplerate;
34         uint64_t samplecount;
35         int *channel_index;
36         GString *pretrig_buf;
37 };
38
39 /**
40  * Check if the given samplerate is supported by the LA8 hardware.
41  *
42  * @param samplerate The samplerate (in Hz) to check.
43  *
44  * @return 1 if the samplerate is supported/valid, 0 otherwise.
45  */
46 static gboolean is_valid_samplerate(uint64_t samplerate)
47 {
48         unsigned int i;
49
50         for (i = 0; i < 255; i++) {
51                 if (samplerate == (SR_MHZ(100) / (i + 1)))
52                         return TRUE;
53         }
54
55         return FALSE;
56 }
57
58 /**
59  * Convert a samplerate (in Hz) to the 'divcount' value the LA8 wants.
60  *
61  * LA8 hardware: sample period = (divcount + 1) * 10ns.
62  * Min. value for divcount: 0x00 (10ns sample period, 100MHz samplerate).
63  * Max. value for divcount: 0xfe (2550ns sample period, 392.15kHz samplerate).
64  *
65  * @param samplerate The samplerate in Hz.
66  *
67  * @return The divcount value as needed by the hardware, or 0xff upon errors.
68  */
69 static uint8_t samplerate_to_divcount(uint64_t samplerate)
70 {
71         if (samplerate == 0 || !is_valid_samplerate(samplerate)) {
72                 sr_warn("Invalid samplerate (%" PRIu64 "Hz)", samplerate);
73                 return 0xff;
74         }
75
76         return (SR_MHZ(100) / samplerate) - 1;
77 }
78
79 static int init(struct sr_output *o, GHashTable *options)
80 {
81         struct context *ctx;
82         struct sr_channel *ch;
83         GSList *l;
84
85         (void)options;
86
87         if (!o || !o->sdi)
88                 return SR_ERR_ARG;
89
90         ctx = g_malloc0(sizeof(struct context));
91         o->priv = ctx;
92
93         for (l = o->sdi->channels; l; l = l->next) {
94                 ch = l->data;
95                 if (ch->type != SR_CHANNEL_LOGIC)
96                         continue;
97                 if (!ch->enabled)
98                         continue;
99                 ctx->num_enabled_channels++;
100         }
101         ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
102         ctx->pretrig_buf = g_string_sized_new(1024);
103
104         return SR_OK;
105 }
106
107 static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
108                 GString **out)
109 {
110         const struct sr_datafeed_logic *logic;
111         struct context *ctx;
112         GVariant *gvar;
113         uint64_t samplerate;
114         gchar c[4];
115
116         *out = NULL;
117         if (!o || !o->sdi)
118                 return SR_ERR_ARG;
119         if (!(ctx = o->priv))
120                 return SR_ERR_ARG;
121
122         switch (packet->type) {
123         case SR_DF_HEADER:
124                 /* One byte for the 'divcount' value. */
125                 if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
126                                 &gvar) == SR_OK) {
127                         samplerate = g_variant_get_uint64(gvar);
128                         g_variant_unref(gvar);
129                 } else
130                         samplerate = 0;
131                 c[0] = samplerate_to_divcount(samplerate);
132                 *out = g_string_new_len(c, 1);
133                 ctx->triggered = FALSE;
134                 break;
135         case SR_DF_TRIGGER:
136                 /* Four bytes (little endian) for the trigger point. */
137                 c[0] = ctx->samplecount & 0xff;
138                 c[1] = (ctx->samplecount >> 8) & 0xff;
139                 c[2] = (ctx->samplecount >> 16) & 0xff;
140                 c[3] = (ctx->samplecount >> 24) & 0xff;
141                 *out = g_string_new_len(c, 4);
142                 /* Flush the pre-trigger buffer. */
143                 if (ctx->pretrig_buf->len)
144                         g_string_append_len(*out, ctx->pretrig_buf->str,
145                                         ctx->pretrig_buf->len);
146                 ctx->triggered = TRUE;
147                 break;
148         case SR_DF_LOGIC:
149                 logic = packet->payload;
150                 if (!ctx->triggered)
151                         g_string_append_len(ctx->pretrig_buf, logic->data, logic->length);
152                 else
153                         *out = g_string_new_len(logic->data, logic->length);
154                 ctx->samplecount += logic->length / logic->unitsize;
155                 break;
156         case SR_DF_END:
157                 if (!ctx->triggered && ctx->pretrig_buf->len) {
158                         /* We never got a trigger, submit an empty one. */
159                         *out = g_string_sized_new(ctx->pretrig_buf->len + 4);
160                         g_string_append_len(*out, "\x00\x00\x00\x00", 4);
161                         g_string_append_len(*out, ctx->pretrig_buf->str, ctx->pretrig_buf->len);
162                 }
163                 break;
164         }
165
166         return SR_OK;
167 }
168
169 static int cleanup(struct sr_output *o)
170 {
171         struct context *ctx;
172
173         if (!o || !o->sdi)
174                 return SR_ERR_ARG;
175
176         if (o->priv) {
177                 ctx = o->priv;
178                 g_string_free(ctx->pretrig_buf, TRUE);
179                 g_free(ctx->channel_index);
180                 g_free(o->priv);
181                 o->priv = NULL;
182         }
183
184         return SR_OK;
185 }
186
187 SR_PRIV struct sr_output_module output_chronovu_la8 = {
188         .id = "chronovu-la8",
189         .name = "ChronoVu LA8",
190         .desc = "ChronoVu LA8 native file format data",
191         .exts = (const char*[]){"kdt", NULL},
192         .flags = 0,
193         .options = NULL,
194         .init = init,
195         .receive = receive,
196         .cleanup = cleanup,
197 };