]> sigrok.org Git - libsigrok.git/blame - hardware/demo/demo.c
sr: Fix/document probe names.
[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
b7f09cf8
UH
30#include "sigrok.h"
31#include "sigrok-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. */
3d2efd7d 67SR_PRIV GIOChannel *channels[2];
d35aaf02 68
e15f48c2
BV
69struct databag {
70 int pipe_fds[2];
71 uint8_t sample_generator;
72 uint8_t thread_running;
73 uint64_t samples_counter;
bb7ef793 74 int dev_index;
9c939c51 75 gpointer session_data;
b9cc3629 76 GTimer *timer;
e15f48c2 77};
85b5af06 78
ffedd0bf 79static 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
4bfbf9fc 89static 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
69040b7c 141static int hw_dev_acquisition_stop(int dev_index, gpointer session_data);
6239c175 142
bb7ef793 143static int hw_init(const char *devinfo)
6239c175 144{
d68e2d1a 145 struct sr_dev_inst *sdi;
85b5af06 146
e15f48c2 147 /* Avoid compiler warnings. */
bb7ef793 148 (void)devinfo;
85b5af06 149
d3683c42 150 sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
c03ed397 151 if (!sdi) {
d68e2d1a 152 sr_err("demo: %s: sr_dev_inst_new failed", __func__);
85b5af06 153 return 0;
c03ed397 154 }
e15f48c2 155
d68e2d1a 156 dev_insts = g_slist_append(dev_insts, sdi);
85b5af06
UH
157
158 return 1;
6239c175
UH
159}
160
e7eb703f 161static int hw_dev_open(int dev_index)
6239c175 162{
17e1afcb 163 /* Avoid compiler warnings. */
bb7ef793 164 (void)dev_index;
6239c175
UH
165
166 /* Nothing needed so far. */
697785d1 167
e46b8fb1 168 return SR_OK;
6239c175
UH
169}
170
e7eb703f 171static int hw_dev_close(int dev_index)
6239c175 172{
17e1afcb 173 /* Avoid compiler warnings. */
bb7ef793 174 (void)dev_index;
6239c175
UH
175
176 /* Nothing needed so far. */
697785d1
UH
177
178 return SR_OK;
6239c175
UH
179}
180
57ab7d9f 181static int hw_cleanup(void)
6239c175
UH
182{
183 /* Nothing needed so far. */
57ab7d9f 184 return SR_OK;
6239c175
UH
185}
186
5097b0d0 187static void *hw_dev_info_get(int dev_index, int dev_info_id)
6239c175 188{
d68e2d1a 189 struct sr_dev_inst *sdi;
85b5af06
UH
190 void *info = NULL;
191
bb7ef793 192 if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) {
c03ed397 193 sr_err("demo: %s: sdi was NULL", __func__);
85b5af06 194 return NULL;
c03ed397 195 }
85b5af06 196
bb7ef793 197 switch (dev_info_id) {
1d9a8a5f 198 case SR_DI_INST:
85b5af06 199 info = sdi;
6239c175 200 break;
5a2326a7 201 case SR_DI_NUM_PROBES:
6239c175
UH
202 info = GINT_TO_POINTER(NUM_PROBES);
203 break;
464d12c7
KS
204 case SR_DI_PROBE_NAMES:
205 info = probe_names;
206 break;
4bfbf9fc
BV
207 case SR_DI_SAMPLERATES:
208 info = &samplerates;
209 break;
5a2326a7 210 case SR_DI_CUR_SAMPLERATE:
6239c175
UH
211 info = &cur_samplerate;
212 break;
5a2326a7 213 case SR_DI_PATTERNMODES:
c8f4624d 214 info = &pattern_strings;
e15f48c2 215 break;
6239c175
UH
216 }
217
218 return info;
219}
220
e7eb703f 221static int hw_dev_status_get(int dev_index)
6239c175 222{
17e1afcb 223 /* Avoid compiler warnings. */
bb7ef793 224 (void)dev_index;
5096c6a6 225
5a2326a7 226 return SR_ST_ACTIVE;
6239c175
UH
227}
228
ffedd0bf 229static int *hw_hwcap_get_all(void)
6239c175 230{
ffedd0bf 231 return hwcaps;
6239c175
UH
232}
233
a9a245b4 234static int hw_dev_config_set(int dev_index, int hwcap, void *value)
6239c175
UH
235{
236 int ret;
e15f48c2 237 char *stropt;
6239c175 238
17e1afcb 239 /* Avoid compiler warnings. */
bb7ef793 240 (void)dev_index;
6239c175 241
ffedd0bf 242 if (hwcap == SR_HWCAP_PROBECONFIG) {
d81d2933
BV
243 /* Nothing to do, but must be supported */
244 ret = SR_OK;
ffedd0bf 245 } else if (hwcap == SR_HWCAP_SAMPLERATE) {
68c12597 246 cur_samplerate = *(uint64_t *)value;
6f422264
UH
247 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
248 cur_samplerate);
e46b8fb1 249 ret = SR_OK;
ffedd0bf 250 } else if (hwcap == SR_HWCAP_LIMIT_SAMPLES) {
68c12597 251 limit_samples = *(uint64_t *)value;
6f422264
UH
252 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
253 limit_samples);
e46b8fb1 254 ret = SR_OK;
ffedd0bf 255 } else if (hwcap == SR_HWCAP_LIMIT_MSEC) {
68c12597 256 limit_msec = *(uint64_t *)value;
6f422264
UH
257 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
258 limit_msec);
e46b8fb1 259 ret = SR_OK;
ffedd0bf 260 } else if (hwcap == SR_HWCAP_PATTERN_MODE) {
e15f48c2 261 stropt = value;
c03ed397
UH
262 ret = SR_OK;
263 if (!strcmp(stropt, "sigrok")) {
264 default_pattern = PATTERN_SIGROK;
265 } else if (!strcmp(stropt, "random")) {
c8f4624d 266 default_pattern = PATTERN_RANDOM;
e15f48c2 267 } else if (!strcmp(stropt, "incremental")) {
c8f4624d 268 default_pattern = PATTERN_INC;
c03ed397
UH
269 } else if (!strcmp(stropt, "all-low")) {
270 default_pattern = PATTERN_ALL_LOW;
271 } else if (!strcmp(stropt, "all-high")) {
272 default_pattern = PATTERN_ALL_HIGH;
e15f48c2 273 } else {
e46b8fb1 274 ret = SR_ERR;
e15f48c2 275 }
c8f4624d
UH
276 sr_dbg("demo: %s: setting pattern to %d", __func__,
277 default_pattern);
6239c175 278 } else {
e46b8fb1 279 ret = SR_ERR;
6239c175
UH
280 }
281
282 return ret;
283}
284
5096c6a6 285static void samples_generator(uint8_t *buf, uint64_t size, void *data)
85b5af06 286{
cddd1c5f 287 static uint64_t p = 0;
85b5af06 288 struct databag *mydata = data;
cddd1c5f 289 uint64_t i;
85b5af06 290
c03ed397 291 /* TODO: Needed? */
5096c6a6 292 memset(buf, 0, size);
85b5af06
UH
293
294 switch (mydata->sample_generator) {
c03ed397 295 case PATTERN_SIGROK: /* sigrok pattern */
917e0e71 296 for (i = 0; i < size; i++) {
c8f4624d 297 *(buf + i) = ~(pattern_sigrok[p] >> 1);
917e0e71
BV
298 if (++p == 64)
299 p = 0;
300 }
301 break;
c8f4624d 302 case PATTERN_RANDOM: /* Random */
5096c6a6
UH
303 for (i = 0; i < size; i++)
304 *(buf + i) = (uint8_t)(rand() & 0xff);
85b5af06 305 break;
c8f4624d 306 case PATTERN_INC: /* Simple increment */
5096c6a6 307 for (i = 0; i < size; i++)
85b5af06
UH
308 *(buf + i) = i;
309 break;
c03ed397 310 case PATTERN_ALL_LOW: /* All probes are low */
5a9660dd 311 memset(buf, 0x00, size);
c03ed397
UH
312 break;
313 case PATTERN_ALL_HIGH: /* All probes are high */
5a9660dd 314 memset(buf, 0xff, size);
c03ed397
UH
315 break;
316 default:
317 /* TODO: Error handling. */
318 break;
85b5af06
UH
319 }
320}
321
322/* Thread function */
323static void thread_func(void *data)
324{
325 struct databag *mydata = data;
326 uint8_t buf[BUFSIZE];
327 uint64_t nb_to_send = 0;
d35aaf02 328 int bytes_written;
1924f59f
HE
329 double time_cur, time_last, time_diff;
330
331 time_last = g_timer_elapsed(mydata->timer, NULL);
85b5af06
UH
332
333 while (thread_running) {
1924f59f
HE
334 /* Rate control */
335 time_cur = g_timer_elapsed(mydata->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
c03ed397 342 if (limit_samples) {
1924f59f 343 nb_to_send = MIN(nb_to_send,
c03ed397
UH
344 limit_samples - mydata->samples_counter);
345 }
1924f59f
HE
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 mydata->samples_counter += nb_to_send;
070befcd
BV
353
354 g_io_channel_write_chars(channels[1], (gchar *)&buf,
c03ed397 355 nb_to_send, (gsize *)&bytes_written, NULL);
b9cc3629
BV
356 }
357
1924f59f
HE
358 /* Check if we're done. */
359 if ((limit_msec && time_cur * 1000 > limit_msec) ||
360 (limit_samples && mydata->samples_counter >= limit_samples))
361 {
85b5af06
UH
362 close(mydata->pipe_fds[1]);
363 thread_running = 0;
85b5af06
UH
364 }
365
1924f59f 366 g_usleep(10);
85b5af06
UH
367 }
368}
369
370/* Callback handling data */
9c939c51 371static int receive_data(int fd, int revents, void *session_data)
85b5af06 372{
b9c735a2 373 struct sr_datafeed_packet packet;
9c939c51
BV
374 struct sr_datafeed_logic logic;
375 static uint64_t samples_received = 0;
376 unsigned char c[BUFSIZE];
108a5bfb 377 gsize z;
1924f59f 378
26ce0bbf 379 /* Avoid compiler warnings. */
cb93f8a9
UH
380 (void)fd;
381 (void)revents;
1924f59f
HE
382
383 do {
384 g_io_channel_read_chars(channels[0],
070befcd 385 (gchar *)&c, BUFSIZE, &z, NULL);
1924f59f
HE
386
387 if (z > 0) {
5a2326a7 388 packet.type = SR_DF_LOGIC;
9c939c51 389 packet.payload = &logic;
9c939c51
BV
390 logic.length = z;
391 logic.unitsize = 1;
392 logic.data = c;
393 sr_session_bus(session_data, &packet);
394 samples_received += z;
1924f59f
HE
395 }
396 } while (z > 0);
85b5af06 397
c03ed397
UH
398 if (!thread_running && z <= 0) {
399 /* Make sure we don't receive more packets. */
1924f59f 400 g_io_channel_close(channels[0]);
d35aaf02 401
1924f59f 402 /* Send last packet. */
5a2326a7 403 packet.type = SR_DF_END;
9c939c51 404 sr_session_bus(session_data, &packet);
1924f59f
HE
405
406 return FALSE;
85b5af06 407 }
1924f59f 408
85b5af06
UH
409 return TRUE;
410}
411
69040b7c 412static int hw_dev_acquisition_start(int dev_index, gpointer session_data)
6239c175 413{
b9c735a2
UH
414 struct sr_datafeed_packet *packet;
415 struct sr_datafeed_header *header;
85b5af06 416 struct databag *mydata;
6239c175 417
27a3a6fe
UH
418 /* TODO: 'mydata' is never g_free()'d? */
419 if (!(mydata = g_try_malloc(sizeof(struct databag)))) {
420 sr_err("demo: %s: mydata malloc failed", __func__);
e46b8fb1 421 return SR_ERR_MALLOC;
27a3a6fe 422 }
85b5af06 423
c8f4624d 424 mydata->sample_generator = default_pattern;
9c939c51 425 mydata->session_data = session_data;
bb7ef793 426 mydata->dev_index = dev_index;
85b5af06 427 mydata->samples_counter = 0;
85b5af06 428
c03ed397
UH
429 if (pipe(mydata->pipe_fds)) {
430 /* TODO: Better error message. */
431 sr_err("demo: %s: pipe() failed", __func__);
e46b8fb1 432 return SR_ERR;
c03ed397 433 }
85b5af06 434
d35aaf02
UH
435 channels[0] = g_io_channel_unix_new(mydata->pipe_fds[0]);
436 channels[1] = g_io_channel_unix_new(mydata->pipe_fds[1]);
437
438 /* Set channel encoding to binary (default is UTF-8). */
439 g_io_channel_set_encoding(channels[0], NULL, NULL);
440 g_io_channel_set_encoding(channels[1], NULL, NULL);
441
442 /* Make channels to unbuffered. */
443 g_io_channel_set_buffered(channels[0], FALSE);
444 g_io_channel_set_buffered(channels[1], FALSE);
445
6f1be0a2 446 sr_source_add(mydata->pipe_fds[0], G_IO_IN | G_IO_ERR, 40,
9c939c51 447 receive_data, session_data);
85b5af06
UH
448
449 /* Run the demo thread. */
450 g_thread_init(NULL);
c03ed397 451 /* This must to be done between g_thread_init() & g_thread_create(). */
1924f59f 452 mydata->timer = g_timer_new();
85b5af06
UH
453 thread_running = 1;
454 my_thread =
455 g_thread_create((GThreadFunc)thread_func, mydata, TRUE, NULL);
c03ed397
UH
456 if (!my_thread) {
457 sr_err("demo: %s: g_thread_create failed", __func__);
458 return SR_ERR; /* TODO */
459 }
6239c175 460
27a3a6fe
UH
461 if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
462 sr_err("demo: %s: packet malloc failed", __func__);
e46b8fb1 463 return SR_ERR_MALLOC;
27a3a6fe
UH
464 }
465
466 if (!(header = g_try_malloc(sizeof(struct sr_datafeed_header)))) {
467 sr_err("demo: %s: header malloc failed", __func__);
468 return SR_ERR_MALLOC;
469 }
6239c175 470
5a2326a7 471 packet->type = SR_DF_HEADER;
9c939c51 472 packet->payload = header;
6239c175
UH
473 header->feed_version = 1;
474 gettimeofday(&header->starttime, NULL);
475 header->samplerate = cur_samplerate;
c2616fb9 476 header->num_logic_probes = NUM_PROBES;
9c939c51 477 sr_session_bus(session_data, packet);
27a3a6fe
UH
478 g_free(header);
479 g_free(packet);
6239c175 480
e46b8fb1 481 return SR_OK;
6239c175
UH
482}
483
69040b7c 484static int hw_dev_acquisition_stop(int dev_index, gpointer session_data)
6239c175 485{
17e1afcb 486 /* Avoid compiler warnings. */
bb7ef793 487 (void)dev_index;
cb93f8a9 488 (void)session_data;
6239c175 489
1924f59f
HE
490 /* Stop generate thread. */
491 thread_running = 0;
3010f21c
UH
492
493 return SR_OK;
6239c175
UH
494}
495
bb7ef793 496SR_PRIV struct sr_dev_plugin demo_plugin_info = {
e519ba86
UH
497 .name = "demo",
498 .longname = "Demo driver and pattern generator",
499 .api_version = 1,
500 .init = hw_init,
501 .cleanup = hw_cleanup,
e7eb703f
UH
502 .dev_open = hw_dev_open,
503 .dev_close = hw_dev_close,
5097b0d0 504 .dev_info_get = hw_dev_info_get,
e7eb703f 505 .dev_status_get = hw_dev_status_get,
ffedd0bf 506 .hwcap_get_all = hw_hwcap_get_all,
a9a245b4 507 .dev_config_set = hw_dev_config_set,
69040b7c
UH
508 .dev_acquisition_start = hw_dev_acquisition_start,
509 .dev_acquisition_stop = hw_dev_acquisition_stop,
6239c175 510};