]> sigrok.org Git - libsigrok.git/blame - hardware/demo/demo.c
sr: add new driver API call: scan()
[libsigrok.git] / hardware / demo / demo.c
CommitLineData
6239c175
UH
1/*
2 * This file is part of the sigrok project.
3 *
4 * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
fc96e6f8 5 * Copyright (C) 2011 Olivier Fauchon <olivier@aixmarseille.com>
6239c175
UH
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>
85b5af06 23#include <unistd.h>
6239c175 24#include <string.h>
d35aaf02
UH
25#ifdef _WIN32
26#include <io.h>
27#include <fcntl.h>
28#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
29#endif
45c59c8b
BV
30#include "libsigrok.h"
31#include "libsigrok-internal.h"
6239c175 32
c03ed397 33/* TODO: Number of probes should be configurable. */
e15f48c2 34#define NUM_PROBES 8
c03ed397 35
e15f48c2 36#define DEMONAME "Demo device"
c03ed397
UH
37
38/* The size of chunks to send through the session bus. */
39/* TODO: Should be configurable. */
e15f48c2 40#define BUFSIZE 4096
85b5af06 41
0d31276b 42/* Supported patterns which we can generate */
e15f48c2 43enum {
0d31276b
UH
44 /**
45 * Pattern which spells "sigrok" using '0's (with '1's as "background")
46 * when displayed using the 'bits' output format.
47 */
c8f4624d 48 PATTERN_SIGROK,
0d31276b 49
c03ed397 50 /** Pattern which consists of (pseudo-)random values on all probes. */
c8f4624d 51 PATTERN_RANDOM,
0d31276b
UH
52
53 /**
54 * Pattern which consists of incrementing numbers.
55 * TODO: Better description.
56 */
c8f4624d 57 PATTERN_INC,
c03ed397
UH
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,
e15f48c2 64};
85b5af06 65
29cbfeaf 66/* FIXME: Should not be global. */
d35aaf02 67
455b26ed 68struct context {
e15f48c2 69 int pipe_fds[2];
249ae2be 70 GIOChannel *channels[2];
e15f48c2
BV
71 uint8_t sample_generator;
72 uint8_t thread_running;
73 uint64_t samples_counter;
bb7ef793 74 int dev_index;
3cd3a20b 75 void *session_dev_id;
b9cc3629 76 GTimer *timer;
e15f48c2 77};
85b5af06 78
915f7cc8 79static const int hwcaps[] = {
5a2326a7 80 SR_HWCAP_LOGIC_ANALYZER,
bb7ef793 81 SR_HWCAP_DEMO_DEV,
4bfbf9fc 82 SR_HWCAP_SAMPLERATE,
5a2326a7
UH
83 SR_HWCAP_PATTERN_MODE,
84 SR_HWCAP_LIMIT_SAMPLES,
85 SR_HWCAP_LIMIT_MSEC,
86 SR_HWCAP_CONTINUOUS,
6239c175
UH
87};
88
a533743d 89static const struct sr_samplerates samplerates = {
c9140419 90 SR_HZ(1),
59df0c77 91 SR_GHZ(1),
c9140419 92 SR_HZ(1),
4bfbf9fc
BV
93 NULL,
94};
95
c8f4624d 96static const char *pattern_strings[] = {
c03ed397 97 "sigrok",
e15f48c2
BV
98 "random",
99 "incremental",
c03ed397
UH
100 "all-low",
101 "all-high",
02440dd8 102 NULL,
85b5af06
UH
103};
104
d261dbbf 105/* We name the probes 0-7 on our demo driver. */
464d12c7
KS
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
c8f4624d 118static uint8_t pattern_sigrok[] = {
917e0e71
BV
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
ea9cfed7
UH
129/* Private, per-device-instance driver context. */
130/* TODO: struct context as with the other drivers. */
131
e7eb703f 132/* List of struct sr_dev_inst, maintained by dev_open()/dev_close(). */
d68e2d1a 133static GSList *dev_insts = NULL;
59df0c77 134static uint64_t cur_samplerate = SR_KHZ(200);
b9cc3629
BV
135static uint64_t limit_samples = 0;
136static uint64_t limit_msec = 0;
c8f4624d 137static int default_pattern = PATTERN_SIGROK;
b9cc3629
BV
138static GThread *my_thread;
139static int thread_running;
6239c175 140
3cd3a20b 141static int hw_dev_acquisition_stop(int dev_index, void *cb_data);
6239c175 142
40dda2c3 143static int hw_init(void)
61136ea6
BV
144{
145
146 /* Nothing to do. */
147
148 return SR_OK;
149}
150
151static int hw_scan(void)
6239c175 152{
d68e2d1a 153 struct sr_dev_inst *sdi;
85b5af06 154
d3683c42 155 sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
c03ed397 156 if (!sdi) {
d68e2d1a 157 sr_err("demo: %s: sr_dev_inst_new failed", __func__);
85b5af06 158 return 0;
c03ed397 159 }
e15f48c2 160
d68e2d1a 161 dev_insts = g_slist_append(dev_insts, sdi);
85b5af06
UH
162
163 return 1;
6239c175
UH
164}
165
e7eb703f 166static int hw_dev_open(int dev_index)
6239c175 167{
17e1afcb 168 /* Avoid compiler warnings. */
bb7ef793 169 (void)dev_index;
6239c175
UH
170
171 /* Nothing needed so far. */
697785d1 172
e46b8fb1 173 return SR_OK;
6239c175
UH
174}
175
e7eb703f 176static int hw_dev_close(int dev_index)
6239c175 177{
17e1afcb 178 /* Avoid compiler warnings. */
bb7ef793 179 (void)dev_index;
6239c175
UH
180
181 /* Nothing needed so far. */
697785d1
UH
182
183 return SR_OK;
6239c175
UH
184}
185
57ab7d9f 186static int hw_cleanup(void)
6239c175
UH
187{
188 /* Nothing needed so far. */
57ab7d9f 189 return SR_OK;
6239c175
UH
190}
191
b7f578be 192static const void *hw_dev_info_get(int dev_index, int dev_info_id)
6239c175 193{
d68e2d1a 194 struct sr_dev_inst *sdi;
b7f578be 195 const void *info = NULL;
85b5af06 196
bb7ef793 197 if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) {
c03ed397 198 sr_err("demo: %s: sdi was NULL", __func__);
85b5af06 199 return NULL;
c03ed397 200 }
85b5af06 201
bb7ef793 202 switch (dev_info_id) {
1d9a8a5f 203 case SR_DI_INST:
85b5af06 204 info = sdi;
6239c175 205 break;
5a2326a7 206 case SR_DI_NUM_PROBES:
6239c175
UH
207 info = GINT_TO_POINTER(NUM_PROBES);
208 break;
464d12c7
KS
209 case SR_DI_PROBE_NAMES:
210 info = probe_names;
211 break;
4bfbf9fc
BV
212 case SR_DI_SAMPLERATES:
213 info = &samplerates;
214 break;
5a2326a7 215 case SR_DI_CUR_SAMPLERATE:
6239c175
UH
216 info = &cur_samplerate;
217 break;
eb0a3731 218 case SR_DI_PATTERNS:
c8f4624d 219 info = &pattern_strings;
e15f48c2 220 break;
6239c175
UH
221 }
222
223 return info;
224}
225
e7eb703f 226static int hw_dev_status_get(int dev_index)
6239c175 227{
17e1afcb 228 /* Avoid compiler warnings. */
bb7ef793 229 (void)dev_index;
5096c6a6 230
5a2326a7 231 return SR_ST_ACTIVE;
6239c175
UH
232}
233
915f7cc8 234static const int *hw_hwcap_get_all(void)
6239c175 235{
ffedd0bf 236 return hwcaps;
6239c175
UH
237}
238
1b79df2f 239static int hw_dev_config_set(int dev_index, int hwcap, const void *value)
6239c175
UH
240{
241 int ret;
1b79df2f 242 const char *stropt;
6239c175 243
17e1afcb 244 /* Avoid compiler warnings. */
bb7ef793 245 (void)dev_index;
6239c175 246
ffedd0bf 247 if (hwcap == SR_HWCAP_PROBECONFIG) {
d81d2933
BV
248 /* Nothing to do, but must be supported */
249 ret = SR_OK;
ffedd0bf 250 } else if (hwcap == SR_HWCAP_SAMPLERATE) {
1b79df2f 251 cur_samplerate = *(const uint64_t *)value;
6f422264
UH
252 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
253 cur_samplerate);
e46b8fb1 254 ret = SR_OK;
ffedd0bf 255 } else if (hwcap == SR_HWCAP_LIMIT_SAMPLES) {
8489264f 256 limit_msec = 0;
1b79df2f 257 limit_samples = *(const uint64_t *)value;
6f422264
UH
258 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
259 limit_samples);
e46b8fb1 260 ret = SR_OK;
ffedd0bf 261 } else if (hwcap == SR_HWCAP_LIMIT_MSEC) {
1b79df2f 262 limit_msec = *(const uint64_t *)value;
8489264f 263 limit_samples = 0;
6f422264
UH
264 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
265 limit_msec);
e46b8fb1 266 ret = SR_OK;
ffedd0bf 267 } else if (hwcap == SR_HWCAP_PATTERN_MODE) {
e15f48c2 268 stropt = value;
c03ed397
UH
269 ret = SR_OK;
270 if (!strcmp(stropt, "sigrok")) {
271 default_pattern = PATTERN_SIGROK;
272 } else if (!strcmp(stropt, "random")) {
c8f4624d 273 default_pattern = PATTERN_RANDOM;
e15f48c2 274 } else if (!strcmp(stropt, "incremental")) {
c8f4624d 275 default_pattern = PATTERN_INC;
c03ed397
UH
276 } else if (!strcmp(stropt, "all-low")) {
277 default_pattern = PATTERN_ALL_LOW;
278 } else if (!strcmp(stropt, "all-high")) {
279 default_pattern = PATTERN_ALL_HIGH;
e15f48c2 280 } else {
e46b8fb1 281 ret = SR_ERR;
e15f48c2 282 }
c8f4624d
UH
283 sr_dbg("demo: %s: setting pattern to %d", __func__,
284 default_pattern);
6239c175 285 } else {
e46b8fb1 286 ret = SR_ERR;
6239c175
UH
287 }
288
289 return ret;
290}
291
5096c6a6 292static void samples_generator(uint8_t *buf, uint64_t size, void *data)
85b5af06 293{
cddd1c5f 294 static uint64_t p = 0;
455b26ed 295 struct context *ctx = data;
cddd1c5f 296 uint64_t i;
85b5af06 297
c03ed397 298 /* TODO: Needed? */
5096c6a6 299 memset(buf, 0, size);
85b5af06 300
ab331b67 301 switch (ctx->sample_generator) {
c03ed397 302 case PATTERN_SIGROK: /* sigrok pattern */
917e0e71 303 for (i = 0; i < size; i++) {
c8f4624d 304 *(buf + i) = ~(pattern_sigrok[p] >> 1);
917e0e71
BV
305 if (++p == 64)
306 p = 0;
307 }
308 break;
c8f4624d 309 case PATTERN_RANDOM: /* Random */
5096c6a6
UH
310 for (i = 0; i < size; i++)
311 *(buf + i) = (uint8_t)(rand() & 0xff);
85b5af06 312 break;
c8f4624d 313 case PATTERN_INC: /* Simple increment */
5096c6a6 314 for (i = 0; i < size; i++)
85b5af06
UH
315 *(buf + i) = i;
316 break;
c03ed397 317 case PATTERN_ALL_LOW: /* All probes are low */
5a9660dd 318 memset(buf, 0x00, size);
c03ed397
UH
319 break;
320 case PATTERN_ALL_HIGH: /* All probes are high */
5a9660dd 321 memset(buf, 0xff, size);
c03ed397
UH
322 break;
323 default:
0abee507 324 sr_err("demo: %s: unknown pattern %d", __func__,
ab331b67 325 ctx->sample_generator);
c03ed397 326 break;
85b5af06
UH
327 }
328}
329
330/* Thread function */
331static void thread_func(void *data)
332{
455b26ed 333 struct context *ctx = data;
85b5af06
UH
334 uint8_t buf[BUFSIZE];
335 uint64_t nb_to_send = 0;
d35aaf02 336 int bytes_written;
1924f59f
HE
337 double time_cur, time_last, time_diff;
338
ab331b67 339 time_last = g_timer_elapsed(ctx->timer, NULL);
85b5af06
UH
340
341 while (thread_running) {
1924f59f 342 /* Rate control */
ab331b67 343 time_cur = g_timer_elapsed(ctx->timer, NULL);
1924f59f
HE
344
345 time_diff = time_cur - time_last;
346 time_last = time_cur;
347
348 nb_to_send = cur_samplerate * time_diff;
349
c03ed397 350 if (limit_samples) {
1924f59f 351 nb_to_send = MIN(nb_to_send,
ab331b67 352 limit_samples - ctx->samples_counter);
c03ed397 353 }
1924f59f
HE
354
355 /* Make sure we don't overflow. */
356 nb_to_send = MIN(nb_to_send, BUFSIZE);
357
358 if (nb_to_send) {
359 samples_generator(buf, nb_to_send, data);
ab331b67 360 ctx->samples_counter += nb_to_send;
070befcd 361
249ae2be 362 g_io_channel_write_chars(ctx->channels[1], (gchar *)&buf,
c03ed397 363 nb_to_send, (gsize *)&bytes_written, NULL);
b9cc3629
BV
364 }
365
1924f59f
HE
366 /* Check if we're done. */
367 if ((limit_msec && time_cur * 1000 > limit_msec) ||
ab331b67 368 (limit_samples && ctx->samples_counter >= limit_samples))
1924f59f 369 {
ab331b67 370 close(ctx->pipe_fds[1]);
85b5af06 371 thread_running = 0;
85b5af06
UH
372 }
373
1924f59f 374 g_usleep(10);
85b5af06
UH
375 }
376}
377
378/* Callback handling data */
1f9813eb 379static int receive_data(int fd, int revents, void *cb_data)
85b5af06 380{
249ae2be 381 struct context *ctx = cb_data;
b9c735a2 382 struct sr_datafeed_packet packet;
9c939c51
BV
383 struct sr_datafeed_logic logic;
384 static uint64_t samples_received = 0;
385 unsigned char c[BUFSIZE];
108a5bfb 386 gsize z;
1924f59f 387
26ce0bbf 388 /* Avoid compiler warnings. */
cb93f8a9
UH
389 (void)fd;
390 (void)revents;
1924f59f
HE
391
392 do {
249ae2be 393 g_io_channel_read_chars(ctx->channels[0],
070befcd 394 (gchar *)&c, BUFSIZE, &z, NULL);
1924f59f
HE
395
396 if (z > 0) {
5a2326a7 397 packet.type = SR_DF_LOGIC;
9c939c51 398 packet.payload = &logic;
9c939c51
BV
399 logic.length = z;
400 logic.unitsize = 1;
401 logic.data = c;
249ae2be 402 sr_session_send(ctx->session_dev_id, &packet);
9c939c51 403 samples_received += z;
1924f59f
HE
404 }
405 } while (z > 0);
85b5af06 406
c03ed397
UH
407 if (!thread_running && z <= 0) {
408 /* Make sure we don't receive more packets. */
249ae2be 409 g_io_channel_shutdown(ctx->channels[0], FALSE, NULL);
d35aaf02 410
1924f59f 411 /* Send last packet. */
5a2326a7 412 packet.type = SR_DF_END;
249ae2be 413 sr_session_send(ctx->session_dev_id, &packet);
1924f59f
HE
414
415 return FALSE;
85b5af06 416 }
1924f59f 417
85b5af06
UH
418 return TRUE;
419}
420
3cd3a20b 421static int hw_dev_acquisition_start(int dev_index, void *cb_data)
6239c175 422{
b9c735a2
UH
423 struct sr_datafeed_packet *packet;
424 struct sr_datafeed_header *header;
f366e86c 425 struct sr_datafeed_meta_logic meta;
455b26ed 426 struct context *ctx;
6239c175 427
ab331b67 428 /* TODO: 'ctx' is never g_free()'d? */
455b26ed 429 if (!(ctx = g_try_malloc(sizeof(struct context)))) {
ab331b67 430 sr_err("demo: %s: ctx malloc failed", __func__);
e46b8fb1 431 return SR_ERR_MALLOC;
27a3a6fe 432 }
85b5af06 433
ab331b67
UH
434 ctx->sample_generator = default_pattern;
435 ctx->session_dev_id = cb_data;
436 ctx->dev_index = dev_index;
437 ctx->samples_counter = 0;
85b5af06 438
ab331b67 439 if (pipe(ctx->pipe_fds)) {
c03ed397
UH
440 /* TODO: Better error message. */
441 sr_err("demo: %s: pipe() failed", __func__);
e46b8fb1 442 return SR_ERR;
c03ed397 443 }
85b5af06 444
249ae2be
LPC
445 ctx->channels[0] = g_io_channel_unix_new(ctx->pipe_fds[0]);
446 ctx->channels[1] = g_io_channel_unix_new(ctx->pipe_fds[1]);
d35aaf02 447
e6e8f8e0
LPC
448 g_io_channel_set_flags(ctx->channels[0], G_IO_FLAG_NONBLOCK, NULL);
449
d35aaf02 450 /* Set channel encoding to binary (default is UTF-8). */
249ae2be
LPC
451 g_io_channel_set_encoding(ctx->channels[0], NULL, NULL);
452 g_io_channel_set_encoding(ctx->channels[1], NULL, NULL);
d35aaf02
UH
453
454 /* Make channels to unbuffered. */
249ae2be
LPC
455 g_io_channel_set_buffered(ctx->channels[0], FALSE);
456 g_io_channel_set_buffered(ctx->channels[1], FALSE);
d35aaf02 457
249ae2be
LPC
458 sr_session_source_add_channel(ctx->channels[0], G_IO_IN | G_IO_ERR,
459 40, receive_data, ctx);
85b5af06
UH
460
461 /* Run the demo thread. */
462 g_thread_init(NULL);
c03ed397 463 /* This must to be done between g_thread_init() & g_thread_create(). */
ab331b67 464 ctx->timer = g_timer_new();
85b5af06
UH
465 thread_running = 1;
466 my_thread =
ab331b67 467 g_thread_create((GThreadFunc)thread_func, ctx, TRUE, NULL);
c03ed397
UH
468 if (!my_thread) {
469 sr_err("demo: %s: g_thread_create failed", __func__);
470 return SR_ERR; /* TODO */
471 }
6239c175 472
27a3a6fe
UH
473 if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
474 sr_err("demo: %s: packet malloc failed", __func__);
e46b8fb1 475 return SR_ERR_MALLOC;
27a3a6fe
UH
476 }
477
478 if (!(header = g_try_malloc(sizeof(struct sr_datafeed_header)))) {
479 sr_err("demo: %s: header malloc failed", __func__);
480 return SR_ERR_MALLOC;
481 }
6239c175 482
5a2326a7 483 packet->type = SR_DF_HEADER;
9c939c51 484 packet->payload = header;
6239c175
UH
485 header->feed_version = 1;
486 gettimeofday(&header->starttime, NULL);
ab331b67 487 sr_session_send(ctx->session_dev_id, packet);
f366e86c
BV
488
489 /* Send metadata about the SR_DF_LOGIC packets to come. */
490 packet->type = SR_DF_META_LOGIC;
491 packet->payload = &meta;
492 meta.samplerate = cur_samplerate;
493 meta.num_probes = NUM_PROBES;
494 sr_session_send(ctx->session_dev_id, packet);
495
27a3a6fe
UH
496 g_free(header);
497 g_free(packet);
6239c175 498
e46b8fb1 499 return SR_OK;
6239c175
UH
500}
501
3cd3a20b
UH
502/* TODO: This stops acquisition on ALL devices, ignoring dev_index. */
503static int hw_dev_acquisition_stop(int dev_index, void *cb_data)
6239c175 504{
17e1afcb 505 /* Avoid compiler warnings. */
bb7ef793 506 (void)dev_index;
3cd3a20b 507 (void)cb_data;
6239c175 508
1924f59f
HE
509 /* Stop generate thread. */
510 thread_running = 0;
3010f21c
UH
511
512 return SR_OK;
6239c175
UH
513}
514
c09f0b57 515SR_PRIV struct sr_dev_driver demo_driver_info = {
e519ba86
UH
516 .name = "demo",
517 .longname = "Demo driver and pattern generator",
518 .api_version = 1,
519 .init = hw_init,
520 .cleanup = hw_cleanup,
61136ea6 521 .scan = hw_scan,
e7eb703f
UH
522 .dev_open = hw_dev_open,
523 .dev_close = hw_dev_close,
5097b0d0 524 .dev_info_get = hw_dev_info_get,
e7eb703f 525 .dev_status_get = hw_dev_status_get,
ffedd0bf 526 .hwcap_get_all = hw_hwcap_get_all,
a9a245b4 527 .dev_config_set = hw_dev_config_set,
69040b7c
UH
528 .dev_acquisition_start = hw_dev_acquisition_start,
529 .dev_acquisition_stop = hw_dev_acquisition_stop,
6239c175 530};