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