]> sigrok.org Git - libsigrok.git/blame_incremental - hardware/demo/demo.c
Return SR_ERR_MALLOC upon allocation errors.
[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/* Private, per-device-instance driver context. */
67struct dev_context {
68 int pipe_fds[2];
69 GIOChannel *channels[2];
70 uint8_t sample_generator;
71 uint8_t thread_running;
72 uint64_t samples_counter;
73 void *session_dev_id;
74 GTimer *timer;
75};
76
77static const int hwcaps[] = {
78 SR_HWCAP_LOGIC_ANALYZER,
79 SR_HWCAP_DEMO_DEV,
80 SR_HWCAP_SAMPLERATE,
81 SR_HWCAP_PATTERN_MODE,
82 SR_HWCAP_LIMIT_SAMPLES,
83 SR_HWCAP_LIMIT_MSEC,
84 SR_HWCAP_CONTINUOUS,
85};
86
87static const struct sr_samplerates samplerates = {
88 SR_HZ(1),
89 SR_GHZ(1),
90 SR_HZ(1),
91 NULL,
92};
93
94static const char *pattern_strings[] = {
95 "sigrok",
96 "random",
97 "incremental",
98 "all-low",
99 "all-high",
100 NULL,
101};
102
103/* We name the probes 0-7 on our demo driver. */
104static const char *probe_names[NUM_PROBES + 1] = {
105 "0",
106 "1",
107 "2",
108 "3",
109 "4",
110 "5",
111 "6",
112 "7",
113 NULL,
114};
115
116static uint8_t pattern_sigrok[] = {
117 0x4c, 0x92, 0x92, 0x92, 0x64, 0x00, 0x00, 0x00,
118 0x82, 0xfe, 0xfe, 0x82, 0x00, 0x00, 0x00, 0x00,
119 0x7c, 0x82, 0x82, 0x92, 0x74, 0x00, 0x00, 0x00,
120 0xfe, 0x12, 0x12, 0x32, 0xcc, 0x00, 0x00, 0x00,
121 0x7c, 0x82, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00,
122 0xfe, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0xbe, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125};
126
127/* Private, per-device-instance driver context. */
128/* TODO: struct context as with the other drivers. */
129
130/* List of struct sr_dev_inst, maintained by dev_open()/dev_close(). */
131SR_PRIV struct sr_dev_driver demo_driver_info;
132static struct sr_dev_driver *ddi = &demo_driver_info;
133static uint64_t cur_samplerate = SR_KHZ(200);
134static uint64_t limit_samples = 0;
135static uint64_t limit_msec = 0;
136static int default_pattern = PATTERN_SIGROK;
137static GThread *my_thread;
138static int thread_running;
139
140static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi,
141 void *cb_data);
142
143static int hw_init(void)
144{
145 struct drv_context *drvc;
146
147 if (!(drvc = g_try_malloc0(sizeof(struct drv_context)))) {
148 sr_err("demo: driver context malloc failed.");
149 return SR_ERR_MALLOC;
150 }
151 ddi->priv = drvc;
152
153 return SR_OK;
154}
155
156static GSList *hw_scan(GSList *options)
157{
158 struct sr_dev_inst *sdi;
159 struct sr_probe *probe;
160 struct drv_context *drvc;
161 GSList *devices;
162 int i;
163
164 (void)options;
165 drvc = ddi->priv;
166 devices = NULL;
167
168 sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
169 if (!sdi) {
170 sr_err("demo: %s: sr_dev_inst_new failed", __func__);
171 return 0;
172 }
173 sdi->driver = ddi;
174
175 for (i = 0; probe_names[i]; i++) {
176 if (!(probe = sr_probe_new(i, SR_PROBE_ANALOG, TRUE,
177 probe_names[i])))
178 return NULL;
179 sdi->probes = g_slist_append(sdi->probes, probe);
180 }
181
182 devices = g_slist_append(devices, sdi);
183 drvc->instances = g_slist_append(drvc->instances, sdi);
184
185 return devices;
186}
187
188static GSList *hw_dev_list(void)
189{
190 struct drv_context *drvc;
191
192 drvc = ddi->priv;
193
194 return drvc->instances;
195}
196
197static int hw_dev_open(struct sr_dev_inst *sdi)
198{
199 /* Avoid compiler warnings. */
200 (void)sdi;
201
202 /* Nothing needed so far. */
203
204 return SR_OK;
205}
206
207static int hw_dev_close(struct sr_dev_inst *sdi)
208{
209 /* Avoid compiler warnings. */
210 (void)sdi;
211
212 /* Nothing needed so far. */
213
214 return SR_OK;
215}
216
217static int hw_cleanup(void)
218{
219 /* Nothing needed so far. */
220 return SR_OK;
221}
222
223static int hw_info_get(int info_id, const void **data,
224 const struct sr_dev_inst *sdi)
225{
226
227 (void)sdi;
228
229 switch (info_id) {
230 case SR_DI_HWCAPS:
231 *data = hwcaps;
232 break;
233 case SR_DI_NUM_PROBES:
234 *data = GINT_TO_POINTER(NUM_PROBES);
235 break;
236 case SR_DI_PROBE_NAMES:
237 *data = probe_names;
238 break;
239 case SR_DI_SAMPLERATES:
240 *data = &samplerates;
241 break;
242 case SR_DI_CUR_SAMPLERATE:
243 *data = &cur_samplerate;
244 break;
245 case SR_DI_PATTERNS:
246 *data = &pattern_strings;
247 break;
248 default:
249 return SR_ERR_ARG;
250 }
251
252 return SR_OK;
253}
254
255static int hw_dev_config_set(const struct sr_dev_inst *sdi, int hwcap,
256 const void *value)
257{
258 int ret;
259 const char *stropt;
260
261 (void)sdi;
262
263 if (hwcap == SR_HWCAP_SAMPLERATE) {
264 cur_samplerate = *(const uint64_t *)value;
265 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
266 cur_samplerate);
267 ret = SR_OK;
268 } else if (hwcap == SR_HWCAP_LIMIT_SAMPLES) {
269 limit_msec = 0;
270 limit_samples = *(const uint64_t *)value;
271 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
272 limit_samples);
273 ret = SR_OK;
274 } else if (hwcap == SR_HWCAP_LIMIT_MSEC) {
275 limit_msec = *(const uint64_t *)value;
276 limit_samples = 0;
277 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
278 limit_msec);
279 ret = SR_OK;
280 } else if (hwcap == SR_HWCAP_PATTERN_MODE) {
281 stropt = value;
282 ret = SR_OK;
283 if (!strcmp(stropt, "sigrok")) {
284 default_pattern = PATTERN_SIGROK;
285 } else if (!strcmp(stropt, "random")) {
286 default_pattern = PATTERN_RANDOM;
287 } else if (!strcmp(stropt, "incremental")) {
288 default_pattern = PATTERN_INC;
289 } else if (!strcmp(stropt, "all-low")) {
290 default_pattern = PATTERN_ALL_LOW;
291 } else if (!strcmp(stropt, "all-high")) {
292 default_pattern = PATTERN_ALL_HIGH;
293 } else {
294 ret = SR_ERR;
295 }
296 sr_dbg("demo: %s: setting pattern to %d", __func__,
297 default_pattern);
298 } else {
299 ret = SR_ERR;
300 }
301
302 return ret;
303}
304
305static void samples_generator(uint8_t *buf, uint64_t size, void *data)
306{
307 static uint64_t p = 0;
308 struct dev_context *devc = data;
309 uint64_t i;
310
311 /* TODO: Needed? */
312 memset(buf, 0, size);
313
314 switch (devc->sample_generator) {
315 case PATTERN_SIGROK: /* sigrok pattern */
316 for (i = 0; i < size; i++) {
317 *(buf + i) = ~(pattern_sigrok[p] >> 1);
318 if (++p == 64)
319 p = 0;
320 }
321 break;
322 case PATTERN_RANDOM: /* Random */
323 for (i = 0; i < size; i++)
324 *(buf + i) = (uint8_t)(rand() & 0xff);
325 break;
326 case PATTERN_INC: /* Simple increment */
327 for (i = 0; i < size; i++)
328 *(buf + i) = i;
329 break;
330 case PATTERN_ALL_LOW: /* All probes are low */
331 memset(buf, 0x00, size);
332 break;
333 case PATTERN_ALL_HIGH: /* All probes are high */
334 memset(buf, 0xff, size);
335 break;
336 default:
337 sr_err("demo: %s: unknown pattern %d", __func__,
338 devc->sample_generator);
339 break;
340 }
341}
342
343/* Thread function */
344static void thread_func(void *data)
345{
346 struct dev_context *devc = data;
347 uint8_t buf[BUFSIZE];
348 uint64_t nb_to_send = 0;
349 int bytes_written;
350 double time_cur, time_last, time_diff;
351
352 time_last = g_timer_elapsed(devc->timer, NULL);
353
354 while (thread_running) {
355 /* Rate control */
356 time_cur = g_timer_elapsed(devc->timer, NULL);
357
358 time_diff = time_cur - time_last;
359 time_last = time_cur;
360
361 nb_to_send = cur_samplerate * time_diff;
362
363 if (limit_samples) {
364 nb_to_send = MIN(nb_to_send,
365 limit_samples - devc->samples_counter);
366 }
367
368 /* Make sure we don't overflow. */
369 nb_to_send = MIN(nb_to_send, BUFSIZE);
370
371 if (nb_to_send) {
372 samples_generator(buf, nb_to_send, data);
373 devc->samples_counter += nb_to_send;
374
375 g_io_channel_write_chars(devc->channels[1], (gchar *)&buf,
376 nb_to_send, (gsize *)&bytes_written, NULL);
377 }
378
379 /* Check if we're done. */
380 if ((limit_msec && time_cur * 1000 > limit_msec) ||
381 (limit_samples && devc->samples_counter >= limit_samples))
382 {
383 close(devc->pipe_fds[1]);
384 thread_running = 0;
385 }
386
387 g_usleep(10);
388 }
389}
390
391/* Callback handling data */
392static int receive_data(int fd, int revents, void *cb_data)
393{
394 struct dev_context *devc = cb_data;
395 struct sr_datafeed_packet packet;
396 struct sr_datafeed_logic logic;
397 static uint64_t samples_received = 0;
398 unsigned char c[BUFSIZE];
399 gsize z;
400
401 /* Avoid compiler warnings. */
402 (void)fd;
403 (void)revents;
404
405 do {
406 g_io_channel_read_chars(devc->channels[0],
407 (gchar *)&c, BUFSIZE, &z, NULL);
408
409 if (z > 0) {
410 packet.type = SR_DF_LOGIC;
411 packet.payload = &logic;
412 logic.length = z;
413 logic.unitsize = 1;
414 logic.data = c;
415 sr_session_send(devc->session_dev_id, &packet);
416 samples_received += z;
417 }
418 } while (z > 0);
419
420 if (!thread_running && z <= 0) {
421 /* Make sure we don't receive more packets. */
422 g_io_channel_shutdown(devc->channels[0], FALSE, NULL);
423
424 /* Send last packet. */
425 packet.type = SR_DF_END;
426 sr_session_send(devc->session_dev_id, &packet);
427
428 return FALSE;
429 }
430
431 return TRUE;
432}
433
434static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi,
435 void *cb_data)
436{
437 struct sr_datafeed_packet *packet;
438 struct sr_datafeed_header *header;
439 struct sr_datafeed_meta_logic meta;
440 struct dev_context *devc;
441
442 (void)sdi;
443
444 /* TODO: 'devc' is never g_free()'d? */
445 if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
446 sr_err("demo: %s: devc malloc failed", __func__);
447 return SR_ERR_MALLOC;
448 }
449
450 devc->sample_generator = default_pattern;
451 devc->session_dev_id = cb_data;
452 devc->samples_counter = 0;
453
454 if (pipe(devc->pipe_fds)) {
455 /* TODO: Better error message. */
456 sr_err("demo: %s: pipe() failed", __func__);
457 return SR_ERR;
458 }
459
460 devc->channels[0] = g_io_channel_unix_new(devc->pipe_fds[0]);
461 devc->channels[1] = g_io_channel_unix_new(devc->pipe_fds[1]);
462
463 g_io_channel_set_flags(devc->channels[0], G_IO_FLAG_NONBLOCK, NULL);
464
465 /* Set channel encoding to binary (default is UTF-8). */
466 g_io_channel_set_encoding(devc->channels[0], NULL, NULL);
467 g_io_channel_set_encoding(devc->channels[1], NULL, NULL);
468
469 /* Make channels to unbuffered. */
470 g_io_channel_set_buffered(devc->channels[0], FALSE);
471 g_io_channel_set_buffered(devc->channels[1], FALSE);
472
473 sr_session_source_add_channel(devc->channels[0], G_IO_IN | G_IO_ERR,
474 40, receive_data, devc);
475
476 /* Run the demo thread. */
477 devc->timer = g_timer_new();
478 thread_running = 1;
479 my_thread = g_thread_try_new("sigrok demo generator",
480 (GThreadFunc)thread_func, devc, NULL);
481 if (!my_thread) {
482 sr_err("demo: %s: g_thread_try_new failed", __func__);
483 return SR_ERR; /* TODO */
484 }
485
486 if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
487 sr_err("demo: %s: packet malloc failed", __func__);
488 return SR_ERR_MALLOC;
489 }
490
491 if (!(header = g_try_malloc(sizeof(struct sr_datafeed_header)))) {
492 sr_err("demo: %s: header malloc failed", __func__);
493 return SR_ERR_MALLOC;
494 }
495
496 packet->type = SR_DF_HEADER;
497 packet->payload = header;
498 header->feed_version = 1;
499 gettimeofday(&header->starttime, NULL);
500 sr_session_send(devc->session_dev_id, packet);
501
502 /* Send metadata about the SR_DF_LOGIC packets to come. */
503 packet->type = SR_DF_META_LOGIC;
504 packet->payload = &meta;
505 meta.samplerate = cur_samplerate;
506 meta.num_probes = NUM_PROBES;
507 sr_session_send(devc->session_dev_id, packet);
508
509 g_free(header);
510 g_free(packet);
511
512 return SR_OK;
513}
514
515static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi,
516 void *cb_data)
517{
518 struct dev_context *devc;
519
520 /* Avoid compiler warnings. */
521 (void)cb_data;
522
523 devc = sdi->priv;
524
525 /* Stop generate thread. */
526 thread_running = 0;
527
528 sr_session_source_remove_channel(devc->channels[0]);
529
530 return SR_OK;
531}
532
533SR_PRIV struct sr_dev_driver demo_driver_info = {
534 .name = "demo",
535 .longname = "Demo driver and pattern generator",
536 .api_version = 1,
537 .init = hw_init,
538 .cleanup = hw_cleanup,
539 .scan = hw_scan,
540 .dev_list = hw_dev_list,
541 .dev_open = hw_dev_open,
542 .dev_close = hw_dev_close,
543 .info_get = hw_info_get,
544 .dev_config_set = hw_dev_config_set,
545 .dev_acquisition_start = hw_dev_acquisition_start,
546 .dev_acquisition_stop = hw_dev_acquisition_stop,
547 .priv = NULL,
548};