]> sigrok.org Git - libsigrok.git/blame_incremental - hardware/demo/demo.c
sr/drivers: change driver dev_acquisition_start/_stop calls to use sdi
[libsigrok.git] / hardware / 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 "libsigrok.h"
31#include "libsigrok-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. */
67
68struct context {
69 int pipe_fds[2];
70 GIOChannel *channels[2];
71 uint8_t sample_generator;
72 uint8_t thread_running;
73 uint64_t samples_counter;
74 void *session_dev_id;
75 GTimer *timer;
76};
77
78static const int hwcaps[] = {
79 SR_HWCAP_LOGIC_ANALYZER,
80 SR_HWCAP_DEMO_DEV,
81 SR_HWCAP_SAMPLERATE,
82 SR_HWCAP_PATTERN_MODE,
83 SR_HWCAP_LIMIT_SAMPLES,
84 SR_HWCAP_LIMIT_MSEC,
85 SR_HWCAP_CONTINUOUS,
86};
87
88static const struct sr_samplerates samplerates = {
89 SR_HZ(1),
90 SR_GHZ(1),
91 SR_HZ(1),
92 NULL,
93};
94
95static const char *pattern_strings[] = {
96 "sigrok",
97 "random",
98 "incremental",
99 "all-low",
100 "all-high",
101 NULL,
102};
103
104/* We name the probes 0-7 on our demo driver. */
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(). */
132SR_PRIV struct sr_dev_driver demo_driver_info;
133static struct sr_dev_driver *ddi = &demo_driver_info;
134static uint64_t cur_samplerate = SR_KHZ(200);
135static uint64_t limit_samples = 0;
136static uint64_t limit_msec = 0;
137static int default_pattern = PATTERN_SIGROK;
138static GThread *my_thread;
139static int thread_running;
140
141static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi,
142 void *cb_data);
143
144static int hw_init(void)
145{
146
147 /* Nothing to do. */
148
149 return SR_OK;
150}
151
152static GSList *hw_scan(GSList *options)
153{
154 struct sr_dev_inst *sdi;
155 GSList *devices;
156
157 (void)options;
158 devices = NULL;
159
160 sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
161 if (!sdi) {
162 sr_err("demo: %s: sr_dev_inst_new failed", __func__);
163 return 0;
164 }
165 sdi->driver = ddi;
166
167 devices = g_slist_append(devices, sdi);
168 ddi->instances = g_slist_append(ddi->instances, sdi);
169
170 return devices;
171}
172
173static int hw_dev_open(struct sr_dev_inst *sdi)
174{
175 /* Avoid compiler warnings. */
176 (void)sdi;
177
178 /* Nothing needed so far. */
179
180 return SR_OK;
181}
182
183static int hw_dev_close(struct sr_dev_inst *sdi)
184{
185 /* Avoid compiler warnings. */
186 (void)sdi;
187
188 /* Nothing needed so far. */
189
190 return SR_OK;
191}
192
193static int hw_cleanup(void)
194{
195 /* Nothing needed so far. */
196 return SR_OK;
197}
198
199static int hw_info_get(int info_id, const void **data,
200 const struct sr_dev_inst *sdi)
201{
202
203 switch (info_id) {
204 case SR_DI_INST:
205 *data = sdi;
206 break;
207 case SR_DI_HWCAPS:
208 *data = hwcaps;
209 break;
210 case SR_DI_NUM_PROBES:
211 *data = GINT_TO_POINTER(NUM_PROBES);
212 break;
213 case SR_DI_PROBE_NAMES:
214 *data = probe_names;
215 break;
216 case SR_DI_SAMPLERATES:
217 *data = &samplerates;
218 break;
219 case SR_DI_CUR_SAMPLERATE:
220 *data = &cur_samplerate;
221 break;
222 case SR_DI_PATTERNS:
223 *data = &pattern_strings;
224 break;
225 default:
226 return SR_ERR_ARG;
227 }
228
229 return SR_OK;
230}
231
232static int hw_dev_status_get(int dev_index)
233{
234 /* Avoid compiler warnings. */
235 (void)dev_index;
236
237 return SR_ST_ACTIVE;
238}
239
240static int hw_dev_config_set(const struct sr_dev_inst *sdi, int hwcap,
241 const void *value)
242{
243 int ret;
244 const char *stropt;
245
246 (void)sdi;
247
248 if (hwcap == SR_HWCAP_PROBECONFIG) {
249 /* Nothing to do, but must be supported */
250 ret = SR_OK;
251 } else if (hwcap == SR_HWCAP_SAMPLERATE) {
252 cur_samplerate = *(const uint64_t *)value;
253 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
254 cur_samplerate);
255 ret = SR_OK;
256 } else if (hwcap == SR_HWCAP_LIMIT_SAMPLES) {
257 limit_msec = 0;
258 limit_samples = *(const uint64_t *)value;
259 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
260 limit_samples);
261 ret = SR_OK;
262 } else if (hwcap == SR_HWCAP_LIMIT_MSEC) {
263 limit_msec = *(const uint64_t *)value;
264 limit_samples = 0;
265 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
266 limit_msec);
267 ret = SR_OK;
268 } else if (hwcap == SR_HWCAP_PATTERN_MODE) {
269 stropt = value;
270 ret = SR_OK;
271 if (!strcmp(stropt, "sigrok")) {
272 default_pattern = PATTERN_SIGROK;
273 } else if (!strcmp(stropt, "random")) {
274 default_pattern = PATTERN_RANDOM;
275 } else if (!strcmp(stropt, "incremental")) {
276 default_pattern = PATTERN_INC;
277 } else if (!strcmp(stropt, "all-low")) {
278 default_pattern = PATTERN_ALL_LOW;
279 } else if (!strcmp(stropt, "all-high")) {
280 default_pattern = PATTERN_ALL_HIGH;
281 } else {
282 ret = SR_ERR;
283 }
284 sr_dbg("demo: %s: setting pattern to %d", __func__,
285 default_pattern);
286 } else {
287 ret = SR_ERR;
288 }
289
290 return ret;
291}
292
293static void samples_generator(uint8_t *buf, uint64_t size, void *data)
294{
295 static uint64_t p = 0;
296 struct context *ctx = data;
297 uint64_t i;
298
299 /* TODO: Needed? */
300 memset(buf, 0, size);
301
302 switch (ctx->sample_generator) {
303 case PATTERN_SIGROK: /* sigrok pattern */
304 for (i = 0; i < size; i++) {
305 *(buf + i) = ~(pattern_sigrok[p] >> 1);
306 if (++p == 64)
307 p = 0;
308 }
309 break;
310 case PATTERN_RANDOM: /* Random */
311 for (i = 0; i < size; i++)
312 *(buf + i) = (uint8_t)(rand() & 0xff);
313 break;
314 case PATTERN_INC: /* Simple increment */
315 for (i = 0; i < size; i++)
316 *(buf + i) = i;
317 break;
318 case PATTERN_ALL_LOW: /* All probes are low */
319 memset(buf, 0x00, size);
320 break;
321 case PATTERN_ALL_HIGH: /* All probes are high */
322 memset(buf, 0xff, size);
323 break;
324 default:
325 sr_err("demo: %s: unknown pattern %d", __func__,
326 ctx->sample_generator);
327 break;
328 }
329}
330
331/* Thread function */
332static void thread_func(void *data)
333{
334 struct context *ctx = data;
335 uint8_t buf[BUFSIZE];
336 uint64_t nb_to_send = 0;
337 int bytes_written;
338 double time_cur, time_last, time_diff;
339
340 time_last = g_timer_elapsed(ctx->timer, NULL);
341
342 while (thread_running) {
343 /* Rate control */
344 time_cur = g_timer_elapsed(ctx->timer, NULL);
345
346 time_diff = time_cur - time_last;
347 time_last = time_cur;
348
349 nb_to_send = cur_samplerate * time_diff;
350
351 if (limit_samples) {
352 nb_to_send = MIN(nb_to_send,
353 limit_samples - ctx->samples_counter);
354 }
355
356 /* Make sure we don't overflow. */
357 nb_to_send = MIN(nb_to_send, BUFSIZE);
358
359 if (nb_to_send) {
360 samples_generator(buf, nb_to_send, data);
361 ctx->samples_counter += nb_to_send;
362
363 g_io_channel_write_chars(ctx->channels[1], (gchar *)&buf,
364 nb_to_send, (gsize *)&bytes_written, NULL);
365 }
366
367 /* Check if we're done. */
368 if ((limit_msec && time_cur * 1000 > limit_msec) ||
369 (limit_samples && ctx->samples_counter >= limit_samples))
370 {
371 close(ctx->pipe_fds[1]);
372 thread_running = 0;
373 }
374
375 g_usleep(10);
376 }
377}
378
379/* Callback handling data */
380static int receive_data(int fd, int revents, void *cb_data)
381{
382 struct context *ctx = cb_data;
383 struct sr_datafeed_packet packet;
384 struct sr_datafeed_logic logic;
385 static uint64_t samples_received = 0;
386 unsigned char c[BUFSIZE];
387 gsize z;
388
389 /* Avoid compiler warnings. */
390 (void)fd;
391 (void)revents;
392
393 do {
394 g_io_channel_read_chars(ctx->channels[0],
395 (gchar *)&c, BUFSIZE, &z, NULL);
396
397 if (z > 0) {
398 packet.type = SR_DF_LOGIC;
399 packet.payload = &logic;
400 logic.length = z;
401 logic.unitsize = 1;
402 logic.data = c;
403 sr_session_send(ctx->session_dev_id, &packet);
404 samples_received += z;
405 }
406 } while (z > 0);
407
408 if (!thread_running && z <= 0) {
409 /* Make sure we don't receive more packets. */
410 g_io_channel_shutdown(ctx->channels[0], FALSE, NULL);
411
412 /* Send last packet. */
413 packet.type = SR_DF_END;
414 sr_session_send(ctx->session_dev_id, &packet);
415
416 return FALSE;
417 }
418
419 return TRUE;
420}
421
422static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi,
423 void *cb_data)
424{
425 struct sr_datafeed_packet *packet;
426 struct sr_datafeed_header *header;
427 struct sr_datafeed_meta_logic meta;
428 struct context *ctx;
429
430 (void)sdi;
431
432 /* TODO: 'ctx' is never g_free()'d? */
433 if (!(ctx = g_try_malloc(sizeof(struct context)))) {
434 sr_err("demo: %s: ctx malloc failed", __func__);
435 return SR_ERR_MALLOC;
436 }
437
438 ctx->sample_generator = default_pattern;
439 ctx->session_dev_id = cb_data;
440 ctx->samples_counter = 0;
441
442 if (pipe(ctx->pipe_fds)) {
443 /* TODO: Better error message. */
444 sr_err("demo: %s: pipe() failed", __func__);
445 return SR_ERR;
446 }
447
448 ctx->channels[0] = g_io_channel_unix_new(ctx->pipe_fds[0]);
449 ctx->channels[1] = g_io_channel_unix_new(ctx->pipe_fds[1]);
450
451 g_io_channel_set_flags(ctx->channels[0], G_IO_FLAG_NONBLOCK, NULL);
452
453 /* Set channel encoding to binary (default is UTF-8). */
454 g_io_channel_set_encoding(ctx->channels[0], NULL, NULL);
455 g_io_channel_set_encoding(ctx->channels[1], NULL, NULL);
456
457 /* Make channels to unbuffered. */
458 g_io_channel_set_buffered(ctx->channels[0], FALSE);
459 g_io_channel_set_buffered(ctx->channels[1], FALSE);
460
461 sr_session_source_add_channel(ctx->channels[0], G_IO_IN | G_IO_ERR,
462 40, receive_data, ctx);
463
464 /* Run the demo thread. */
465 g_thread_init(NULL);
466 /* This must to be done between g_thread_init() & g_thread_create(). */
467 ctx->timer = g_timer_new();
468 thread_running = 1;
469 my_thread =
470 g_thread_create((GThreadFunc)thread_func, ctx, TRUE, NULL);
471 if (!my_thread) {
472 sr_err("demo: %s: g_thread_create failed", __func__);
473 return SR_ERR; /* TODO */
474 }
475
476 if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
477 sr_err("demo: %s: packet malloc failed", __func__);
478 return SR_ERR_MALLOC;
479 }
480
481 if (!(header = g_try_malloc(sizeof(struct sr_datafeed_header)))) {
482 sr_err("demo: %s: header malloc failed", __func__);
483 return SR_ERR_MALLOC;
484 }
485
486 packet->type = SR_DF_HEADER;
487 packet->payload = header;
488 header->feed_version = 1;
489 gettimeofday(&header->starttime, NULL);
490 sr_session_send(ctx->session_dev_id, packet);
491
492 /* Send metadata about the SR_DF_LOGIC packets to come. */
493 packet->type = SR_DF_META_LOGIC;
494 packet->payload = &meta;
495 meta.samplerate = cur_samplerate;
496 meta.num_probes = NUM_PROBES;
497 sr_session_send(ctx->session_dev_id, packet);
498
499 g_free(header);
500 g_free(packet);
501
502 return SR_OK;
503}
504
505static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi,
506 void *cb_data)
507{
508 /* Avoid compiler warnings. */
509 (void)sdi;
510 (void)cb_data;
511
512 /* Stop generate thread. */
513 thread_running = 0;
514
515 return SR_OK;
516}
517
518SR_PRIV struct sr_dev_driver demo_driver_info = {
519 .name = "demo",
520 .longname = "Demo driver and pattern generator",
521 .api_version = 1,
522 .init = hw_init,
523 .cleanup = hw_cleanup,
524 .scan = hw_scan,
525 .dev_open = hw_dev_open,
526 .dev_close = hw_dev_close,
527 .info_get = hw_info_get,
528 .dev_status_get = hw_dev_status_get,
529 .dev_config_set = hw_dev_config_set,
530 .dev_acquisition_start = hw_dev_acquisition_start,
531 .dev_acquisition_stop = hw_dev_acquisition_stop,
532 .instances = NULL,
533};