]> sigrok.org Git - libsigrok.git/blame_incremental - hardware/demo/demo.c
sr/cli/gtk/qt: s/configuration/config/.
[libsigrok.git] / hardware / demo / demo.c
... / ...
CommitLineData
1/*
2 * This file is part of the sigrok project.
3 *
4 * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
5 * Copyright (C) 2011 Olivier Fauchon <olivier@aixmarseille.com>
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>
23#include <unistd.h>
24#include <string.h>
25#ifdef _WIN32
26#include <io.h>
27#include <fcntl.h>
28#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
29#endif
30#include "sigrok.h"
31#include "sigrok-internal.h"
32
33/* TODO: Number of probes should be configurable. */
34#define NUM_PROBES 8
35
36#define DEMONAME "Demo device"
37
38/* The size of chunks to send through the session bus. */
39/* TODO: Should be configurable. */
40#define BUFSIZE 4096
41
42/* Supported patterns which we can generate */
43enum {
44 /**
45 * Pattern which spells "sigrok" using '0's (with '1's as "background")
46 * when displayed using the 'bits' output format.
47 */
48 PATTERN_SIGROK,
49
50 /** Pattern which consists of (pseudo-)random values on all probes. */
51 PATTERN_RANDOM,
52
53 /**
54 * Pattern which consists of incrementing numbers.
55 * TODO: Better description.
56 */
57 PATTERN_INC,
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,
64};
65
66/* FIXME: Should not be global. */
67SR_PRIV GIOChannel *channels[2];
68
69struct databag {
70 int pipe_fds[2];
71 uint8_t sample_generator;
72 uint8_t thread_running;
73 uint64_t samples_counter;
74 int dev_index;
75 gpointer session_data;
76 GTimer *timer;
77};
78
79static int hwcaps[] = {
80 SR_HWCAP_LOGIC_ANALYZER,
81 SR_HWCAP_DEMO_DEV,
82 SR_HWCAP_SAMPLERATE,
83 SR_HWCAP_PATTERN_MODE,
84 SR_HWCAP_LIMIT_SAMPLES,
85 SR_HWCAP_LIMIT_MSEC,
86 SR_HWCAP_CONTINUOUS,
87};
88
89static struct sr_samplerates samplerates = {
90 SR_HZ(1),
91 SR_GHZ(1),
92 SR_HZ(1),
93 NULL,
94};
95
96static const char *pattern_strings[] = {
97 "sigrok",
98 "random",
99 "incremental",
100 "all-low",
101 "all-high",
102 NULL,
103};
104
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
117static uint8_t pattern_sigrok[] = {
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
128/* List of struct sr_dev_inst, maintained by opendev()/closedev(). */
129static GSList *dev_insts = NULL;
130static uint64_t cur_samplerate = SR_KHZ(200);
131static uint64_t limit_samples = 0;
132static uint64_t limit_msec = 0;
133static int default_pattern = PATTERN_SIGROK;
134static GThread *my_thread;
135static int thread_running;
136
137static int hw_stop_acquisition(int dev_index, gpointer session_data);
138
139static int hw_init(const char *devinfo)
140{
141 struct sr_dev_inst *sdi;
142
143 /* Avoid compiler warnings. */
144 (void)devinfo;
145
146 sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
147 if (!sdi) {
148 sr_err("demo: %s: sr_dev_inst_new failed", __func__);
149 return 0;
150 }
151
152 dev_insts = g_slist_append(dev_insts, sdi);
153
154 return 1;
155}
156
157static int hw_opendev(int dev_index)
158{
159 /* Avoid compiler warnings. */
160 (void)dev_index;
161
162 /* Nothing needed so far. */
163
164 return SR_OK;
165}
166
167static int hw_closedev(int dev_index)
168{
169 /* Avoid compiler warnings. */
170 (void)dev_index;
171
172 /* Nothing needed so far. */
173
174 return SR_OK;
175}
176
177static int hw_cleanup(void)
178{
179 /* Nothing needed so far. */
180 return SR_OK;
181}
182
183static void *hw_get_dev_info(int dev_index, int dev_info_id)
184{
185 struct sr_dev_inst *sdi;
186 void *info = NULL;
187
188 if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) {
189 sr_err("demo: %s: sdi was NULL", __func__);
190 return NULL;
191 }
192
193 switch (dev_info_id) {
194 case SR_DI_INST:
195 info = sdi;
196 break;
197 case SR_DI_NUM_PROBES:
198 info = GINT_TO_POINTER(NUM_PROBES);
199 break;
200 case SR_DI_PROBE_NAMES:
201 info = probe_names;
202 break;
203 case SR_DI_SAMPLERATES:
204 info = &samplerates;
205 break;
206 case SR_DI_CUR_SAMPLERATE:
207 info = &cur_samplerate;
208 break;
209 case SR_DI_PATTERNMODES:
210 info = &pattern_strings;
211 break;
212 }
213
214 return info;
215}
216
217static int hw_get_status(int dev_index)
218{
219 /* Avoid compiler warnings. */
220 (void)dev_index;
221
222 return SR_ST_ACTIVE;
223}
224
225static int *hw_hwcap_get_all(void)
226{
227 return hwcaps;
228}
229
230static int hw_config_set(int dev_index, int hwcap, void *value)
231{
232 int ret;
233 char *stropt;
234
235 /* Avoid compiler warnings. */
236 (void)dev_index;
237
238 if (hwcap == SR_HWCAP_PROBECONFIG) {
239 /* Nothing to do, but must be supported */
240 ret = SR_OK;
241 } else if (hwcap == SR_HWCAP_SAMPLERATE) {
242 cur_samplerate = *(uint64_t *)value;
243 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
244 cur_samplerate);
245 ret = SR_OK;
246 } else if (hwcap == SR_HWCAP_LIMIT_SAMPLES) {
247 limit_samples = *(uint64_t *)value;
248 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
249 limit_samples);
250 ret = SR_OK;
251 } else if (hwcap == SR_HWCAP_LIMIT_MSEC) {
252 limit_msec = *(uint64_t *)value;
253 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
254 limit_msec);
255 ret = SR_OK;
256 } else if (hwcap == SR_HWCAP_PATTERN_MODE) {
257 stropt = value;
258 ret = SR_OK;
259 if (!strcmp(stropt, "sigrok")) {
260 default_pattern = PATTERN_SIGROK;
261 } else if (!strcmp(stropt, "random")) {
262 default_pattern = PATTERN_RANDOM;
263 } else if (!strcmp(stropt, "incremental")) {
264 default_pattern = PATTERN_INC;
265 } else if (!strcmp(stropt, "all-low")) {
266 default_pattern = PATTERN_ALL_LOW;
267 } else if (!strcmp(stropt, "all-high")) {
268 default_pattern = PATTERN_ALL_HIGH;
269 } else {
270 ret = SR_ERR;
271 }
272 sr_dbg("demo: %s: setting pattern to %d", __func__,
273 default_pattern);
274 } else {
275 ret = SR_ERR;
276 }
277
278 return ret;
279}
280
281static void samples_generator(uint8_t *buf, uint64_t size, void *data)
282{
283 static uint64_t p = 0;
284 struct databag *mydata = data;
285 uint64_t i;
286
287 /* TODO: Needed? */
288 memset(buf, 0, size);
289
290 switch (mydata->sample_generator) {
291 case PATTERN_SIGROK: /* sigrok pattern */
292 for (i = 0; i < size; i++) {
293 *(buf + i) = ~(pattern_sigrok[p] >> 1);
294 if (++p == 64)
295 p = 0;
296 }
297 break;
298 case PATTERN_RANDOM: /* Random */
299 for (i = 0; i < size; i++)
300 *(buf + i) = (uint8_t)(rand() & 0xff);
301 break;
302 case PATTERN_INC: /* Simple increment */
303 for (i = 0; i < size; i++)
304 *(buf + i) = i;
305 break;
306 case PATTERN_ALL_LOW: /* All probes are low */
307 memset(buf, 0x00, size);
308 break;
309 case PATTERN_ALL_HIGH: /* All probes are high */
310 memset(buf, 0xff, size);
311 break;
312 default:
313 /* TODO: Error handling. */
314 break;
315 }
316}
317
318/* Thread function */
319static void thread_func(void *data)
320{
321 struct databag *mydata = data;
322 uint8_t buf[BUFSIZE];
323 uint64_t nb_to_send = 0;
324 int bytes_written;
325 double time_cur, time_last, time_diff;
326
327 time_last = g_timer_elapsed(mydata->timer, NULL);
328
329 while (thread_running) {
330 /* Rate control */
331 time_cur = g_timer_elapsed(mydata->timer, NULL);
332
333 time_diff = time_cur - time_last;
334 time_last = time_cur;
335
336 nb_to_send = cur_samplerate * time_diff;
337
338 if (limit_samples) {
339 nb_to_send = MIN(nb_to_send,
340 limit_samples - mydata->samples_counter);
341 }
342
343 /* Make sure we don't overflow. */
344 nb_to_send = MIN(nb_to_send, BUFSIZE);
345
346 if (nb_to_send) {
347 samples_generator(buf, nb_to_send, data);
348 mydata->samples_counter += nb_to_send;
349
350 g_io_channel_write_chars(channels[1], (gchar *)&buf,
351 nb_to_send, (gsize *)&bytes_written, NULL);
352 }
353
354 /* Check if we're done. */
355 if ((limit_msec && time_cur * 1000 > limit_msec) ||
356 (limit_samples && mydata->samples_counter >= limit_samples))
357 {
358 close(mydata->pipe_fds[1]);
359 thread_running = 0;
360 }
361
362 g_usleep(10);
363 }
364}
365
366/* Callback handling data */
367static int receive_data(int fd, int revents, void *session_data)
368{
369 struct sr_datafeed_packet packet;
370 struct sr_datafeed_logic logic;
371 static uint64_t samples_received = 0;
372 unsigned char c[BUFSIZE];
373 gsize z;
374
375 /* Avoid compiler warnings. */
376 (void)fd;
377 (void)revents;
378
379 do {
380 g_io_channel_read_chars(channels[0],
381 (gchar *)&c, BUFSIZE, &z, NULL);
382
383 if (z > 0) {
384 packet.type = SR_DF_LOGIC;
385 packet.payload = &logic;
386 logic.length = z;
387 logic.unitsize = 1;
388 logic.data = c;
389 sr_session_bus(session_data, &packet);
390 samples_received += z;
391 }
392 } while (z > 0);
393
394 if (!thread_running && z <= 0) {
395 /* Make sure we don't receive more packets. */
396 g_io_channel_close(channels[0]);
397
398 /* Send last packet. */
399 packet.type = SR_DF_END;
400 sr_session_bus(session_data, &packet);
401
402 return FALSE;
403 }
404
405 return TRUE;
406}
407
408static int hw_start_acquisition(int dev_index, gpointer session_data)
409{
410 struct sr_datafeed_packet *packet;
411 struct sr_datafeed_header *header;
412 struct databag *mydata;
413
414 /* TODO: 'mydata' is never g_free()'d? */
415 if (!(mydata = g_try_malloc(sizeof(struct databag)))) {
416 sr_err("demo: %s: mydata malloc failed", __func__);
417 return SR_ERR_MALLOC;
418 }
419
420 mydata->sample_generator = default_pattern;
421 mydata->session_data = session_data;
422 mydata->dev_index = dev_index;
423 mydata->samples_counter = 0;
424
425 if (pipe(mydata->pipe_fds)) {
426 /* TODO: Better error message. */
427 sr_err("demo: %s: pipe() failed", __func__);
428 return SR_ERR;
429 }
430
431 channels[0] = g_io_channel_unix_new(mydata->pipe_fds[0]);
432 channels[1] = g_io_channel_unix_new(mydata->pipe_fds[1]);
433
434 /* Set channel encoding to binary (default is UTF-8). */
435 g_io_channel_set_encoding(channels[0], NULL, NULL);
436 g_io_channel_set_encoding(channels[1], NULL, NULL);
437
438 /* Make channels to unbuffered. */
439 g_io_channel_set_buffered(channels[0], FALSE);
440 g_io_channel_set_buffered(channels[1], FALSE);
441
442 sr_source_add(mydata->pipe_fds[0], G_IO_IN | G_IO_ERR, 40,
443 receive_data, session_data);
444
445 /* Run the demo thread. */
446 g_thread_init(NULL);
447 /* This must to be done between g_thread_init() & g_thread_create(). */
448 mydata->timer = g_timer_new();
449 thread_running = 1;
450 my_thread =
451 g_thread_create((GThreadFunc)thread_func, mydata, TRUE, NULL);
452 if (!my_thread) {
453 sr_err("demo: %s: g_thread_create failed", __func__);
454 return SR_ERR; /* TODO */
455 }
456
457 if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
458 sr_err("demo: %s: packet malloc failed", __func__);
459 return SR_ERR_MALLOC;
460 }
461
462 if (!(header = g_try_malloc(sizeof(struct sr_datafeed_header)))) {
463 sr_err("demo: %s: header malloc failed", __func__);
464 return SR_ERR_MALLOC;
465 }
466
467 packet->type = SR_DF_HEADER;
468 packet->payload = header;
469 header->feed_version = 1;
470 gettimeofday(&header->starttime, NULL);
471 header->samplerate = cur_samplerate;
472 header->num_logic_probes = NUM_PROBES;
473 sr_session_bus(session_data, packet);
474 g_free(header);
475 g_free(packet);
476
477 return SR_OK;
478}
479
480static int hw_stop_acquisition(int dev_index, gpointer session_data)
481{
482 /* Avoid compiler warnings. */
483 (void)dev_index;
484 (void)session_data;
485
486 /* Stop generate thread. */
487 thread_running = 0;
488
489 return SR_OK;
490}
491
492SR_PRIV struct sr_dev_plugin demo_plugin_info = {
493 .name = "demo",
494 .longname = "Demo driver and pattern generator",
495 .api_version = 1,
496 .init = hw_init,
497 .cleanup = hw_cleanup,
498 .opendev = hw_opendev,
499 .closedev = hw_closedev,
500 .get_dev_info = hw_get_dev_info,
501 .get_status = hw_get_status,
502 .hwcap_get_all = hw_hwcap_get_all,
503 .config_set = hw_config_set,
504 .start_acquisition = hw_start_acquisition,
505 .stop_acquisition = hw_stop_acquisition,
506};