]> sigrok.org Git - libsigrok.git/blame_incremental - hardware/demo/demo.c
chronovu-la8: don't use deprecated hwcap_get_all() driver 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 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(int dev_index)
174{
175 /* Avoid compiler warnings. */
176 (void)dev_index;
177
178 /* Nothing needed so far. */
179
180 return SR_OK;
181}
182
183static int hw_dev_close(int dev_index)
184{
185 /* Avoid compiler warnings. */
186 (void)dev_index;
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_NUM_PROBES:
208 *data = GINT_TO_POINTER(NUM_PROBES);
209 break;
210 case SR_DI_PROBE_NAMES:
211 *data = probe_names;
212 break;
213 case SR_DI_SAMPLERATES:
214 *data = &samplerates;
215 break;
216 case SR_DI_CUR_SAMPLERATE:
217 *data = &cur_samplerate;
218 break;
219 case SR_DI_PATTERNS:
220 *data = &pattern_strings;
221 break;
222 default:
223 return SR_ERR_ARG;
224 }
225
226 return SR_OK;
227}
228
229static int hw_dev_status_get(int dev_index)
230{
231 /* Avoid compiler warnings. */
232 (void)dev_index;
233
234 return SR_ST_ACTIVE;
235}
236
237static const int *hw_hwcap_get_all(void)
238{
239 return hwcaps;
240}
241
242static int hw_dev_config_set(int dev_index, int hwcap, const void *value)
243{
244 int ret;
245 const char *stropt;
246
247 /* Avoid compiler warnings. */
248 (void)dev_index;
249
250 if (hwcap == SR_HWCAP_PROBECONFIG) {
251 /* Nothing to do, but must be supported */
252 ret = SR_OK;
253 } else if (hwcap == SR_HWCAP_SAMPLERATE) {
254 cur_samplerate = *(const uint64_t *)value;
255 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
256 cur_samplerate);
257 ret = SR_OK;
258 } else if (hwcap == SR_HWCAP_LIMIT_SAMPLES) {
259 limit_msec = 0;
260 limit_samples = *(const uint64_t *)value;
261 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
262 limit_samples);
263 ret = SR_OK;
264 } else if (hwcap == SR_HWCAP_LIMIT_MSEC) {
265 limit_msec = *(const uint64_t *)value;
266 limit_samples = 0;
267 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
268 limit_msec);
269 ret = SR_OK;
270 } else if (hwcap == SR_HWCAP_PATTERN_MODE) {
271 stropt = value;
272 ret = SR_OK;
273 if (!strcmp(stropt, "sigrok")) {
274 default_pattern = PATTERN_SIGROK;
275 } else if (!strcmp(stropt, "random")) {
276 default_pattern = PATTERN_RANDOM;
277 } else if (!strcmp(stropt, "incremental")) {
278 default_pattern = PATTERN_INC;
279 } else if (!strcmp(stropt, "all-low")) {
280 default_pattern = PATTERN_ALL_LOW;
281 } else if (!strcmp(stropt, "all-high")) {
282 default_pattern = PATTERN_ALL_HIGH;
283 } else {
284 ret = SR_ERR;
285 }
286 sr_dbg("demo: %s: setting pattern to %d", __func__,
287 default_pattern);
288 } else {
289 ret = SR_ERR;
290 }
291
292 return ret;
293}
294
295static void samples_generator(uint8_t *buf, uint64_t size, void *data)
296{
297 static uint64_t p = 0;
298 struct context *ctx = data;
299 uint64_t i;
300
301 /* TODO: Needed? */
302 memset(buf, 0, size);
303
304 switch (ctx->sample_generator) {
305 case PATTERN_SIGROK: /* sigrok pattern */
306 for (i = 0; i < size; i++) {
307 *(buf + i) = ~(pattern_sigrok[p] >> 1);
308 if (++p == 64)
309 p = 0;
310 }
311 break;
312 case PATTERN_RANDOM: /* Random */
313 for (i = 0; i < size; i++)
314 *(buf + i) = (uint8_t)(rand() & 0xff);
315 break;
316 case PATTERN_INC: /* Simple increment */
317 for (i = 0; i < size; i++)
318 *(buf + i) = i;
319 break;
320 case PATTERN_ALL_LOW: /* All probes are low */
321 memset(buf, 0x00, size);
322 break;
323 case PATTERN_ALL_HIGH: /* All probes are high */
324 memset(buf, 0xff, size);
325 break;
326 default:
327 sr_err("demo: %s: unknown pattern %d", __func__,
328 ctx->sample_generator);
329 break;
330 }
331}
332
333/* Thread function */
334static void thread_func(void *data)
335{
336 struct context *ctx = data;
337 uint8_t buf[BUFSIZE];
338 uint64_t nb_to_send = 0;
339 int bytes_written;
340 double time_cur, time_last, time_diff;
341
342 time_last = g_timer_elapsed(ctx->timer, NULL);
343
344 while (thread_running) {
345 /* Rate control */
346 time_cur = g_timer_elapsed(ctx->timer, NULL);
347
348 time_diff = time_cur - time_last;
349 time_last = time_cur;
350
351 nb_to_send = cur_samplerate * time_diff;
352
353 if (limit_samples) {
354 nb_to_send = MIN(nb_to_send,
355 limit_samples - ctx->samples_counter);
356 }
357
358 /* Make sure we don't overflow. */
359 nb_to_send = MIN(nb_to_send, BUFSIZE);
360
361 if (nb_to_send) {
362 samples_generator(buf, nb_to_send, data);
363 ctx->samples_counter += nb_to_send;
364
365 g_io_channel_write_chars(ctx->channels[1], (gchar *)&buf,
366 nb_to_send, (gsize *)&bytes_written, NULL);
367 }
368
369 /* Check if we're done. */
370 if ((limit_msec && time_cur * 1000 > limit_msec) ||
371 (limit_samples && ctx->samples_counter >= limit_samples))
372 {
373 close(ctx->pipe_fds[1]);
374 thread_running = 0;
375 }
376
377 g_usleep(10);
378 }
379}
380
381/* Callback handling data */
382static int receive_data(int fd, int revents, void *cb_data)
383{
384 struct context *ctx = cb_data;
385 struct sr_datafeed_packet packet;
386 struct sr_datafeed_logic logic;
387 static uint64_t samples_received = 0;
388 unsigned char c[BUFSIZE];
389 gsize z;
390
391 /* Avoid compiler warnings. */
392 (void)fd;
393 (void)revents;
394
395 do {
396 g_io_channel_read_chars(ctx->channels[0],
397 (gchar *)&c, BUFSIZE, &z, NULL);
398
399 if (z > 0) {
400 packet.type = SR_DF_LOGIC;
401 packet.payload = &logic;
402 logic.length = z;
403 logic.unitsize = 1;
404 logic.data = c;
405 sr_session_send(ctx->session_dev_id, &packet);
406 samples_received += z;
407 }
408 } while (z > 0);
409
410 if (!thread_running && z <= 0) {
411 /* Make sure we don't receive more packets. */
412 g_io_channel_shutdown(ctx->channels[0], FALSE, NULL);
413
414 /* Send last packet. */
415 packet.type = SR_DF_END;
416 sr_session_send(ctx->session_dev_id, &packet);
417
418 return FALSE;
419 }
420
421 return TRUE;
422}
423
424static int hw_dev_acquisition_start(int dev_index, void *cb_data)
425{
426 struct sr_datafeed_packet *packet;
427 struct sr_datafeed_header *header;
428 struct sr_datafeed_meta_logic meta;
429 struct context *ctx;
430
431 /* TODO: 'ctx' is never g_free()'d? */
432 if (!(ctx = g_try_malloc(sizeof(struct context)))) {
433 sr_err("demo: %s: ctx malloc failed", __func__);
434 return SR_ERR_MALLOC;
435 }
436
437 ctx->sample_generator = default_pattern;
438 ctx->session_dev_id = cb_data;
439 ctx->dev_index = dev_index;
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
505/* TODO: This stops acquisition on ALL devices, ignoring dev_index. */
506static int hw_dev_acquisition_stop(int dev_index, void *cb_data)
507{
508 /* Avoid compiler warnings. */
509 (void)dev_index;
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// .hwcap_get_all = hw_hwcap_get_all,
530 .dev_config_set = hw_dev_config_set,
531 .dev_acquisition_start = hw_dev_acquisition_start,
532 .dev_acquisition_stop = hw_dev_acquisition_stop,
533 .instances = NULL,
534};