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