]> sigrok.org Git - libsigrok.git/blame_incremental - hardware/demo/demo.c
sr: Compile fix for Windows/MinGW.
[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 device_index;
75 gpointer session_data;
76 GTimer *timer;
77};
78
79static int capabilities[] = {
80 SR_HWCAP_LOGIC_ANALYZER,
81 SR_HWCAP_DEMO_DEVICE,
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_device_instance, maintained by opendev()/closedev(). */
129static GSList *device_instances = 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 void hw_stop_acquisition(int device_index, gpointer session_data);
138
139static int hw_init(const char *deviceinfo)
140{
141 struct sr_device_instance *sdi;
142
143 /* Avoid compiler warnings. */
144 (void)deviceinfo;
145
146 sdi = sr_device_instance_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
147 if (!sdi) {
148 sr_err("demo: %s: sr_device_instance_new failed", __func__);
149 return 0;
150 }
151
152 device_instances = g_slist_append(device_instances, sdi);
153
154 return 1;
155}
156
157static int hw_opendev(int device_index)
158{
159 /* Avoid compiler warnings. */
160 (void)device_index;
161
162 /* Nothing needed so far. */
163
164 return SR_OK;
165}
166
167static int hw_closedev(int device_index)
168{
169 /* Avoid compiler warnings. */
170 (void)device_index;
171
172 /* Nothing needed so far. */
173
174 return SR_OK;
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{
184 struct sr_device_instance *sdi;
185 void *info = NULL;
186
187 if (!(sdi = sr_get_device_instance(device_instances, device_index))) {
188 sr_err("demo: %s: sdi was NULL", __func__);
189 return NULL;
190 }
191
192 switch (device_info_id) {
193 case SR_DI_INSTANCE:
194 info = sdi;
195 break;
196 case SR_DI_NUM_PROBES:
197 info = GINT_TO_POINTER(NUM_PROBES);
198 break;
199 case SR_DI_PROBE_NAMES:
200 info = probe_names;
201 break;
202 case SR_DI_SAMPLERATES:
203 info = &samplerates;
204 break;
205 case SR_DI_CUR_SAMPLERATE:
206 info = &cur_samplerate;
207 break;
208 case SR_DI_PATTERNMODES:
209 info = &pattern_strings;
210 break;
211 }
212
213 return info;
214}
215
216static int hw_get_status(int device_index)
217{
218 /* Avoid compiler warnings. */
219 (void)device_index;
220
221 return SR_ST_ACTIVE;
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;
232 char *stropt;
233
234 /* Avoid compiler warnings. */
235 (void)device_index;
236
237 if (capability == SR_HWCAP_PROBECONFIG) {
238 /* Nothing to do, but must be supported */
239 ret = SR_OK;
240 } else if (capability == SR_HWCAP_SAMPLERATE) {
241 cur_samplerate = *(uint64_t *)value;
242 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
243 cur_samplerate);
244 ret = SR_OK;
245 } else if (capability == SR_HWCAP_LIMIT_SAMPLES) {
246 limit_samples = *(uint64_t *)value;
247 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
248 limit_samples);
249 ret = SR_OK;
250 } else if (capability == SR_HWCAP_LIMIT_MSEC) {
251 limit_msec = *(uint64_t *)value;
252 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
253 limit_msec);
254 ret = SR_OK;
255 } else if (capability == SR_HWCAP_PATTERN_MODE) {
256 stropt = value;
257 ret = SR_OK;
258 if (!strcmp(stropt, "sigrok")) {
259 default_pattern = PATTERN_SIGROK;
260 } else if (!strcmp(stropt, "random")) {
261 default_pattern = PATTERN_RANDOM;
262 } else if (!strcmp(stropt, "incremental")) {
263 default_pattern = PATTERN_INC;
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;
268 } else {
269 ret = SR_ERR;
270 }
271 sr_dbg("demo: %s: setting pattern to %d", __func__,
272 default_pattern);
273 } else {
274 ret = SR_ERR;
275 }
276
277 return ret;
278}
279
280static void samples_generator(uint8_t *buf, uint64_t size, void *data)
281{
282 static uint64_t p = 0;
283 struct databag *mydata = data;
284 uint64_t i;
285
286 /* TODO: Needed? */
287 memset(buf, 0, size);
288
289 switch (mydata->sample_generator) {
290 case PATTERN_SIGROK: /* sigrok pattern */
291 for (i = 0; i < size; i++) {
292 *(buf + i) = ~(pattern_sigrok[p] >> 1);
293 if (++p == 64)
294 p = 0;
295 }
296 break;
297 case PATTERN_RANDOM: /* Random */
298 for (i = 0; i < size; i++)
299 *(buf + i) = (uint8_t)(rand() & 0xff);
300 break;
301 case PATTERN_INC: /* Simple increment */
302 for (i = 0; i < size; i++)
303 *(buf + i) = i;
304 break;
305 case PATTERN_ALL_LOW: /* All probes are low */
306 memset(buf, 0x00, size);
307 break;
308 case PATTERN_ALL_HIGH: /* All probes are high */
309 memset(buf, 0xff, size);
310 break;
311 default:
312 /* TODO: Error handling. */
313 break;
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;
323 int bytes_written;
324 double time_cur, time_last, time_diff;
325
326 time_last = g_timer_elapsed(mydata->timer, NULL);
327
328 while (thread_running) {
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
337 if (limit_samples) {
338 nb_to_send = MIN(nb_to_send,
339 limit_samples - mydata->samples_counter);
340 }
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;
348
349 g_io_channel_write_chars(channels[1], (gchar *)&buf,
350 nb_to_send, (gsize *)&bytes_written, NULL);
351 }
352
353 /* Check if we're done. */
354 if ((limit_msec && time_cur * 1000 > limit_msec) ||
355 (limit_samples && mydata->samples_counter >= limit_samples))
356 {
357 close(mydata->pipe_fds[1]);
358 thread_running = 0;
359 }
360
361 g_usleep(10);
362 }
363}
364
365/* Callback handling data */
366static int receive_data(int fd, int revents, void *session_data)
367{
368 struct sr_datafeed_packet packet;
369 struct sr_datafeed_logic logic;
370 static uint64_t samples_received = 0;
371 unsigned char c[BUFSIZE];
372 gsize z;
373
374 /* Avoid compiler warnings. */
375 (void)fd;
376 (void)revents;
377
378 do {
379 g_io_channel_read_chars(channels[0],
380 (gchar *)&c, BUFSIZE, &z, NULL);
381
382 if (z > 0) {
383 packet.type = SR_DF_LOGIC;
384 packet.payload = &logic;
385 logic.length = z;
386 logic.unitsize = 1;
387 logic.data = c;
388 sr_session_bus(session_data, &packet);
389 samples_received += z;
390 }
391 } while (z > 0);
392
393 if (!thread_running && z <= 0) {
394 /* Make sure we don't receive more packets. */
395 g_io_channel_close(channels[0]);
396
397 /* Send last packet. */
398 packet.type = SR_DF_END;
399 sr_session_bus(session_data, &packet);
400
401 return FALSE;
402 }
403
404 return TRUE;
405}
406
407static int hw_start_acquisition(int device_index, gpointer session_data)
408{
409 struct sr_datafeed_packet *packet;
410 struct sr_datafeed_header *header;
411 struct databag *mydata;
412
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__);
416 return SR_ERR_MALLOC;
417 }
418
419 mydata->sample_generator = default_pattern;
420 mydata->session_data = session_data;
421 mydata->device_index = device_index;
422 mydata->samples_counter = 0;
423
424 if (pipe(mydata->pipe_fds)) {
425 /* TODO: Better error message. */
426 sr_err("demo: %s: pipe() failed", __func__);
427 return SR_ERR;
428 }
429
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
441 sr_source_add(mydata->pipe_fds[0], G_IO_IN | G_IO_ERR, 40,
442 receive_data, session_data);
443
444 /* Run the demo thread. */
445 g_thread_init(NULL);
446 /* This must to be done between g_thread_init() & g_thread_create(). */
447 mydata->timer = g_timer_new();
448 thread_running = 1;
449 my_thread =
450 g_thread_create((GThreadFunc)thread_func, mydata, TRUE, NULL);
451 if (!my_thread) {
452 sr_err("demo: %s: g_thread_create failed", __func__);
453 return SR_ERR; /* TODO */
454 }
455
456 if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
457 sr_err("demo: %s: packet malloc failed", __func__);
458 return SR_ERR_MALLOC;
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 }
465
466 packet->type = SR_DF_HEADER;
467 packet->payload = header;
468 header->feed_version = 1;
469 gettimeofday(&header->starttime, NULL);
470 header->samplerate = cur_samplerate;
471 header->num_logic_probes = NUM_PROBES;
472 header->num_analog_probes = 0;
473 sr_session_bus(session_data, packet);
474 g_free(header);
475 g_free(packet);
476
477 return SR_OK;
478}
479
480static void hw_stop_acquisition(int device_index, gpointer session_data)
481{
482 /* Avoid compiler warnings. */
483 (void)device_index;
484 (void)session_data;
485
486 /* Stop generate thread. */
487 thread_running = 0;
488}
489
490SR_PRIV struct sr_device_plugin demo_plugin_info = {
491 .name = "demo",
492 .longname = "Demo driver and pattern generator",
493 .api_version = 1,
494 .init = hw_init,
495 .cleanup = hw_cleanup,
496 .opendev = hw_opendev,
497 .closedev = hw_closedev,
498 .get_device_info = hw_get_device_info,
499 .get_status = hw_get_status,
500 .get_capabilities = hw_get_capabilities,
501 .set_configuration = hw_set_configuration,
502 .start_acquisition = hw_start_acquisition,
503 .stop_acquisition = hw_stop_acquisition,
504};