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