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