]> sigrok.org Git - libsigrok.git/blame_incremental - demo/demo.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / demo / demo.c
... / ...
CommitLineData
1/*
2 * This file is part of the sigrok project.
3 *
4 * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
5 * Copyright (C) 2011 Olivier Fauchon <olivier@aixmarseille.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#include <stdlib.h>
23#include <unistd.h>
24#include <string.h>
25#ifdef _WIN32
26#include <io.h>
27#include <fcntl.h>
28#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
29#endif
30#include "sigrok.h"
31#include "sigrok-internal.h"
32
33/* TODO: Number of probes should be configurable. */
34#define NUM_PROBES 8
35
36#define DEMONAME "Demo device"
37
38/* The size of chunks to send through the session bus. */
39/* TODO: Should be configurable. */
40#define BUFSIZE 4096
41
42/* Supported patterns which we can generate */
43enum {
44 /**
45 * Pattern which spells "sigrok" using '0's (with '1's as "background")
46 * when displayed using the 'bits' output format.
47 */
48 PATTERN_SIGROK,
49
50 /** Pattern which consists of (pseudo-)random values on all probes. */
51 PATTERN_RANDOM,
52
53 /**
54 * Pattern which consists of incrementing numbers.
55 * TODO: Better description.
56 */
57 PATTERN_INC,
58
59 /** Pattern where all probes have a low logic state. */
60 PATTERN_ALL_LOW,
61
62 /** Pattern where all probes have a high logic state. */
63 PATTERN_ALL_HIGH,
64};
65
66/* FIXME: Should not be global. */
67SR_PRIV GIOChannel *channels[2];
68
69struct databag {
70 int pipe_fds[2];
71 uint8_t sample_generator;
72 uint8_t thread_running;
73 uint64_t samples_counter;
74 int dev_index;
75 gpointer session_data;
76 GTimer *timer;
77};
78
79static int hwcaps[] = {
80 SR_HWCAP_LOGIC_ANALYZER,
81 SR_HWCAP_DEMO_DEV,
82 SR_HWCAP_SAMPLERATE,
83 SR_HWCAP_PATTERN_MODE,
84 SR_HWCAP_LIMIT_SAMPLES,
85 SR_HWCAP_LIMIT_MSEC,
86 SR_HWCAP_CONTINUOUS,
87};
88
89static struct sr_samplerates samplerates = {
90 SR_HZ(1),
91 SR_GHZ(1),
92 SR_HZ(1),
93 NULL,
94};
95
96static const char *pattern_strings[] = {
97 "sigrok",
98 "random",
99 "incremental",
100 "all-low",
101 "all-high",
102 NULL,
103};
104
105static const char *probe_names[NUM_PROBES + 1] = {
106 "0",
107 "1",
108 "2",
109 "3",
110 "4",
111 "5",
112 "6",
113 "7",
114 NULL,
115};
116
117static uint8_t pattern_sigrok[] = {
118 0x4c, 0x92, 0x92, 0x92, 0x64, 0x00, 0x00, 0x00,
119 0x82, 0xfe, 0xfe, 0x82, 0x00, 0x00, 0x00, 0x00,
120 0x7c, 0x82, 0x82, 0x92, 0x74, 0x00, 0x00, 0x00,
121 0xfe, 0x12, 0x12, 0x32, 0xcc, 0x00, 0x00, 0x00,
122 0x7c, 0x82, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00,
123 0xfe, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0xbe, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126};
127
128/* Private, per-device-instance driver context. */
129/* TODO: struct context as with the other drivers. */
130
131/* List of struct sr_dev_inst, maintained by dev_open()/dev_close(). */
132static GSList *dev_insts = NULL;
133static uint64_t cur_samplerate = SR_KHZ(200);
134static uint64_t limit_samples = 0;
135static uint64_t limit_msec = 0;
136static int default_pattern = PATTERN_SIGROK;
137static GThread *my_thread;
138static int thread_running;
139
140static int hw_dev_acquisition_stop(int dev_index, gpointer session_data);
141
142static int hw_init(const char *devinfo)
143{
144 struct sr_dev_inst *sdi;
145
146 /* Avoid compiler warnings. */
147 (void)devinfo;
148
149 sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
150 if (!sdi) {
151 sr_err("demo: %s: sr_dev_inst_new failed", __func__);
152 return 0;
153 }
154
155 dev_insts = g_slist_append(dev_insts, sdi);
156
157 return 1;
158}
159
160static int hw_dev_open(int dev_index)
161{
162 /* Avoid compiler warnings. */
163 (void)dev_index;
164
165 /* Nothing needed so far. */
166
167 return SR_OK;
168}
169
170static int hw_dev_close(int dev_index)
171{
172 /* Avoid compiler warnings. */
173 (void)dev_index;
174
175 /* Nothing needed so far. */
176
177 return SR_OK;
178}
179
180static int hw_cleanup(void)
181{
182 /* Nothing needed so far. */
183 return SR_OK;
184}
185
186static void *hw_dev_info_get(int dev_index, int dev_info_id)
187{
188 struct sr_dev_inst *sdi;
189 void *info = NULL;
190
191 if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) {
192 sr_err("demo: %s: sdi was NULL", __func__);
193 return NULL;
194 }
195
196 switch (dev_info_id) {
197 case SR_DI_INST:
198 info = sdi;
199 break;
200 case SR_DI_NUM_PROBES:
201 info = GINT_TO_POINTER(NUM_PROBES);
202 break;
203 case SR_DI_PROBE_NAMES:
204 info = probe_names;
205 break;
206 case SR_DI_SAMPLERATES:
207 info = &samplerates;
208 break;
209 case SR_DI_CUR_SAMPLERATE:
210 info = &cur_samplerate;
211 break;
212 case SR_DI_PATTERNMODES:
213 info = &pattern_strings;
214 break;
215 }
216
217 return info;
218}
219
220static int hw_dev_status_get(int dev_index)
221{
222 /* Avoid compiler warnings. */
223 (void)dev_index;
224
225 return SR_ST_ACTIVE;
226}
227
228static int *hw_hwcap_get_all(void)
229{
230 return hwcaps;
231}
232
233static int hw_dev_config_set(int dev_index, int hwcap, void *value)
234{
235 int ret;
236 char *stropt;
237
238 /* Avoid compiler warnings. */
239 (void)dev_index;
240
241 if (hwcap == SR_HWCAP_PROBECONFIG) {
242 /* Nothing to do, but must be supported */
243 ret = SR_OK;
244 } else if (hwcap == SR_HWCAP_SAMPLERATE) {
245 cur_samplerate = *(uint64_t *)value;
246 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
247 cur_samplerate);
248 ret = SR_OK;
249 } else if (hwcap == SR_HWCAP_LIMIT_SAMPLES) {
250 limit_samples = *(uint64_t *)value;
251 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
252 limit_samples);
253 ret = SR_OK;
254 } else if (hwcap == SR_HWCAP_LIMIT_MSEC) {
255 limit_msec = *(uint64_t *)value;
256 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
257 limit_msec);
258 ret = SR_OK;
259 } else if (hwcap == SR_HWCAP_PATTERN_MODE) {
260 stropt = value;
261 ret = SR_OK;
262 if (!strcmp(stropt, "sigrok")) {
263 default_pattern = PATTERN_SIGROK;
264 } else if (!strcmp(stropt, "random")) {
265 default_pattern = PATTERN_RANDOM;
266 } else if (!strcmp(stropt, "incremental")) {
267 default_pattern = PATTERN_INC;
268 } else if (!strcmp(stropt, "all-low")) {
269 default_pattern = PATTERN_ALL_LOW;
270 } else if (!strcmp(stropt, "all-high")) {
271 default_pattern = PATTERN_ALL_HIGH;
272 } else {
273 ret = SR_ERR;
274 }
275 sr_dbg("demo: %s: setting pattern to %d", __func__,
276 default_pattern);
277 } else {
278 ret = SR_ERR;
279 }
280
281 return ret;
282}
283
284static void samples_generator(uint8_t *buf, uint64_t size, void *data)
285{
286 static uint64_t p = 0;
287 struct databag *mydata = data;
288 uint64_t i;
289
290 /* TODO: Needed? */
291 memset(buf, 0, size);
292
293 switch (mydata->sample_generator) {
294 case PATTERN_SIGROK: /* sigrok pattern */
295 for (i = 0; i < size; i++) {
296 *(buf + i) = ~(pattern_sigrok[p] >> 1);
297 if (++p == 64)
298 p = 0;
299 }
300 break;
301 case PATTERN_RANDOM: /* Random */
302 for (i = 0; i < size; i++)
303 *(buf + i) = (uint8_t)(rand() & 0xff);
304 break;
305 case PATTERN_INC: /* Simple increment */
306 for (i = 0; i < size; i++)
307 *(buf + i) = i;
308 break;
309 case PATTERN_ALL_LOW: /* All probes are low */
310 memset(buf, 0x00, size);
311 break;
312 case PATTERN_ALL_HIGH: /* All probes are high */
313 memset(buf, 0xff, size);
314 break;
315 default:
316 /* TODO: Error handling. */
317 break;
318 }
319}
320
321/* Thread function */
322static void thread_func(void *data)
323{
324 struct databag *mydata = data;
325 uint8_t buf[BUFSIZE];
326 uint64_t nb_to_send = 0;
327 int bytes_written;
328 double time_cur, time_last, time_diff;
329
330 time_last = g_timer_elapsed(mydata->timer, NULL);
331
332 while (thread_running) {
333 /* Rate control */
334 time_cur = g_timer_elapsed(mydata->timer, NULL);
335
336 time_diff = time_cur - time_last;
337 time_last = time_cur;
338
339 nb_to_send = cur_samplerate * time_diff;
340
341 if (limit_samples) {
342 nb_to_send = MIN(nb_to_send,
343 limit_samples - mydata->samples_counter);
344 }
345
346 /* Make sure we don't overflow. */
347 nb_to_send = MIN(nb_to_send, BUFSIZE);
348
349 if (nb_to_send) {
350 samples_generator(buf, nb_to_send, data);
351 mydata->samples_counter += nb_to_send;
352
353 g_io_channel_write_chars(channels[1], (gchar *)&buf,
354 nb_to_send, (gsize *)&bytes_written, NULL);
355 }
356
357 /* Check if we're done. */
358 if ((limit_msec && time_cur * 1000 > limit_msec) ||
359 (limit_samples && mydata->samples_counter >= limit_samples))
360 {
361 close(mydata->pipe_fds[1]);
362 thread_running = 0;
363 }
364
365 g_usleep(10);
366 }
367}
368
369/* Callback handling data */
370static int receive_data(int fd, int revents, void *session_data)
371{
372 struct sr_datafeed_packet packet;
373 struct sr_datafeed_logic logic;
374 static uint64_t samples_received = 0;
375 unsigned char c[BUFSIZE];
376 gsize z;
377
378 /* Avoid compiler warnings. */
379 (void)fd;
380 (void)revents;
381
382 do {
383 g_io_channel_read_chars(channels[0],
384 (gchar *)&c, BUFSIZE, &z, NULL);
385
386 if (z > 0) {
387 packet.type = SR_DF_LOGIC;
388 packet.payload = &logic;
389 logic.length = z;
390 logic.unitsize = 1;
391 logic.data = c;
392 sr_session_bus(session_data, &packet);
393 samples_received += z;
394 }
395 } while (z > 0);
396
397 if (!thread_running && z <= 0) {
398 /* Make sure we don't receive more packets. */
399 g_io_channel_close(channels[0]);
400
401 /* Send last packet. */
402 packet.type = SR_DF_END;
403 sr_session_bus(session_data, &packet);
404
405 return FALSE;
406 }
407
408 return TRUE;
409}
410
411static int hw_dev_acquisition_start(int dev_index, gpointer session_data)
412{
413 struct sr_datafeed_packet *packet;
414 struct sr_datafeed_header *header;
415 struct databag *mydata;
416
417 /* TODO: 'mydata' is never g_free()'d? */
418 if (!(mydata = g_try_malloc(sizeof(struct databag)))) {
419 sr_err("demo: %s: mydata malloc failed", __func__);
420 return SR_ERR_MALLOC;
421 }
422
423 mydata->sample_generator = default_pattern;
424 mydata->session_data = session_data;
425 mydata->dev_index = dev_index;
426 mydata->samples_counter = 0;
427
428 if (pipe(mydata->pipe_fds)) {
429 /* TODO: Better error message. */
430 sr_err("demo: %s: pipe() failed", __func__);
431 return SR_ERR;
432 }
433
434 channels[0] = g_io_channel_unix_new(mydata->pipe_fds[0]);
435 channels[1] = g_io_channel_unix_new(mydata->pipe_fds[1]);
436
437 /* Set channel encoding to binary (default is UTF-8). */
438 g_io_channel_set_encoding(channels[0], NULL, NULL);
439 g_io_channel_set_encoding(channels[1], NULL, NULL);
440
441 /* Make channels to unbuffered. */
442 g_io_channel_set_buffered(channels[0], FALSE);
443 g_io_channel_set_buffered(channels[1], FALSE);
444
445 sr_source_add(mydata->pipe_fds[0], G_IO_IN | G_IO_ERR, 40,
446 receive_data, session_data);
447
448 /* Run the demo thread. */
449 g_thread_init(NULL);
450 /* This must to be done between g_thread_init() & g_thread_create(). */
451 mydata->timer = g_timer_new();
452 thread_running = 1;
453 my_thread =
454 g_thread_create((GThreadFunc)thread_func, mydata, TRUE, NULL);
455 if (!my_thread) {
456 sr_err("demo: %s: g_thread_create failed", __func__);
457 return SR_ERR; /* TODO */
458 }
459
460 if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
461 sr_err("demo: %s: packet malloc failed", __func__);
462 return SR_ERR_MALLOC;
463 }
464
465 if (!(header = g_try_malloc(sizeof(struct sr_datafeed_header)))) {
466 sr_err("demo: %s: header malloc failed", __func__);
467 return SR_ERR_MALLOC;
468 }
469
470 packet->type = SR_DF_HEADER;
471 packet->payload = header;
472 header->feed_version = 1;
473 gettimeofday(&header->starttime, NULL);
474 header->samplerate = cur_samplerate;
475 header->num_logic_probes = NUM_PROBES;
476 sr_session_bus(session_data, packet);
477 g_free(header);
478 g_free(packet);
479
480 return SR_OK;
481}
482
483static int hw_dev_acquisition_stop(int dev_index, gpointer session_data)
484{
485 /* Avoid compiler warnings. */
486 (void)dev_index;
487 (void)session_data;
488
489 /* Stop generate thread. */
490 thread_running = 0;
491
492 return SR_OK;
493}
494
495SR_PRIV struct sr_dev_plugin demo_plugin_info = {
496 .name = "demo",
497 .longname = "Demo driver and pattern generator",
498 .api_version = 1,
499 .init = hw_init,
500 .cleanup = hw_cleanup,
501 .dev_open = hw_dev_open,
502 .dev_close = hw_dev_close,
503 .dev_info_get = hw_dev_info_get,
504 .dev_status_get = hw_dev_status_get,
505 .hwcap_get_all = hw_hwcap_get_all,
506 .dev_config_set = hw_dev_config_set,
507 .dev_acquisition_start = hw_dev_acquisition_start,
508 .dev_acquisition_stop = hw_dev_acquisition_stop,
509};