]> sigrok.org Git - libsigrok.git/blame - hardware/demo/demo.c
add SR_HWCAP_DEMO_DEVICE capability
[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
6239c175 30#include "config.h"
b7f09cf8
UH
31#include "sigrok.h"
32#include "sigrok-internal.h"
6239c175 33
c03ed397 34/* TODO: Number of probes should be configurable. */
e15f48c2 35#define NUM_PROBES 8
c03ed397 36
e15f48c2 37#define DEMONAME "Demo device"
c03ed397
UH
38
39/* The size of chunks to send through the session bus. */
40/* TODO: Should be configurable. */
e15f48c2 41#define BUFSIZE 4096
85b5af06 42
0d31276b 43/* Supported patterns which we can generate */
e15f48c2 44enum {
0d31276b
UH
45 /**
46 * Pattern which spells "sigrok" using '0's (with '1's as "background")
47 * when displayed using the 'bits' output format.
48 */
c8f4624d 49 PATTERN_SIGROK,
0d31276b 50
c03ed397 51 /** Pattern which consists of (pseudo-)random values on all probes. */
c8f4624d 52 PATTERN_RANDOM,
0d31276b
UH
53
54 /**
55 * Pattern which consists of incrementing numbers.
56 * TODO: Better description.
57 */
c8f4624d 58 PATTERN_INC,
c03ed397
UH
59
60 /** Pattern where all probes have a low logic state. */
61 PATTERN_ALL_LOW,
62
63 /** Pattern where all probes have a high logic state. */
64 PATTERN_ALL_HIGH,
e15f48c2 65};
85b5af06 66
29cbfeaf 67/* FIXME: Should not be global. */
d35aaf02
UH
68GIOChannel *channels[2];
69
e15f48c2
BV
70struct databag {
71 int pipe_fds[2];
72 uint8_t sample_generator;
73 uint8_t thread_running;
74 uint64_t samples_counter;
75 int device_index;
9c939c51 76 gpointer session_data;
b9cc3629 77 GTimer *timer;
e15f48c2 78};
85b5af06 79
6239c175 80static int capabilities[] = {
5a2326a7 81 SR_HWCAP_LOGIC_ANALYZER,
a141db8c 82 SR_HWCAP_DEMO_DEVICE,
4bfbf9fc 83 SR_HWCAP_SAMPLERATE,
5a2326a7
UH
84 SR_HWCAP_PATTERN_MODE,
85 SR_HWCAP_LIMIT_SAMPLES,
86 SR_HWCAP_LIMIT_MSEC,
87 SR_HWCAP_CONTINUOUS,
6239c175
UH
88};
89
4bfbf9fc 90static struct sr_samplerates samplerates = {
c9140419 91 SR_HZ(1),
59df0c77 92 SR_GHZ(1),
c9140419 93 SR_HZ(1),
4bfbf9fc
BV
94 NULL,
95};
96
c8f4624d 97static const char *pattern_strings[] = {
c03ed397 98 "sigrok",
e15f48c2
BV
99 "random",
100 "incremental",
c03ed397
UH
101 "all-low",
102 "all-high",
02440dd8 103 NULL,
85b5af06
UH
104};
105
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
a00ba012 129/* List of struct sr_device_instance, maintained by opendev()/closedev(). */
85b5af06 130static GSList *device_instances = NULL;
59df0c77 131static uint64_t cur_samplerate = SR_KHZ(200);
9c939c51 132static uint64_t period_ps = 5000000;
b9cc3629
BV
133static uint64_t limit_samples = 0;
134static uint64_t limit_msec = 0;
c8f4624d 135static int default_pattern = PATTERN_SIGROK;
b9cc3629
BV
136static GThread *my_thread;
137static int thread_running;
6239c175 138
9c939c51 139static void hw_stop_acquisition(int device_index, gpointer session_data);
6239c175 140
54ac5277 141static int hw_init(const char *deviceinfo)
6239c175 142{
a00ba012 143 struct sr_device_instance *sdi;
85b5af06 144
e15f48c2 145 /* Avoid compiler warnings. */
cb93f8a9 146 (void)deviceinfo;
85b5af06 147
5a2326a7 148 sdi = sr_device_instance_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
c03ed397
UH
149 if (!sdi) {
150 sr_err("demo: %s: sr_device_instance_new failed", __func__);
85b5af06 151 return 0;
c03ed397 152 }
e15f48c2 153
85b5af06
UH
154 device_instances = g_slist_append(device_instances, sdi);
155
156 return 1;
6239c175
UH
157}
158
159static int hw_opendev(int device_index)
160{
17e1afcb 161 /* Avoid compiler warnings. */
cb93f8a9 162 (void)device_index;
6239c175
UH
163
164 /* Nothing needed so far. */
697785d1 165
e46b8fb1 166 return SR_OK;
6239c175
UH
167}
168
697785d1 169static int hw_closedev(int device_index)
6239c175 170{
17e1afcb 171 /* Avoid compiler warnings. */
cb93f8a9 172 (void)device_index;
6239c175
UH
173
174 /* Nothing needed so far. */
697785d1
UH
175
176 return SR_OK;
6239c175
UH
177}
178
179static void hw_cleanup(void)
180{
181 /* Nothing needed so far. */
182}
183
184static void *hw_get_device_info(int device_index, int device_info_id)
185{
a00ba012 186 struct sr_device_instance *sdi;
85b5af06
UH
187 void *info = NULL;
188
c03ed397
UH
189 if (!(sdi = sr_get_device_instance(device_instances, device_index))) {
190 sr_err("demo: %s: sdi was NULL", __func__);
85b5af06 191 return NULL;
c03ed397 192 }
85b5af06 193
6239c175 194 switch (device_info_id) {
5a2326a7 195 case SR_DI_INSTANCE:
85b5af06 196 info = sdi;
6239c175 197 break;
5a2326a7 198 case SR_DI_NUM_PROBES:
6239c175
UH
199 info = GINT_TO_POINTER(NUM_PROBES);
200 break;
464d12c7
KS
201 case SR_DI_PROBE_NAMES:
202 info = probe_names;
203 break;
4bfbf9fc
BV
204 case SR_DI_SAMPLERATES:
205 info = &samplerates;
206 break;
5a2326a7 207 case SR_DI_CUR_SAMPLERATE:
6239c175
UH
208 info = &cur_samplerate;
209 break;
5a2326a7 210 case SR_DI_PATTERNMODES:
c8f4624d 211 info = &pattern_strings;
e15f48c2 212 break;
6239c175
UH
213 }
214
215 return info;
216}
217
218static int hw_get_status(int device_index)
219{
17e1afcb 220 /* Avoid compiler warnings. */
cb93f8a9 221 (void)device_index;
5096c6a6 222
5a2326a7 223 return SR_ST_ACTIVE;
6239c175
UH
224}
225
226static int *hw_get_capabilities(void)
227{
228 return capabilities;
229}
230
231static int hw_set_configuration(int device_index, int capability, void *value)
232{
233 int ret;
e15f48c2 234 char *stropt;
6239c175 235
17e1afcb 236 /* Avoid compiler warnings. */
cb93f8a9 237 (void)device_index;
6239c175 238
5a2326a7 239 if (capability == SR_HWCAP_PROBECONFIG) {
d81d2933
BV
240 /* Nothing to do, but must be supported */
241 ret = SR_OK;
242 } else if (capability == SR_HWCAP_SAMPLERATE) {
68c12597 243 cur_samplerate = *(uint64_t *)value;
9c939c51 244 period_ps = 1000000000000 / cur_samplerate;
6f422264
UH
245 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
246 cur_samplerate);
e46b8fb1 247 ret = SR_OK;
5a2326a7 248 } else if (capability == SR_HWCAP_LIMIT_SAMPLES) {
68c12597 249 limit_samples = *(uint64_t *)value;
6f422264
UH
250 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
251 limit_samples);
e46b8fb1 252 ret = SR_OK;
5a2326a7 253 } else if (capability == SR_HWCAP_LIMIT_MSEC) {
68c12597 254 limit_msec = *(uint64_t *)value;
6f422264
UH
255 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
256 limit_msec);
e46b8fb1 257 ret = SR_OK;
5a2326a7 258 } else if (capability == SR_HWCAP_PATTERN_MODE) {
e15f48c2 259 stropt = value;
c03ed397
UH
260 ret = SR_OK;
261 if (!strcmp(stropt, "sigrok")) {
262 default_pattern = PATTERN_SIGROK;
263 } else if (!strcmp(stropt, "random")) {
c8f4624d 264 default_pattern = PATTERN_RANDOM;
e15f48c2 265 } else if (!strcmp(stropt, "incremental")) {
c8f4624d 266 default_pattern = PATTERN_INC;
c03ed397
UH
267 } else if (!strcmp(stropt, "all-low")) {
268 default_pattern = PATTERN_ALL_LOW;
269 } else if (!strcmp(stropt, "all-high")) {
270 default_pattern = PATTERN_ALL_HIGH;
e15f48c2 271 } else {
e46b8fb1 272 ret = SR_ERR;
e15f48c2 273 }
c8f4624d
UH
274 sr_dbg("demo: %s: setting pattern to %d", __func__,
275 default_pattern);
6239c175 276 } else {
e46b8fb1 277 ret = SR_ERR;
6239c175
UH
278 }
279
280 return ret;
281}
282
5096c6a6 283static void samples_generator(uint8_t *buf, uint64_t size, void *data)
85b5af06 284{
cddd1c5f 285 static uint64_t p = 0;
85b5af06 286 struct databag *mydata = data;
cddd1c5f 287 uint64_t i;
85b5af06 288
c03ed397 289 /* TODO: Needed? */
5096c6a6 290 memset(buf, 0, size);
85b5af06
UH
291
292 switch (mydata->sample_generator) {
c03ed397 293 case PATTERN_SIGROK: /* sigrok pattern */
917e0e71 294 for (i = 0; i < size; i++) {
c8f4624d 295 *(buf + i) = ~(pattern_sigrok[p] >> 1);
917e0e71
BV
296 if (++p == 64)
297 p = 0;
298 }
299 break;
c8f4624d 300 case PATTERN_RANDOM: /* Random */
5096c6a6
UH
301 for (i = 0; i < size; i++)
302 *(buf + i) = (uint8_t)(rand() & 0xff);
85b5af06 303 break;
c8f4624d 304 case PATTERN_INC: /* Simple increment */
5096c6a6 305 for (i = 0; i < size; i++)
85b5af06
UH
306 *(buf + i) = i;
307 break;
c03ed397 308 case PATTERN_ALL_LOW: /* All probes are low */
5a9660dd 309 memset(buf, 0x00, size);
c03ed397
UH
310 break;
311 case PATTERN_ALL_HIGH: /* All probes are high */
5a9660dd 312 memset(buf, 0xff, size);
c03ed397
UH
313 break;
314 default:
315 /* TODO: Error handling. */
316 break;
85b5af06
UH
317 }
318}
319
320/* Thread function */
321static void thread_func(void *data)
322{
323 struct databag *mydata = data;
324 uint8_t buf[BUFSIZE];
325 uint64_t nb_to_send = 0;
d35aaf02 326 int bytes_written;
1924f59f
HE
327 double time_cur, time_last, time_diff;
328
329 time_last = g_timer_elapsed(mydata->timer, NULL);
85b5af06
UH
330
331 while (thread_running) {
1924f59f
HE
332 /* Rate control */
333 time_cur = g_timer_elapsed(mydata->timer, NULL);
334
335 time_diff = time_cur - time_last;
336 time_last = time_cur;
337
338 nb_to_send = cur_samplerate * time_diff;
339
c03ed397 340 if (limit_samples) {
1924f59f 341 nb_to_send = MIN(nb_to_send,
c03ed397
UH
342 limit_samples - mydata->samples_counter);
343 }
1924f59f
HE
344
345 /* Make sure we don't overflow. */
346 nb_to_send = MIN(nb_to_send, BUFSIZE);
347
348 if (nb_to_send) {
349 samples_generator(buf, nb_to_send, data);
350 mydata->samples_counter += nb_to_send;
070befcd
BV
351
352 g_io_channel_write_chars(channels[1], (gchar *)&buf,
c03ed397 353 nb_to_send, (gsize *)&bytes_written, NULL);
b9cc3629
BV
354 }
355
1924f59f
HE
356 /* Check if we're done. */
357 if ((limit_msec && time_cur * 1000 > limit_msec) ||
358 (limit_samples && mydata->samples_counter >= limit_samples))
359 {
85b5af06
UH
360 close(mydata->pipe_fds[1]);
361 thread_running = 0;
85b5af06
UH
362 }
363
1924f59f 364 g_usleep(10);
85b5af06
UH
365 }
366}
367
368/* Callback handling data */
9c939c51 369static int receive_data(int fd, int revents, void *session_data)
85b5af06 370{
b9c735a2 371 struct sr_datafeed_packet packet;
9c939c51
BV
372 struct sr_datafeed_logic logic;
373 static uint64_t samples_received = 0;
374 unsigned char c[BUFSIZE];
108a5bfb 375 gsize z;
1924f59f 376
26ce0bbf 377 /* Avoid compiler warnings. */
cb93f8a9
UH
378 (void)fd;
379 (void)revents;
1924f59f
HE
380
381 do {
382 g_io_channel_read_chars(channels[0],
070befcd 383 (gchar *)&c, BUFSIZE, &z, NULL);
1924f59f
HE
384
385 if (z > 0) {
5a2326a7 386 packet.type = SR_DF_LOGIC;
9c939c51
BV
387 packet.payload = &logic;
388 packet.timeoffset = samples_received * period_ps;
389 packet.duration = z * period_ps;
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
9c939c51 412static int hw_start_acquisition(int device_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;
85b5af06
UH
426 mydata->device_index = device_index;
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
BV
472 packet->payload = header;
473 packet->timeoffset = 0;
474 packet->duration = 0;
6239c175
UH
475 header->feed_version = 1;
476 gettimeofday(&header->starttime, NULL);
477 header->samplerate = cur_samplerate;
c2616fb9
DR
478 header->num_logic_probes = NUM_PROBES;
479 header->num_analog_probes = 0;
9c939c51 480 sr_session_bus(session_data, packet);
27a3a6fe
UH
481 g_free(header);
482 g_free(packet);
6239c175 483
e46b8fb1 484 return SR_OK;
6239c175
UH
485}
486
9c939c51 487static void hw_stop_acquisition(int device_index, gpointer session_data)
6239c175 488{
17e1afcb 489 /* Avoid compiler warnings. */
cb93f8a9
UH
490 (void)device_index;
491 (void)session_data;
6239c175 492
1924f59f
HE
493 /* Stop generate thread. */
494 thread_running = 0;
6239c175
UH
495}
496
5c2d46d1 497struct sr_device_plugin demo_plugin_info = {
e519ba86
UH
498 .name = "demo",
499 .longname = "Demo driver and pattern generator",
500 .api_version = 1,
501 .init = hw_init,
502 .cleanup = hw_cleanup,
86f5e3d8
UH
503 .opendev = hw_opendev,
504 .closedev = hw_closedev,
e519ba86
UH
505 .get_device_info = hw_get_device_info,
506 .get_status = hw_get_status,
507 .get_capabilities = hw_get_capabilities,
508 .set_configuration = hw_set_configuration,
509 .start_acquisition = hw_start_acquisition,
510 .stop_acquisition = hw_stop_acquisition,
6239c175 511};