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