]> sigrok.org Git - libsigrok.git/blame_incremental - hardware/demo/demo.c
sr/srd: Move some files to their resp. dirs.
[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 "config.h"
31#include "sigrok.h"
32#include "sigrok-internal.h"
33
34/* TODO: Number of probes should be configurable. */
35#define NUM_PROBES 8
36
37#define DEMONAME "Demo device"
38
39/* The size of chunks to send through the session bus. */
40/* TODO: Should be configurable. */
41#define BUFSIZE 4096
42
43/* Supported patterns which we can generate */
44enum {
45 /**
46 * Pattern which spells "sigrok" using '0's (with '1's as "background")
47 * when displayed using the 'bits' output format.
48 */
49 PATTERN_SIGROK,
50
51 /** Pattern which consists of (pseudo-)random values on all probes. */
52 PATTERN_RANDOM,
53
54 /**
55 * Pattern which consists of incrementing numbers.
56 * TODO: Better description.
57 */
58 PATTERN_INC,
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,
65};
66
67/* FIXME: Should not be global. */
68GIOChannel *channels[2];
69
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;
76 gpointer session_data;
77 GTimer *timer;
78};
79
80static int capabilities[] = {
81 SR_HWCAP_LOGIC_ANALYZER,
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 period_ps = 5000000;
132static uint64_t limit_samples = 0;
133static uint64_t limit_msec = 0;
134static int default_pattern = PATTERN_SIGROK;
135static GThread *my_thread;
136static int thread_running;
137
138static void hw_stop_acquisition(int device_index, gpointer session_data);
139
140static int hw_init(const char *deviceinfo)
141{
142 struct sr_device_instance *sdi;
143
144 /* Avoid compiler warnings. */
145 (void)deviceinfo;
146
147 sdi = sr_device_instance_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
148 if (!sdi) {
149 sr_err("demo: %s: sr_device_instance_new failed", __func__);
150 return 0;
151 }
152
153 device_instances = g_slist_append(device_instances, sdi);
154
155 return 1;
156}
157
158static int hw_opendev(int device_index)
159{
160 /* Avoid compiler warnings. */
161 (void)device_index;
162
163 /* Nothing needed so far. */
164
165 return SR_OK;
166}
167
168static int hw_closedev(int device_index)
169{
170 /* Avoid compiler warnings. */
171 (void)device_index;
172
173 /* Nothing needed so far. */
174
175 return SR_OK;
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{
185 struct sr_device_instance *sdi;
186 void *info = NULL;
187
188 if (!(sdi = sr_get_device_instance(device_instances, device_index))) {
189 sr_err("demo: %s: sdi was NULL", __func__);
190 return NULL;
191 }
192
193 switch (device_info_id) {
194 case SR_DI_INSTANCE:
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 device_index)
218{
219 /* Avoid compiler warnings. */
220 (void)device_index;
221
222 return SR_ST_ACTIVE;
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;
233 char *stropt;
234
235 /* Avoid compiler warnings. */
236 (void)device_index;
237
238 if (capability == SR_HWCAP_PROBECONFIG) {
239 /* Nothing to do, but must be supported */
240 ret = SR_OK;
241 } else if (capability == SR_HWCAP_SAMPLERATE) {
242 cur_samplerate = *(uint64_t *)value;
243 period_ps = 1000000000000 / cur_samplerate;
244 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
245 cur_samplerate);
246 ret = SR_OK;
247 } else if (capability == SR_HWCAP_LIMIT_SAMPLES) {
248 limit_samples = *(uint64_t *)value;
249 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
250 limit_samples);
251 ret = SR_OK;
252 } else if (capability == SR_HWCAP_LIMIT_MSEC) {
253 limit_msec = *(uint64_t *)value;
254 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
255 limit_msec);
256 ret = SR_OK;
257 } else if (capability == SR_HWCAP_PATTERN_MODE) {
258 stropt = value;
259 ret = SR_OK;
260 if (!strcmp(stropt, "sigrok")) {
261 default_pattern = PATTERN_SIGROK;
262 } else if (!strcmp(stropt, "random")) {
263 default_pattern = PATTERN_RANDOM;
264 } else if (!strcmp(stropt, "incremental")) {
265 default_pattern = PATTERN_INC;
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;
270 } else {
271 ret = SR_ERR;
272 }
273 sr_dbg("demo: %s: setting pattern to %d", __func__,
274 default_pattern);
275 } else {
276 ret = SR_ERR;
277 }
278
279 return ret;
280}
281
282static void samples_generator(uint8_t *buf, uint64_t size, void *data)
283{
284 static uint64_t p = 0;
285 struct databag *mydata = data;
286 uint64_t i;
287
288 /* TODO: Needed? */
289 memset(buf, 0, size);
290
291 switch (mydata->sample_generator) {
292 case PATTERN_SIGROK: /* sigrok pattern */
293 for (i = 0; i < size; i++) {
294 *(buf + i) = ~(pattern_sigrok[p] >> 1);
295 if (++p == 64)
296 p = 0;
297 }
298 break;
299 case PATTERN_RANDOM: /* Random */
300 for (i = 0; i < size; i++)
301 *(buf + i) = (uint8_t)(rand() & 0xff);
302 break;
303 case PATTERN_INC: /* Simple increment */
304 for (i = 0; i < size; i++)
305 *(buf + i) = i;
306 break;
307 case PATTERN_ALL_LOW: /* All probes are low */
308 memset(buf, 0x00, size);
309 break;
310 case PATTERN_ALL_HIGH: /* All probes are high */
311 memset(buf, 0xff, size);
312 break;
313 default:
314 /* TODO: Error handling. */
315 break;
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;
325 int bytes_written;
326 double time_cur, time_last, time_diff;
327
328 time_last = g_timer_elapsed(mydata->timer, NULL);
329
330 while (thread_running) {
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
339 if (limit_samples) {
340 nb_to_send = MIN(nb_to_send,
341 limit_samples - mydata->samples_counter);
342 }
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;
350
351 g_io_channel_write_chars(channels[1], (gchar *)&buf,
352 nb_to_send, (gsize *)&bytes_written, NULL);
353 }
354
355 /* Check if we're done. */
356 if ((limit_msec && time_cur * 1000 > limit_msec) ||
357 (limit_samples && mydata->samples_counter >= limit_samples))
358 {
359 close(mydata->pipe_fds[1]);
360 thread_running = 0;
361 }
362
363 g_usleep(10);
364 }
365}
366
367/* Callback handling data */
368static int receive_data(int fd, int revents, void *session_data)
369{
370 struct sr_datafeed_packet packet;
371 struct sr_datafeed_logic logic;
372 static uint64_t samples_received = 0;
373 unsigned char c[BUFSIZE];
374 gsize z;
375
376 /* Avoid compiler warnings. */
377 (void)fd;
378 (void)revents;
379
380 do {
381 g_io_channel_read_chars(channels[0],
382 (gchar *)&c, BUFSIZE, &z, NULL);
383
384 if (z > 0) {
385 packet.type = SR_DF_LOGIC;
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;
394 }
395 } while (z > 0);
396
397 if (!thread_running && z <= 0) {
398 /* Make sure we don't receive more packets. */
399 g_io_channel_close(channels[0]);
400
401 /* Send last packet. */
402 packet.type = SR_DF_END;
403 sr_session_bus(session_data, &packet);
404
405 return FALSE;
406 }
407
408 return TRUE;
409}
410
411static int hw_start_acquisition(int device_index, gpointer session_data)
412{
413 struct sr_datafeed_packet *packet;
414 struct sr_datafeed_header *header;
415 struct databag *mydata;
416
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__);
420 return SR_ERR_MALLOC;
421 }
422
423 mydata->sample_generator = default_pattern;
424 mydata->session_data = session_data;
425 mydata->device_index = device_index;
426 mydata->samples_counter = 0;
427
428 if (pipe(mydata->pipe_fds)) {
429 /* TODO: Better error message. */
430 sr_err("demo: %s: pipe() failed", __func__);
431 return SR_ERR;
432 }
433
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
445 sr_source_add(mydata->pipe_fds[0], G_IO_IN | G_IO_ERR, 40,
446 receive_data, session_data);
447
448 /* Run the demo thread. */
449 g_thread_init(NULL);
450 /* This must to be done between g_thread_init() & g_thread_create(). */
451 mydata->timer = g_timer_new();
452 thread_running = 1;
453 my_thread =
454 g_thread_create((GThreadFunc)thread_func, mydata, TRUE, NULL);
455 if (!my_thread) {
456 sr_err("demo: %s: g_thread_create failed", __func__);
457 return SR_ERR; /* TODO */
458 }
459
460 if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
461 sr_err("demo: %s: packet malloc failed", __func__);
462 return SR_ERR_MALLOC;
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 }
469
470 packet->type = SR_DF_HEADER;
471 packet->payload = header;
472 packet->timeoffset = 0;
473 packet->duration = 0;
474 header->feed_version = 1;
475 gettimeofday(&header->starttime, NULL);
476 header->samplerate = cur_samplerate;
477 header->num_logic_probes = NUM_PROBES;
478 header->num_analog_probes = 0;
479 sr_session_bus(session_data, packet);
480 g_free(header);
481 g_free(packet);
482
483 return SR_OK;
484}
485
486static void hw_stop_acquisition(int device_index, gpointer session_data)
487{
488 /* Avoid compiler warnings. */
489 (void)device_index;
490 (void)session_data;
491
492 /* Stop generate thread. */
493 thread_running = 0;
494}
495
496struct sr_device_plugin demo_plugin_info = {
497 .name = "demo",
498 .longname = "Demo driver and pattern generator",
499 .api_version = 1,
500 .init = hw_init,
501 .cleanup = hw_cleanup,
502 .opendev = hw_opendev,
503 .closedev = hw_closedev,
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,
510};