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