]> sigrok.org Git - libsigrok.git/blame - hardware/demo/demo.c
demo: Add all-low/all-high pattern support.
[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;
e15f48c2 76 gpointer session_device_id;
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);
b9cc3629
BV
119static uint64_t limit_samples = 0;
120static uint64_t limit_msec = 0;
c8f4624d 121static int default_pattern = PATTERN_SIGROK;
b9cc3629
BV
122static GThread *my_thread;
123static int thread_running;
6239c175 124
6239c175
UH
125static void hw_stop_acquisition(int device_index, gpointer session_device_id);
126
54ac5277 127static int hw_init(const char *deviceinfo)
6239c175 128{
a00ba012 129 struct sr_device_instance *sdi;
85b5af06 130
e15f48c2
BV
131 /* Avoid compiler warnings. */
132 deviceinfo = deviceinfo;
85b5af06 133
5a2326a7 134 sdi = sr_device_instance_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
c03ed397
UH
135 if (!sdi) {
136 sr_err("demo: %s: sr_device_instance_new failed", __func__);
85b5af06 137 return 0;
c03ed397 138 }
e15f48c2 139
85b5af06
UH
140 device_instances = g_slist_append(device_instances, sdi);
141
142 return 1;
6239c175
UH
143}
144
145static int hw_opendev(int device_index)
146{
17e1afcb 147 /* Avoid compiler warnings. */
6239c175
UH
148 device_index = device_index;
149
150 /* Nothing needed so far. */
697785d1 151
e46b8fb1 152 return SR_OK;
6239c175
UH
153}
154
697785d1 155static int hw_closedev(int device_index)
6239c175 156{
17e1afcb 157 /* Avoid compiler warnings. */
6239c175
UH
158 device_index = device_index;
159
160 /* Nothing needed so far. */
697785d1
UH
161
162 return SR_OK;
6239c175
UH
163}
164
165static void hw_cleanup(void)
166{
167 /* Nothing needed so far. */
168}
169
170static void *hw_get_device_info(int device_index, int device_info_id)
171{
a00ba012 172 struct sr_device_instance *sdi;
85b5af06
UH
173 void *info = NULL;
174
c03ed397
UH
175 if (!(sdi = sr_get_device_instance(device_instances, device_index))) {
176 sr_err("demo: %s: sdi was NULL", __func__);
85b5af06 177 return NULL;
c03ed397 178 }
85b5af06 179
6239c175 180 switch (device_info_id) {
5a2326a7 181 case SR_DI_INSTANCE:
85b5af06 182 info = sdi;
6239c175 183 break;
5a2326a7 184 case SR_DI_NUM_PROBES:
6239c175
UH
185 info = GINT_TO_POINTER(NUM_PROBES);
186 break;
4bfbf9fc
BV
187 case SR_DI_SAMPLERATES:
188 info = &samplerates;
189 break;
5a2326a7 190 case SR_DI_CUR_SAMPLERATE:
6239c175
UH
191 info = &cur_samplerate;
192 break;
5a2326a7 193 case SR_DI_PATTERNMODES:
c8f4624d 194 info = &pattern_strings;
e15f48c2 195 break;
6239c175
UH
196 }
197
198 return info;
199}
200
201static int hw_get_status(int device_index)
202{
17e1afcb 203 /* Avoid compiler warnings. */
6239c175 204 device_index = device_index;
5096c6a6 205
5a2326a7 206 return SR_ST_ACTIVE;
6239c175
UH
207}
208
209static int *hw_get_capabilities(void)
210{
211 return capabilities;
212}
213
214static int hw_set_configuration(int device_index, int capability, void *value)
215{
216 int ret;
e15f48c2 217 char *stropt;
6239c175 218
17e1afcb 219 /* Avoid compiler warnings. */
6239c175
UH
220 device_index = device_index;
221
5a2326a7 222 if (capability == SR_HWCAP_PROBECONFIG) {
d81d2933
BV
223 /* Nothing to do, but must be supported */
224 ret = SR_OK;
225 } else if (capability == SR_HWCAP_SAMPLERATE) {
68c12597 226 cur_samplerate = *(uint64_t *)value;
6f422264
UH
227 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
228 cur_samplerate);
e46b8fb1 229 ret = SR_OK;
5a2326a7 230 } else if (capability == SR_HWCAP_LIMIT_SAMPLES) {
68c12597 231 limit_samples = *(uint64_t *)value;
6f422264
UH
232 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
233 limit_samples);
e46b8fb1 234 ret = SR_OK;
5a2326a7 235 } else if (capability == SR_HWCAP_LIMIT_MSEC) {
68c12597 236 limit_msec = *(uint64_t *)value;
6f422264
UH
237 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
238 limit_msec);
e46b8fb1 239 ret = SR_OK;
5a2326a7 240 } else if (capability == SR_HWCAP_PATTERN_MODE) {
e15f48c2 241 stropt = value;
c03ed397
UH
242 ret = SR_OK;
243 if (!strcmp(stropt, "sigrok")) {
244 default_pattern = PATTERN_SIGROK;
245 } else if (!strcmp(stropt, "random")) {
c8f4624d 246 default_pattern = PATTERN_RANDOM;
e15f48c2 247 } else if (!strcmp(stropt, "incremental")) {
c8f4624d 248 default_pattern = PATTERN_INC;
c03ed397
UH
249 } else if (!strcmp(stropt, "all-low")) {
250 default_pattern = PATTERN_ALL_LOW;
251 } else if (!strcmp(stropt, "all-high")) {
252 default_pattern = PATTERN_ALL_HIGH;
e15f48c2 253 } else {
e46b8fb1 254 ret = SR_ERR;
e15f48c2 255 }
c8f4624d
UH
256 sr_dbg("demo: %s: setting pattern to %d", __func__,
257 default_pattern);
6239c175 258 } else {
e46b8fb1 259 ret = SR_ERR;
6239c175
UH
260 }
261
262 return ret;
263}
264
5096c6a6 265static void samples_generator(uint8_t *buf, uint64_t size, void *data)
85b5af06 266{
cddd1c5f 267 static uint64_t p = 0;
85b5af06 268 struct databag *mydata = data;
cddd1c5f 269 uint64_t i;
85b5af06 270
c03ed397 271 /* TODO: Needed? */
5096c6a6 272 memset(buf, 0, size);
85b5af06
UH
273
274 switch (mydata->sample_generator) {
c03ed397 275 case PATTERN_SIGROK: /* sigrok pattern */
917e0e71 276 for (i = 0; i < size; i++) {
c8f4624d 277 *(buf + i) = ~(pattern_sigrok[p] >> 1);
917e0e71
BV
278 if (++p == 64)
279 p = 0;
280 }
281 break;
c8f4624d 282 case PATTERN_RANDOM: /* Random */
5096c6a6
UH
283 for (i = 0; i < size; i++)
284 *(buf + i) = (uint8_t)(rand() & 0xff);
85b5af06 285 break;
c8f4624d 286 case PATTERN_INC: /* Simple increment */
5096c6a6 287 for (i = 0; i < size; i++)
85b5af06
UH
288 *(buf + i) = i;
289 break;
c03ed397
UH
290 case PATTERN_ALL_LOW: /* All probes are low */
291 for (i = 0; i < size; i++)
292 *(buf + i) = 0x00;
293 break;
294 case PATTERN_ALL_HIGH: /* All probes are high */
295 for (i = 0; i < size; i++)
296 *(buf + i) = 0xff;
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 */
353static int receive_data(int fd, int revents, void *user_data)
354{
b9c735a2 355 struct sr_datafeed_packet packet;
26ce0bbf 356 char c[BUFSIZE];
108a5bfb 357 gsize z;
1924f59f 358
26ce0bbf
UH
359 /* Avoid compiler warnings. */
360 fd = fd;
361 revents = revents;
1924f59f
HE
362
363 do {
364 g_io_channel_read_chars(channels[0],
070befcd 365 (gchar *)&c, BUFSIZE, &z, NULL);
1924f59f
HE
366
367 if (z > 0) {
5a2326a7 368 packet.type = SR_DF_LOGIC;
1924f59f
HE
369 packet.length = z;
370 packet.unitsize = 1;
371 packet.payload = c;
8a2efef2 372 sr_session_bus(user_data, &packet);
1924f59f
HE
373 }
374 } while (z > 0);
85b5af06 375
c03ed397
UH
376 if (!thread_running && z <= 0) {
377 /* Make sure we don't receive more packets. */
1924f59f 378 g_io_channel_close(channels[0]);
d35aaf02 379
1924f59f 380 /* Send last packet. */
5a2326a7 381 packet.type = SR_DF_END;
8a2efef2 382 sr_session_bus(user_data, &packet);
1924f59f
HE
383
384 return FALSE;
85b5af06 385 }
1924f59f 386
85b5af06
UH
387 return TRUE;
388}
389
6239c175
UH
390static int hw_start_acquisition(int device_index, gpointer session_device_id)
391{
b9c735a2
UH
392 struct sr_datafeed_packet *packet;
393 struct sr_datafeed_header *header;
85b5af06 394 struct databag *mydata;
6239c175 395
27a3a6fe
UH
396 /* TODO: 'mydata' is never g_free()'d? */
397 if (!(mydata = g_try_malloc(sizeof(struct databag)))) {
398 sr_err("demo: %s: mydata malloc failed", __func__);
e46b8fb1 399 return SR_ERR_MALLOC;
27a3a6fe 400 }
85b5af06 401
c8f4624d 402 mydata->sample_generator = default_pattern;
85b5af06
UH
403 mydata->session_device_id = session_device_id;
404 mydata->device_index = device_index;
405 mydata->samples_counter = 0;
85b5af06 406
c03ed397
UH
407 if (pipe(mydata->pipe_fds)) {
408 /* TODO: Better error message. */
409 sr_err("demo: %s: pipe() failed", __func__);
e46b8fb1 410 return SR_ERR;
c03ed397 411 }
85b5af06 412
d35aaf02
UH
413 channels[0] = g_io_channel_unix_new(mydata->pipe_fds[0]);
414 channels[1] = g_io_channel_unix_new(mydata->pipe_fds[1]);
415
416 /* Set channel encoding to binary (default is UTF-8). */
417 g_io_channel_set_encoding(channels[0], NULL, NULL);
418 g_io_channel_set_encoding(channels[1], NULL, NULL);
419
420 /* Make channels to unbuffered. */
421 g_io_channel_set_buffered(channels[0], FALSE);
422 g_io_channel_set_buffered(channels[1], FALSE);
423
6f1be0a2
UH
424 sr_source_add(mydata->pipe_fds[0], G_IO_IN | G_IO_ERR, 40,
425 receive_data, session_device_id);
85b5af06
UH
426
427 /* Run the demo thread. */
428 g_thread_init(NULL);
c03ed397 429 /* This must to be done between g_thread_init() & g_thread_create(). */
1924f59f 430 mydata->timer = g_timer_new();
85b5af06
UH
431 thread_running = 1;
432 my_thread =
433 g_thread_create((GThreadFunc)thread_func, mydata, TRUE, NULL);
c03ed397
UH
434 if (!my_thread) {
435 sr_err("demo: %s: g_thread_create failed", __func__);
436 return SR_ERR; /* TODO */
437 }
6239c175 438
27a3a6fe
UH
439 if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
440 sr_err("demo: %s: packet malloc failed", __func__);
e46b8fb1 441 return SR_ERR_MALLOC;
27a3a6fe
UH
442 }
443
444 if (!(header = g_try_malloc(sizeof(struct sr_datafeed_header)))) {
445 sr_err("demo: %s: header malloc failed", __func__);
446 return SR_ERR_MALLOC;
447 }
6239c175 448
5a2326a7 449 packet->type = SR_DF_HEADER;
b9c735a2 450 packet->length = sizeof(struct sr_datafeed_header);
6239c175
UH
451 packet->payload = (unsigned char *)header;
452 header->feed_version = 1;
453 gettimeofday(&header->starttime, NULL);
454 header->samplerate = cur_samplerate;
5a2326a7 455 header->protocol_id = SR_PROTO_RAW;
c2616fb9
DR
456 header->num_logic_probes = NUM_PROBES;
457 header->num_analog_probes = 0;
8a2efef2 458 sr_session_bus(session_device_id, packet);
27a3a6fe
UH
459 g_free(header);
460 g_free(packet);
6239c175 461
e46b8fb1 462 return SR_OK;
6239c175
UH
463}
464
6239c175
UH
465static void hw_stop_acquisition(int device_index, gpointer session_device_id)
466{
17e1afcb 467 /* Avoid compiler warnings. */
6239c175 468 device_index = device_index;
1924f59f 469 session_device_id = session_device_id;
6239c175 470
1924f59f
HE
471 /* Stop generate thread. */
472 thread_running = 0;
6239c175
UH
473}
474
5c2d46d1 475struct sr_device_plugin demo_plugin_info = {
e519ba86
UH
476 .name = "demo",
477 .longname = "Demo driver and pattern generator",
478 .api_version = 1,
479 .init = hw_init,
480 .cleanup = hw_cleanup,
86f5e3d8
UH
481 .opendev = hw_opendev,
482 .closedev = hw_closedev,
e519ba86
UH
483 .get_device_info = hw_get_device_info,
484 .get_status = hw_get_status,
485 .get_capabilities = hw_get_capabilities,
486 .set_configuration = hw_set_configuration,
487 .start_acquisition = hw_start_acquisition,
488 .stop_acquisition = hw_stop_acquisition,
6239c175 489};