]> sigrok.org Git - libsigrok.git/blame_incremental - hardware/demo/demo.c
demo: Add all-low/all-high pattern support.
[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#include <sigrok.h>
26#include <sigrok-internal.h>
27#ifdef _WIN32
28#include <io.h>
29#include <fcntl.h>
30#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
31#endif
32#include "config.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_device_id;
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 uint8_t pattern_sigrok[] = {
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
116/* List of struct sr_device_instance, maintained by opendev()/closedev(). */
117static GSList *device_instances = NULL;
118static uint64_t cur_samplerate = SR_KHZ(200);
119static uint64_t limit_samples = 0;
120static uint64_t limit_msec = 0;
121static int default_pattern = PATTERN_SIGROK;
122static GThread *my_thread;
123static int thread_running;
124
125static void hw_stop_acquisition(int device_index, gpointer session_device_id);
126
127static int hw_init(const char *deviceinfo)
128{
129 struct sr_device_instance *sdi;
130
131 /* Avoid compiler warnings. */
132 deviceinfo = deviceinfo;
133
134 sdi = sr_device_instance_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
135 if (!sdi) {
136 sr_err("demo: %s: sr_device_instance_new failed", __func__);
137 return 0;
138 }
139
140 device_instances = g_slist_append(device_instances, sdi);
141
142 return 1;
143}
144
145static int hw_opendev(int device_index)
146{
147 /* Avoid compiler warnings. */
148 device_index = device_index;
149
150 /* Nothing needed so far. */
151
152 return SR_OK;
153}
154
155static int hw_closedev(int device_index)
156{
157 /* Avoid compiler warnings. */
158 device_index = device_index;
159
160 /* Nothing needed so far. */
161
162 return SR_OK;
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{
172 struct sr_device_instance *sdi;
173 void *info = NULL;
174
175 if (!(sdi = sr_get_device_instance(device_instances, device_index))) {
176 sr_err("demo: %s: sdi was NULL", __func__);
177 return NULL;
178 }
179
180 switch (device_info_id) {
181 case SR_DI_INSTANCE:
182 info = sdi;
183 break;
184 case SR_DI_NUM_PROBES:
185 info = GINT_TO_POINTER(NUM_PROBES);
186 break;
187 case SR_DI_SAMPLERATES:
188 info = &samplerates;
189 break;
190 case SR_DI_CUR_SAMPLERATE:
191 info = &cur_samplerate;
192 break;
193 case SR_DI_PATTERNMODES:
194 info = &pattern_strings;
195 break;
196 }
197
198 return info;
199}
200
201static int hw_get_status(int device_index)
202{
203 /* Avoid compiler warnings. */
204 device_index = device_index;
205
206 return SR_ST_ACTIVE;
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;
217 char *stropt;
218
219 /* Avoid compiler warnings. */
220 device_index = device_index;
221
222 if (capability == SR_HWCAP_PROBECONFIG) {
223 /* Nothing to do, but must be supported */
224 ret = SR_OK;
225 } else if (capability == SR_HWCAP_SAMPLERATE) {
226 cur_samplerate = *(uint64_t *)value;
227 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
228 cur_samplerate);
229 ret = SR_OK;
230 } else if (capability == SR_HWCAP_LIMIT_SAMPLES) {
231 limit_samples = *(uint64_t *)value;
232 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
233 limit_samples);
234 ret = SR_OK;
235 } else if (capability == SR_HWCAP_LIMIT_MSEC) {
236 limit_msec = *(uint64_t *)value;
237 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
238 limit_msec);
239 ret = SR_OK;
240 } else if (capability == SR_HWCAP_PATTERN_MODE) {
241 stropt = value;
242 ret = SR_OK;
243 if (!strcmp(stropt, "sigrok")) {
244 default_pattern = PATTERN_SIGROK;
245 } else if (!strcmp(stropt, "random")) {
246 default_pattern = PATTERN_RANDOM;
247 } else if (!strcmp(stropt, "incremental")) {
248 default_pattern = PATTERN_INC;
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;
253 } else {
254 ret = SR_ERR;
255 }
256 sr_dbg("demo: %s: setting pattern to %d", __func__,
257 default_pattern);
258 } else {
259 ret = SR_ERR;
260 }
261
262 return ret;
263}
264
265static void samples_generator(uint8_t *buf, uint64_t size, void *data)
266{
267 static uint64_t p = 0;
268 struct databag *mydata = data;
269 uint64_t i;
270
271 /* TODO: Needed? */
272 memset(buf, 0, size);
273
274 switch (mydata->sample_generator) {
275 case PATTERN_SIGROK: /* sigrok pattern */
276 for (i = 0; i < size; i++) {
277 *(buf + i) = ~(pattern_sigrok[p] >> 1);
278 if (++p == 64)
279 p = 0;
280 }
281 break;
282 case PATTERN_RANDOM: /* Random */
283 for (i = 0; i < size; i++)
284 *(buf + i) = (uint8_t)(rand() & 0xff);
285 break;
286 case PATTERN_INC: /* Simple increment */
287 for (i = 0; i < size; i++)
288 *(buf + i) = i;
289 break;
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;
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;
310 int bytes_written;
311 double time_cur, time_last, time_diff;
312
313 time_last = g_timer_elapsed(mydata->timer, NULL);
314
315 while (thread_running) {
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
324 if (limit_samples) {
325 nb_to_send = MIN(nb_to_send,
326 limit_samples - mydata->samples_counter);
327 }
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;
335
336 g_io_channel_write_chars(channels[1], (gchar *)&buf,
337 nb_to_send, (gsize *)&bytes_written, NULL);
338 }
339
340 /* Check if we're done. */
341 if ((limit_msec && time_cur * 1000 > limit_msec) ||
342 (limit_samples && mydata->samples_counter >= limit_samples))
343 {
344 close(mydata->pipe_fds[1]);
345 thread_running = 0;
346 }
347
348 g_usleep(10);
349 }
350}
351
352/* Callback handling data */
353static int receive_data(int fd, int revents, void *user_data)
354{
355 struct sr_datafeed_packet packet;
356 char c[BUFSIZE];
357 gsize z;
358
359 /* Avoid compiler warnings. */
360 fd = fd;
361 revents = revents;
362
363 do {
364 g_io_channel_read_chars(channels[0],
365 (gchar *)&c, BUFSIZE, &z, NULL);
366
367 if (z > 0) {
368 packet.type = SR_DF_LOGIC;
369 packet.length = z;
370 packet.unitsize = 1;
371 packet.payload = c;
372 sr_session_bus(user_data, &packet);
373 }
374 } while (z > 0);
375
376 if (!thread_running && z <= 0) {
377 /* Make sure we don't receive more packets. */
378 g_io_channel_close(channels[0]);
379
380 /* Send last packet. */
381 packet.type = SR_DF_END;
382 sr_session_bus(user_data, &packet);
383
384 return FALSE;
385 }
386
387 return TRUE;
388}
389
390static int hw_start_acquisition(int device_index, gpointer session_device_id)
391{
392 struct sr_datafeed_packet *packet;
393 struct sr_datafeed_header *header;
394 struct databag *mydata;
395
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__);
399 return SR_ERR_MALLOC;
400 }
401
402 mydata->sample_generator = default_pattern;
403 mydata->session_device_id = session_device_id;
404 mydata->device_index = device_index;
405 mydata->samples_counter = 0;
406
407 if (pipe(mydata->pipe_fds)) {
408 /* TODO: Better error message. */
409 sr_err("demo: %s: pipe() failed", __func__);
410 return SR_ERR;
411 }
412
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
424 sr_source_add(mydata->pipe_fds[0], G_IO_IN | G_IO_ERR, 40,
425 receive_data, session_device_id);
426
427 /* Run the demo thread. */
428 g_thread_init(NULL);
429 /* This must to be done between g_thread_init() & g_thread_create(). */
430 mydata->timer = g_timer_new();
431 thread_running = 1;
432 my_thread =
433 g_thread_create((GThreadFunc)thread_func, mydata, TRUE, NULL);
434 if (!my_thread) {
435 sr_err("demo: %s: g_thread_create failed", __func__);
436 return SR_ERR; /* TODO */
437 }
438
439 if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
440 sr_err("demo: %s: packet malloc failed", __func__);
441 return SR_ERR_MALLOC;
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 }
448
449 packet->type = SR_DF_HEADER;
450 packet->length = sizeof(struct sr_datafeed_header);
451 packet->payload = (unsigned char *)header;
452 header->feed_version = 1;
453 gettimeofday(&header->starttime, NULL);
454 header->samplerate = cur_samplerate;
455 header->protocol_id = SR_PROTO_RAW;
456 header->num_logic_probes = NUM_PROBES;
457 header->num_analog_probes = 0;
458 sr_session_bus(session_device_id, packet);
459 g_free(header);
460 g_free(packet);
461
462 return SR_OK;
463}
464
465static void hw_stop_acquisition(int device_index, gpointer session_device_id)
466{
467 /* Avoid compiler warnings. */
468 device_index = device_index;
469 session_device_id = session_device_id;
470
471 /* Stop generate thread. */
472 thread_running = 0;
473}
474
475struct sr_device_plugin demo_plugin_info = {
476 .name = "demo",
477 .longname = "Demo driver and pattern generator",
478 .api_version = 1,
479 .init = hw_init,
480 .cleanup = hw_cleanup,
481 .opendev = hw_opendev,
482 .closedev = hw_closedev,
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,
489};