]> sigrok.org Git - libsigrok.git/blame_incremental - hardware/demo/demo.c
sr: Made the dev_info_get return value const
[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 "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 context {
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 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 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, void *value)
235{
236 int ret;
237 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 = *(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_samples = *(uint64_t *)value;
252 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
253 limit_samples);
254 ret = SR_OK;
255 } else if (hwcap == SR_HWCAP_LIMIT_MSEC) {
256 limit_msec = *(uint64_t *)value;
257 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
258 limit_msec);
259 ret = SR_OK;
260 } else if (hwcap == SR_HWCAP_PATTERN_MODE) {
261 stropt = value;
262 ret = SR_OK;
263 if (!strcmp(stropt, "sigrok")) {
264 default_pattern = PATTERN_SIGROK;
265 } else if (!strcmp(stropt, "random")) {
266 default_pattern = PATTERN_RANDOM;
267 } else if (!strcmp(stropt, "incremental")) {
268 default_pattern = PATTERN_INC;
269 } else if (!strcmp(stropt, "all-low")) {
270 default_pattern = PATTERN_ALL_LOW;
271 } else if (!strcmp(stropt, "all-high")) {
272 default_pattern = PATTERN_ALL_HIGH;
273 } else {
274 ret = SR_ERR;
275 }
276 sr_dbg("demo: %s: setting pattern to %d", __func__,
277 default_pattern);
278 } else {
279 ret = SR_ERR;
280 }
281
282 return ret;
283}
284
285static void samples_generator(uint8_t *buf, uint64_t size, void *data)
286{
287 static uint64_t p = 0;
288 struct context *ctx = data;
289 uint64_t i;
290
291 /* TODO: Needed? */
292 memset(buf, 0, size);
293
294 switch (ctx->sample_generator) {
295 case PATTERN_SIGROK: /* sigrok pattern */
296 for (i = 0; i < size; i++) {
297 *(buf + i) = ~(pattern_sigrok[p] >> 1);
298 if (++p == 64)
299 p = 0;
300 }
301 break;
302 case PATTERN_RANDOM: /* Random */
303 for (i = 0; i < size; i++)
304 *(buf + i) = (uint8_t)(rand() & 0xff);
305 break;
306 case PATTERN_INC: /* Simple increment */
307 for (i = 0; i < size; i++)
308 *(buf + i) = i;
309 break;
310 case PATTERN_ALL_LOW: /* All probes are low */
311 memset(buf, 0x00, size);
312 break;
313 case PATTERN_ALL_HIGH: /* All probes are high */
314 memset(buf, 0xff, size);
315 break;
316 default:
317 sr_err("demo: %s: unknown pattern %d", __func__,
318 ctx->sample_generator);
319 break;
320 }
321}
322
323/* Thread function */
324static void thread_func(void *data)
325{
326 struct context *ctx = data;
327 uint8_t buf[BUFSIZE];
328 uint64_t nb_to_send = 0;
329 int bytes_written;
330 double time_cur, time_last, time_diff;
331
332 time_last = g_timer_elapsed(ctx->timer, NULL);
333
334 while (thread_running) {
335 /* Rate control */
336 time_cur = g_timer_elapsed(ctx->timer, NULL);
337
338 time_diff = time_cur - time_last;
339 time_last = time_cur;
340
341 nb_to_send = cur_samplerate * time_diff;
342
343 if (limit_samples) {
344 nb_to_send = MIN(nb_to_send,
345 limit_samples - ctx->samples_counter);
346 }
347
348 /* Make sure we don't overflow. */
349 nb_to_send = MIN(nb_to_send, BUFSIZE);
350
351 if (nb_to_send) {
352 samples_generator(buf, nb_to_send, data);
353 ctx->samples_counter += nb_to_send;
354
355 g_io_channel_write_chars(channels[1], (gchar *)&buf,
356 nb_to_send, (gsize *)&bytes_written, NULL);
357 }
358
359 /* Check if we're done. */
360 if ((limit_msec && time_cur * 1000 > limit_msec) ||
361 (limit_samples && ctx->samples_counter >= limit_samples))
362 {
363 close(ctx->pipe_fds[1]);
364 thread_running = 0;
365 }
366
367 g_usleep(10);
368 }
369}
370
371/* Callback handling data */
372static int receive_data(int fd, int revents, void *cb_data)
373{
374 struct sr_datafeed_packet packet;
375 struct sr_datafeed_logic logic;
376 static uint64_t samples_received = 0;
377 unsigned char c[BUFSIZE];
378 gsize z;
379
380 /* Avoid compiler warnings. */
381 (void)fd;
382 (void)revents;
383
384 do {
385 g_io_channel_read_chars(channels[0],
386 (gchar *)&c, BUFSIZE, &z, NULL);
387
388 if (z > 0) {
389 packet.type = SR_DF_LOGIC;
390 packet.payload = &logic;
391 logic.length = z;
392 logic.unitsize = 1;
393 logic.data = c;
394 sr_session_send(cb_data, &packet);
395 samples_received += z;
396 }
397 } while (z > 0);
398
399 if (!thread_running && z <= 0) {
400 /* Make sure we don't receive more packets. */
401 g_io_channel_shutdown(channels[0], FALSE, NULL);
402
403 /* Send last packet. */
404 packet.type = SR_DF_END;
405 sr_session_send(cb_data, &packet);
406
407 return FALSE;
408 }
409
410 return TRUE;
411}
412
413static int hw_dev_acquisition_start(int dev_index, void *cb_data)
414{
415 struct sr_datafeed_packet *packet;
416 struct sr_datafeed_header *header;
417 struct sr_datafeed_meta_logic meta;
418 struct context *ctx;
419
420 /* TODO: 'ctx' is never g_free()'d? */
421 if (!(ctx = g_try_malloc(sizeof(struct context)))) {
422 sr_err("demo: %s: ctx malloc failed", __func__);
423 return SR_ERR_MALLOC;
424 }
425
426 ctx->sample_generator = default_pattern;
427 ctx->session_dev_id = cb_data;
428 ctx->dev_index = dev_index;
429 ctx->samples_counter = 0;
430
431 if (pipe(ctx->pipe_fds)) {
432 /* TODO: Better error message. */
433 sr_err("demo: %s: pipe() failed", __func__);
434 return SR_ERR;
435 }
436
437 channels[0] = g_io_channel_unix_new(ctx->pipe_fds[0]);
438 channels[1] = g_io_channel_unix_new(ctx->pipe_fds[1]);
439
440 /* Set channel encoding to binary (default is UTF-8). */
441 g_io_channel_set_encoding(channels[0], NULL, NULL);
442 g_io_channel_set_encoding(channels[1], NULL, NULL);
443
444 /* Make channels to unbuffered. */
445 g_io_channel_set_buffered(channels[0], FALSE);
446 g_io_channel_set_buffered(channels[1], FALSE);
447
448 sr_source_add(ctx->pipe_fds[0], G_IO_IN | G_IO_ERR, 40,
449 receive_data, ctx->session_dev_id);
450
451 /* Run the demo thread. */
452 g_thread_init(NULL);
453 /* This must to be done between g_thread_init() & g_thread_create(). */
454 ctx->timer = g_timer_new();
455 thread_running = 1;
456 my_thread =
457 g_thread_create((GThreadFunc)thread_func, ctx, TRUE, NULL);
458 if (!my_thread) {
459 sr_err("demo: %s: g_thread_create failed", __func__);
460 return SR_ERR; /* TODO */
461 }
462
463 if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
464 sr_err("demo: %s: packet malloc failed", __func__);
465 return SR_ERR_MALLOC;
466 }
467
468 if (!(header = g_try_malloc(sizeof(struct sr_datafeed_header)))) {
469 sr_err("demo: %s: header malloc failed", __func__);
470 return SR_ERR_MALLOC;
471 }
472
473 packet->type = SR_DF_HEADER;
474 packet->payload = header;
475 header->feed_version = 1;
476 gettimeofday(&header->starttime, NULL);
477 sr_session_send(ctx->session_dev_id, packet);
478
479 /* Send metadata about the SR_DF_LOGIC packets to come. */
480 packet->type = SR_DF_META_LOGIC;
481 packet->payload = &meta;
482 meta.samplerate = cur_samplerate;
483 meta.num_probes = NUM_PROBES;
484 sr_session_send(ctx->session_dev_id, packet);
485
486 g_free(header);
487 g_free(packet);
488
489 return SR_OK;
490}
491
492/* TODO: This stops acquisition on ALL devices, ignoring dev_index. */
493static int hw_dev_acquisition_stop(int dev_index, void *cb_data)
494{
495 /* Avoid compiler warnings. */
496 (void)dev_index;
497 (void)cb_data;
498
499 /* Stop generate thread. */
500 thread_running = 0;
501
502 return SR_OK;
503}
504
505SR_PRIV struct sr_dev_driver demo_driver_info = {
506 .name = "demo",
507 .longname = "Demo driver and pattern generator",
508 .api_version = 1,
509 .init = hw_init,
510 .cleanup = hw_cleanup,
511 .dev_open = hw_dev_open,
512 .dev_close = hw_dev_close,
513 .dev_info_get = hw_dev_info_get,
514 .dev_status_get = hw_dev_status_get,
515 .hwcap_get_all = hw_hwcap_get_all,
516 .dev_config_set = hw_dev_config_set,
517 .dev_acquisition_start = hw_dev_acquisition_start,
518 .dev_acquisition_stop = hw_dev_acquisition_stop,
519};