]> sigrok.org Git - libsigrok.git/blame_incremental - hardware/demo/demo.c
demo: Only one GIOChannel is needed
[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 * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <stdlib.h>
24#include <unistd.h>
25#include <string.h>
26#ifdef _WIN32
27#include <io.h>
28#include <fcntl.h>
29#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
30#endif
31#include "libsigrok.h"
32#include "libsigrok-internal.h"
33
34/* Message logging helpers with driver-specific prefix string. */
35#define DRIVER_LOG_DOMAIN "demo: "
36#define sr_log(l, s, args...) sr_log(l, DRIVER_LOG_DOMAIN s, ## args)
37#define sr_spew(s, args...) sr_spew(DRIVER_LOG_DOMAIN s, ## args)
38#define sr_dbg(s, args...) sr_dbg(DRIVER_LOG_DOMAIN s, ## args)
39#define sr_info(s, args...) sr_info(DRIVER_LOG_DOMAIN s, ## args)
40#define sr_warn(s, args...) sr_warn(DRIVER_LOG_DOMAIN s, ## args)
41#define sr_err(s, args...) sr_err(DRIVER_LOG_DOMAIN s, ## args)
42
43/* TODO: Number of probes should be configurable. */
44#define NUM_PROBES 8
45
46#define DEMONAME "Demo device"
47
48/* The size of chunks to send through the session bus. */
49/* TODO: Should be configurable. */
50#define BUFSIZE 4096
51
52#define STR_PATTERN_SIGROK "sigrok"
53#define STR_PATTERN_RANDOM "random"
54#define STR_PATTERN_INC "incremental"
55#define STR_PATTERN_ALL_LOW "all-low"
56#define STR_PATTERN_ALL_HIGH "all-high"
57
58/* Supported patterns which we can generate */
59enum {
60 /**
61 * Pattern which spells "sigrok" using '0's (with '1's as "background")
62 * when displayed using the 'bits' output format.
63 */
64 PATTERN_SIGROK,
65
66 /** Pattern which consists of (pseudo-)random values on all probes. */
67 PATTERN_RANDOM,
68
69 /**
70 * Pattern which consists of incrementing numbers.
71 * TODO: Better description.
72 */
73 PATTERN_INC,
74
75 /** Pattern where all probes have a low logic state. */
76 PATTERN_ALL_LOW,
77
78 /** Pattern where all probes have a high logic state. */
79 PATTERN_ALL_HIGH,
80};
81
82/* Private, per-device-instance driver context. */
83struct dev_context {
84 int pipe_fds[2];
85 GIOChannel *channel;
86 uint8_t sample_generator;
87 uint64_t samples_counter;
88 void *cb_data;
89 int64_t starttime;
90};
91
92static const int hwcaps[] = {
93 SR_CONF_LOGIC_ANALYZER,
94 SR_CONF_DEMO_DEV,
95 SR_CONF_SAMPLERATE,
96 SR_CONF_PATTERN_MODE,
97 SR_CONF_LIMIT_SAMPLES,
98 SR_CONF_LIMIT_MSEC,
99 SR_CONF_CONTINUOUS,
100};
101
102static const uint64_t samplerates[] = {
103 SR_HZ(1),
104 SR_GHZ(1),
105 SR_HZ(1),
106};
107
108static const char *pattern_strings[] = {
109 "sigrok",
110 "random",
111 "incremental",
112 "all-low",
113 "all-high",
114};
115
116/* We name the probes 0-7 on our demo driver. */
117static const char *probe_names[NUM_PROBES + 1] = {
118 "0", "1", "2", "3", "4", "5", "6", "7",
119 NULL,
120};
121
122static uint8_t pattern_sigrok[] = {
123 0x4c, 0x92, 0x92, 0x92, 0x64, 0x00, 0x00, 0x00,
124 0x82, 0xfe, 0xfe, 0x82, 0x00, 0x00, 0x00, 0x00,
125 0x7c, 0x82, 0x82, 0x92, 0x74, 0x00, 0x00, 0x00,
126 0xfe, 0x12, 0x12, 0x32, 0xcc, 0x00, 0x00, 0x00,
127 0x7c, 0x82, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00,
128 0xfe, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0xbe, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131};
132
133/* Private, per-device-instance driver context. */
134/* TODO: struct context as with the other drivers. */
135
136/* List of struct sr_dev_inst, maintained by dev_open()/dev_close(). */
137SR_PRIV struct sr_dev_driver demo_driver_info;
138static struct sr_dev_driver *di = &demo_driver_info;
139static uint64_t cur_samplerate = SR_KHZ(200);
140static uint64_t limit_samples = 0;
141static uint64_t limit_msec = 0;
142static int default_pattern = PATTERN_SIGROK;
143
144static int hw_dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
145
146static int clear_instances(void)
147{
148 /* Nothing needed so far. */
149
150 return SR_OK;
151}
152
153static int hw_init(struct sr_context *sr_ctx)
154{
155 return std_hw_init(sr_ctx, di, DRIVER_LOG_DOMAIN);
156}
157
158static GSList *hw_scan(GSList *options)
159{
160 struct sr_dev_inst *sdi;
161 struct sr_probe *probe;
162 struct drv_context *drvc;
163 GSList *devices;
164 int i;
165
166 (void)options;
167
168 drvc = di->priv;
169
170 devices = NULL;
171
172 sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
173 if (!sdi) {
174 sr_err("%s: sr_dev_inst_new failed", __func__);
175 return 0;
176 }
177 sdi->driver = di;
178
179 for (i = 0; probe_names[i]; i++) {
180 if (!(probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE,
181 probe_names[i])))
182 return NULL;
183 sdi->probes = g_slist_append(sdi->probes, probe);
184 }
185
186 devices = g_slist_append(devices, sdi);
187 drvc->instances = g_slist_append(drvc->instances, sdi);
188
189 return devices;
190}
191
192static GSList *hw_dev_list(void)
193{
194 return ((struct drv_context *)(di->priv))->instances;
195}
196
197static int hw_dev_open(struct sr_dev_inst *sdi)
198{
199 (void)sdi;
200
201 /* Nothing needed so far. */
202
203 return SR_OK;
204}
205
206static int hw_dev_close(struct sr_dev_inst *sdi)
207{
208 (void)sdi;
209
210 /* Nothing needed so far. */
211
212 return SR_OK;
213}
214
215static int hw_cleanup(void)
216{
217 /* Nothing needed so far. */
218 return SR_OK;
219}
220
221static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi)
222{
223 (void)sdi;
224
225 switch (id) {
226 case SR_CONF_SAMPLERATE:
227 *data = g_variant_new_uint64(cur_samplerate);
228 break;
229 case SR_CONF_LIMIT_SAMPLES:
230 *data = g_variant_new_uint64(limit_samples);
231 break;
232 case SR_CONF_LIMIT_MSEC:
233 *data = g_variant_new_uint64(limit_msec);
234 break;
235 case SR_CONF_PATTERN_MODE:
236 switch (default_pattern) {
237 case PATTERN_SIGROK:
238 *data = g_variant_new_string(STR_PATTERN_SIGROK);
239 break;
240 case PATTERN_RANDOM:
241 *data = g_variant_new_string(STR_PATTERN_RANDOM);
242 break;
243 case PATTERN_INC:
244 *data = g_variant_new_string(STR_PATTERN_INC);
245 break;
246 case PATTERN_ALL_LOW:
247 *data = g_variant_new_string(STR_PATTERN_ALL_LOW);
248 break;
249 case PATTERN_ALL_HIGH:
250 *data = g_variant_new_string(STR_PATTERN_ALL_HIGH);
251 break;
252 }
253 break;
254 default:
255 return SR_ERR_ARG;
256 }
257
258 return SR_OK;
259}
260
261static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi)
262{
263 int ret;
264 const char *stropt;
265
266 (void)sdi;
267
268 if (id == SR_CONF_SAMPLERATE) {
269 cur_samplerate = g_variant_get_uint64(data);
270 sr_dbg("%s: setting samplerate to %" PRIu64, __func__,
271 cur_samplerate);
272 ret = SR_OK;
273 } else if (id == SR_CONF_LIMIT_SAMPLES) {
274 limit_msec = 0;
275 limit_samples = g_variant_get_uint64(data);
276 sr_dbg("%s: setting limit_samples to %" PRIu64, __func__,
277 limit_samples);
278 ret = SR_OK;
279 } else if (id == SR_CONF_LIMIT_MSEC) {
280 limit_msec = g_variant_get_uint64(data);
281 limit_samples = 0;
282 sr_dbg("%s: setting limit_msec to %" PRIu64, __func__,
283 limit_msec);
284 ret = SR_OK;
285 } else if (id == SR_CONF_PATTERN_MODE) {
286 stropt = g_variant_get_string(data, NULL);
287 ret = SR_OK;
288 if (!strcmp(stropt, STR_PATTERN_SIGROK)) {
289 default_pattern = PATTERN_SIGROK;
290 } else if (!strcmp(stropt, STR_PATTERN_RANDOM)) {
291 default_pattern = PATTERN_RANDOM;
292 } else if (!strcmp(stropt, STR_PATTERN_INC)) {
293 default_pattern = PATTERN_INC;
294 } else if (!strcmp(stropt, STR_PATTERN_ALL_LOW)) {
295 default_pattern = PATTERN_ALL_LOW;
296 } else if (!strcmp(stropt, STR_PATTERN_ALL_HIGH)) {
297 default_pattern = PATTERN_ALL_HIGH;
298 } else {
299 ret = SR_ERR;
300 }
301 sr_dbg("%s: setting pattern to %d", __func__, default_pattern);
302 } else {
303 ret = SR_ERR;
304 }
305
306 return ret;
307}
308
309static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi)
310{
311 GVariant *gvar;
312 GVariantBuilder gvb;
313
314 (void)sdi;
315
316 switch (key) {
317 case SR_CONF_DEVICE_OPTIONS:
318 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
319 hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
320 break;
321 case SR_CONF_SAMPLERATE:
322 g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
323 gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
324 ARRAY_SIZE(samplerates), sizeof(uint64_t));
325 g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
326 *data = g_variant_builder_end(&gvb);
327 break;
328 case SR_CONF_PATTERN_MODE:
329 *data = g_variant_new_strv(pattern_strings, ARRAY_SIZE(pattern_strings));
330 break;
331 default:
332 return SR_ERR_ARG;
333 }
334
335 return SR_OK;
336}
337
338static void samples_generator(uint8_t *buf, uint64_t size,
339 struct dev_context *devc)
340{
341 static uint64_t p = 0;
342 uint64_t i;
343
344 /* TODO: Needed? */
345 memset(buf, 0, size);
346
347 switch (devc->sample_generator) {
348 case PATTERN_SIGROK: /* sigrok pattern */
349 for (i = 0; i < size; i++) {
350 *(buf + i) = ~(pattern_sigrok[
351 p++ % sizeof(pattern_sigrok)] >> 1);
352 }
353 break;
354 case PATTERN_RANDOM: /* Random */
355 for (i = 0; i < size; i++)
356 *(buf + i) = (uint8_t)(rand() & 0xff);
357 break;
358 case PATTERN_INC: /* Simple increment */
359 for (i = 0; i < size; i++)
360 *(buf + i) = p++;
361 break;
362 case PATTERN_ALL_LOW: /* All probes are low */
363 memset(buf, 0x00, size);
364 break;
365 case PATTERN_ALL_HIGH: /* All probes are high */
366 memset(buf, 0xff, size);
367 break;
368 default:
369 sr_err("Unknown pattern: %d.", devc->sample_generator);
370 break;
371 }
372}
373
374/* Callback handling data */
375static int receive_data(int fd, int revents, void *cb_data)
376{
377 struct dev_context *devc = cb_data;
378 struct sr_datafeed_packet packet;
379 struct sr_datafeed_logic logic;
380 uint8_t buf[BUFSIZE];
381 static uint64_t samples_to_send, expected_samplenum, sending_now;
382 int64_t time, elapsed;
383
384 (void)fd;
385 (void)revents;
386
387 /* How many "virtual" samples should we have collected by now? */
388 time = g_get_monotonic_time();
389 elapsed = time - devc->starttime;
390 expected_samplenum = elapsed * cur_samplerate / 1000000;
391 /* Of those, how many do we still have to send? */
392 samples_to_send = expected_samplenum - devc->samples_counter;
393
394 if (limit_samples) {
395 samples_to_send = MIN(samples_to_send,
396 limit_samples - devc->samples_counter);
397 }
398
399 while (samples_to_send > 0) {
400 sending_now = MIN(samples_to_send, sizeof(buf));
401 samples_to_send -= sending_now;
402 samples_generator(buf, sending_now, devc);
403
404 packet.type = SR_DF_LOGIC;
405 packet.payload = &logic;
406 logic.length = sending_now;
407 logic.unitsize = 1;
408 logic.data = buf;
409 sr_session_send(devc->cb_data, &packet);
410 devc->samples_counter += sending_now;
411 }
412
413 if (limit_samples && devc->samples_counter >= limit_samples) {
414 sr_info("Requested number of samples reached.");
415 hw_dev_acquisition_stop(NULL, cb_data);
416 return TRUE;
417 }
418
419 return TRUE;
420}
421
422static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi,
423 void *cb_data)
424{
425 struct dev_context *devc;
426
427 (void)sdi;
428
429 /* TODO: 'devc' is never g_free()'d? */
430 if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
431 sr_err("%s: devc malloc failed", __func__);
432 return SR_ERR_MALLOC;
433 }
434
435 devc->sample_generator = default_pattern;
436 devc->cb_data = cb_data;
437 devc->samples_counter = 0;
438
439 /*
440 * Setting two channels connected by a pipe is a remnant from when the
441 * demo driver generated data in a thread, and collected and sent the
442 * data in the main program loop.
443 * They are kept here because it provides a convenient way of setting
444 * up a timeout-based polling mechanism.
445 */
446 if (pipe(devc->pipe_fds)) {
447 /* TODO: Better error message. */
448 sr_err("%s: pipe() failed", __func__);
449 return SR_ERR;
450 }
451
452 devc->channel = g_io_channel_unix_new(devc->pipe_fds[0]);
453
454 g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL);
455
456 /* Set channel encoding to binary (default is UTF-8). */
457 g_io_channel_set_encoding(devc->channel, NULL, NULL);
458
459 /* Make channels to unbuffered. */
460 g_io_channel_set_buffered(devc->channel, FALSE);
461
462 sr_session_source_add_channel(devc->channel, G_IO_IN | G_IO_ERR,
463 40, receive_data, devc);
464
465 /* Send header packet to the session bus. */
466 std_session_send_df_header(cb_data, DRIVER_LOG_DOMAIN);
467
468 /* We use this timestamp to decide how many more samples to send. */
469 devc->starttime = g_get_monotonic_time();
470
471 return SR_OK;
472}
473
474static int hw_dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
475{
476 struct dev_context *devc;
477 struct sr_datafeed_packet packet;
478
479 (void)sdi;
480
481 devc = cb_data;
482
483 sr_dbg("Stopping aquisition.");
484
485 sr_session_source_remove_channel(devc->channel);
486 g_io_channel_shutdown(devc->channel, FALSE, NULL);
487
488 /* Send last packet. */
489 packet.type = SR_DF_END;
490 sr_session_send(devc->cb_data, &packet);
491
492 return SR_OK;
493}
494
495SR_PRIV struct sr_dev_driver demo_driver_info = {
496 .name = "demo",
497 .longname = "Demo driver and pattern generator",
498 .api_version = 1,
499 .init = hw_init,
500 .cleanup = hw_cleanup,
501 .scan = hw_scan,
502 .dev_list = hw_dev_list,
503 .dev_clear = clear_instances,
504 .config_get = config_get,
505 .config_set = config_set,
506 .config_list = config_list,
507 .dev_open = hw_dev_open,
508 .dev_close = hw_dev_close,
509 .dev_acquisition_start = hw_dev_acquisition_start,
510 .dev_acquisition_stop = hw_dev_acquisition_stop,
511 .priv = NULL,
512};