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