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