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