]> sigrok.org Git - libsigrok.git/blob - hardware/demo/demo.c
ed8c6f4b1ece8ac7c75962e63e0c5befccd5754d
[libsigrok.git] / hardware / demo / demo.c
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 "libsigrok.h"
31 #include "libsigrok-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 */
43 enum {
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. */
67
68 struct context {
69         int pipe_fds[2];
70         GIOChannel *channels[2];
71         uint8_t sample_generator;
72         uint8_t thread_running;
73         uint64_t samples_counter;
74         int dev_index;
75         void *session_dev_id;
76         GTimer *timer;
77 };
78
79 static const 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
89 static const struct sr_samplerates samplerates = {
90         SR_HZ(1),
91         SR_GHZ(1),
92         SR_HZ(1),
93         NULL,
94 };
95
96 static const char *pattern_strings[] = {
97         "sigrok",
98         "random",
99         "incremental",
100         "all-low",
101         "all-high",
102         NULL,
103 };
104
105 /* We name the probes 0-7 on our demo driver. */
106 static const char *probe_names[NUM_PROBES + 1] = {
107         "0",
108         "1",
109         "2",
110         "3",
111         "4",
112         "5",
113         "6",
114         "7",
115         NULL,
116 };
117
118 static uint8_t pattern_sigrok[] = {
119         0x4c, 0x92, 0x92, 0x92, 0x64, 0x00, 0x00, 0x00,
120         0x82, 0xfe, 0xfe, 0x82, 0x00, 0x00, 0x00, 0x00,
121         0x7c, 0x82, 0x82, 0x92, 0x74, 0x00, 0x00, 0x00,
122         0xfe, 0x12, 0x12, 0x32, 0xcc, 0x00, 0x00, 0x00,
123         0x7c, 0x82, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00,
124         0xfe, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00,
125         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126         0xbe, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 };
128
129 /* Private, per-device-instance driver context. */
130 /* TODO: struct context as with the other drivers. */
131
132 /* List of struct sr_dev_inst, maintained by dev_open()/dev_close(). */
133 static GSList *dev_insts = NULL;
134 static uint64_t cur_samplerate = SR_KHZ(200);
135 static uint64_t limit_samples = 0;
136 static uint64_t limit_msec = 0;
137 static int default_pattern = PATTERN_SIGROK;
138 static GThread *my_thread;
139 static int thread_running;
140
141 static int hw_dev_acquisition_stop(int dev_index, void *cb_data);
142
143 static int hw_init(void)
144 {
145         struct sr_dev_inst *sdi;
146
147         sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
148         if (!sdi) {
149                 sr_err("demo: %s: sr_dev_inst_new failed", __func__);
150                 return 0;
151         }
152
153         dev_insts = g_slist_append(dev_insts, sdi);
154
155         return 1;
156 }
157
158 static int hw_dev_open(int dev_index)
159 {
160         /* Avoid compiler warnings. */
161         (void)dev_index;
162
163         /* Nothing needed so far. */
164
165         return SR_OK;
166 }
167
168 static int hw_dev_close(int dev_index)
169 {
170         /* Avoid compiler warnings. */
171         (void)dev_index;
172
173         /* Nothing needed so far. */
174
175         return SR_OK;
176 }
177
178 static int hw_cleanup(void)
179 {
180         /* Nothing needed so far. */
181         return SR_OK;
182 }
183
184 static const void *hw_dev_info_get(int dev_index, int dev_info_id)
185 {
186         struct sr_dev_inst *sdi;
187         const void *info = NULL;
188
189         if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) {
190                 sr_err("demo: %s: sdi was NULL", __func__);
191                 return NULL;
192         }
193
194         switch (dev_info_id) {
195         case SR_DI_INST:
196                 info = sdi;
197                 break;
198         case SR_DI_NUM_PROBES:
199                 info = GINT_TO_POINTER(NUM_PROBES);
200                 break;
201         case SR_DI_PROBE_NAMES:
202                 info = probe_names;
203                 break;
204         case SR_DI_SAMPLERATES:
205                 info = &samplerates;
206                 break;
207         case SR_DI_CUR_SAMPLERATE:
208                 info = &cur_samplerate;
209                 break;
210         case SR_DI_PATTERNS:
211                 info = &pattern_strings;
212                 break;
213         }
214
215         return info;
216 }
217
218 static int hw_dev_status_get(int dev_index)
219 {
220         /* Avoid compiler warnings. */
221         (void)dev_index;
222
223         return SR_ST_ACTIVE;
224 }
225
226 static const int *hw_hwcap_get_all(void)
227 {
228         return hwcaps;
229 }
230
231 static int hw_dev_config_set(int dev_index, int hwcap, const void *value)
232 {
233         int ret;
234         const char *stropt;
235
236         /* Avoid compiler warnings. */
237         (void)dev_index;
238
239         if (hwcap == SR_HWCAP_PROBECONFIG) {
240                 /* Nothing to do, but must be supported */
241                 ret = SR_OK;
242         } else if (hwcap == SR_HWCAP_SAMPLERATE) {
243                 cur_samplerate = *(const uint64_t *)value;
244                 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
245                        cur_samplerate);
246                 ret = SR_OK;
247         } else if (hwcap == SR_HWCAP_LIMIT_SAMPLES) {
248                 limit_msec = 0;
249                 limit_samples = *(const uint64_t *)value;
250                 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
251                        limit_samples);
252                 ret = SR_OK;
253         } else if (hwcap == SR_HWCAP_LIMIT_MSEC) {
254                 limit_msec = *(const uint64_t *)value;
255                 limit_samples = 0;
256                 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
257                        limit_msec);
258                 ret = SR_OK;
259         } else if (hwcap == SR_HWCAP_PATTERN_MODE) {
260                 stropt = value;
261                 ret = SR_OK;
262                 if (!strcmp(stropt, "sigrok")) {
263                         default_pattern = PATTERN_SIGROK;
264                 } else if (!strcmp(stropt, "random")) {
265                         default_pattern = PATTERN_RANDOM;
266                 } else if (!strcmp(stropt, "incremental")) {
267                         default_pattern = PATTERN_INC;
268                 } else if (!strcmp(stropt, "all-low")) {
269                         default_pattern = PATTERN_ALL_LOW;
270                 } else if (!strcmp(stropt, "all-high")) {
271                         default_pattern = PATTERN_ALL_HIGH;
272                 } else {
273                         ret = SR_ERR;
274                 }
275                 sr_dbg("demo: %s: setting pattern to %d", __func__,
276                        default_pattern);
277         } else {
278                 ret = SR_ERR;
279         }
280
281         return ret;
282 }
283
284 static void samples_generator(uint8_t *buf, uint64_t size, void *data)
285 {
286         static uint64_t p = 0;
287         struct context *ctx = data;
288         uint64_t i;
289
290         /* TODO: Needed? */
291         memset(buf, 0, size);
292
293         switch (ctx->sample_generator) {
294         case PATTERN_SIGROK: /* sigrok pattern */
295                 for (i = 0; i < size; i++) {
296                         *(buf + i) = ~(pattern_sigrok[p] >> 1);
297                         if (++p == 64)
298                                 p = 0;
299                 }
300                 break;
301         case PATTERN_RANDOM: /* Random */
302                 for (i = 0; i < size; i++)
303                         *(buf + i) = (uint8_t)(rand() & 0xff);
304                 break;
305         case PATTERN_INC: /* Simple increment */
306                 for (i = 0; i < size; i++)
307                         *(buf + i) = i;
308                 break;
309         case PATTERN_ALL_LOW: /* All probes are low */
310                 memset(buf, 0x00, size);
311                 break;
312         case PATTERN_ALL_HIGH: /* All probes are high */
313                 memset(buf, 0xff, size);
314                 break;
315         default:
316                 sr_err("demo: %s: unknown pattern %d", __func__,
317                        ctx->sample_generator);
318                 break;
319         }
320 }
321
322 /* Thread function */
323 static void thread_func(void *data)
324 {
325         struct context *ctx = data;
326         uint8_t buf[BUFSIZE];
327         uint64_t nb_to_send = 0;
328         int bytes_written;
329         double time_cur, time_last, time_diff;
330
331         time_last = g_timer_elapsed(ctx->timer, NULL);
332
333         while (thread_running) {
334                 /* Rate control */
335                 time_cur = g_timer_elapsed(ctx->timer, NULL);
336
337                 time_diff = time_cur - time_last;
338                 time_last = time_cur;
339
340                 nb_to_send = cur_samplerate * time_diff;
341
342                 if (limit_samples) {
343                         nb_to_send = MIN(nb_to_send,
344                                       limit_samples - ctx->samples_counter);
345                 }
346
347                 /* Make sure we don't overflow. */
348                 nb_to_send = MIN(nb_to_send, BUFSIZE);
349
350                 if (nb_to_send) {
351                         samples_generator(buf, nb_to_send, data);
352                         ctx->samples_counter += nb_to_send;
353
354                         g_io_channel_write_chars(ctx->channels[1], (gchar *)&buf,
355                                 nb_to_send, (gsize *)&bytes_written, NULL);
356                 }
357
358                 /* Check if we're done. */
359                 if ((limit_msec && time_cur * 1000 > limit_msec) ||
360                     (limit_samples && ctx->samples_counter >= limit_samples))
361                 {
362                         close(ctx->pipe_fds[1]);
363                         thread_running = 0;
364                 }
365
366                 g_usleep(10);
367         }
368 }
369
370 /* Callback handling data */
371 static int receive_data(int fd, int revents, void *cb_data)
372 {
373         struct context *ctx = cb_data;
374         struct sr_datafeed_packet packet;
375         struct sr_datafeed_logic logic;
376         static uint64_t samples_received = 0;
377         unsigned char c[BUFSIZE];
378         gsize z;
379
380         /* Avoid compiler warnings. */
381         (void)fd;
382         (void)revents;
383
384         do {
385                 g_io_channel_read_chars(ctx->channels[0],
386                                         (gchar *)&c, BUFSIZE, &z, NULL);
387
388                 if (z > 0) {
389                         packet.type = SR_DF_LOGIC;
390                         packet.payload = &logic;
391                         logic.length = z;
392                         logic.unitsize = 1;
393                         logic.data = c;
394                         sr_session_send(ctx->session_dev_id, &packet);
395                         samples_received += z;
396                 }
397         } while (z > 0);
398
399         if (!thread_running && z <= 0) {
400                 /* Make sure we don't receive more packets. */
401                 g_io_channel_shutdown(ctx->channels[0], FALSE, NULL);
402
403                 /* Send last packet. */
404                 packet.type = SR_DF_END;
405                 sr_session_send(ctx->session_dev_id, &packet);
406
407                 return FALSE;
408         }
409
410         return TRUE;
411 }
412
413 static int hw_dev_acquisition_start(int dev_index, void *cb_data)
414 {
415         struct sr_datafeed_packet *packet;
416         struct sr_datafeed_header *header;
417         struct sr_datafeed_meta_logic meta;
418         struct context *ctx;
419
420         /* TODO: 'ctx' is never g_free()'d? */
421         if (!(ctx = g_try_malloc(sizeof(struct context)))) {
422                 sr_err("demo: %s: ctx malloc failed", __func__);
423                 return SR_ERR_MALLOC;
424         }
425
426         ctx->sample_generator = default_pattern;
427         ctx->session_dev_id = cb_data;
428         ctx->dev_index = dev_index;
429         ctx->samples_counter = 0;
430
431         if (pipe(ctx->pipe_fds)) {
432                 /* TODO: Better error message. */
433                 sr_err("demo: %s: pipe() failed", __func__);
434                 return SR_ERR;
435         }
436
437         ctx->channels[0] = g_io_channel_unix_new(ctx->pipe_fds[0]);
438         ctx->channels[1] = g_io_channel_unix_new(ctx->pipe_fds[1]);
439
440         g_io_channel_set_flags(ctx->channels[0], G_IO_FLAG_NONBLOCK, NULL);
441
442         /* Set channel encoding to binary (default is UTF-8). */
443         g_io_channel_set_encoding(ctx->channels[0], NULL, NULL);
444         g_io_channel_set_encoding(ctx->channels[1], NULL, NULL);
445
446         /* Make channels to unbuffered. */
447         g_io_channel_set_buffered(ctx->channels[0], FALSE);
448         g_io_channel_set_buffered(ctx->channels[1], FALSE);
449
450         sr_session_source_add_channel(ctx->channels[0], G_IO_IN | G_IO_ERR,
451                     40, receive_data, ctx);
452
453         /* Run the demo thread. */
454         g_thread_init(NULL);
455         /* This must to be done between g_thread_init() & g_thread_create(). */
456         ctx->timer = g_timer_new();
457         thread_running = 1;
458         my_thread =
459             g_thread_create((GThreadFunc)thread_func, ctx, TRUE, NULL);
460         if (!my_thread) {
461                 sr_err("demo: %s: g_thread_create failed", __func__);
462                 return SR_ERR; /* TODO */
463         }
464
465         if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
466                 sr_err("demo: %s: packet malloc failed", __func__);
467                 return SR_ERR_MALLOC;
468         }
469
470         if (!(header = g_try_malloc(sizeof(struct sr_datafeed_header)))) {
471                 sr_err("demo: %s: header malloc failed", __func__);
472                 return SR_ERR_MALLOC;
473         }
474
475         packet->type = SR_DF_HEADER;
476         packet->payload = header;
477         header->feed_version = 1;
478         gettimeofday(&header->starttime, NULL);
479         sr_session_send(ctx->session_dev_id, packet);
480
481         /* Send metadata about the SR_DF_LOGIC packets to come. */
482         packet->type = SR_DF_META_LOGIC;
483         packet->payload = &meta;
484         meta.samplerate = cur_samplerate;
485         meta.num_probes = NUM_PROBES;
486         sr_session_send(ctx->session_dev_id, packet);
487
488         g_free(header);
489         g_free(packet);
490
491         return SR_OK;
492 }
493
494 /* TODO: This stops acquisition on ALL devices, ignoring dev_index. */
495 static int hw_dev_acquisition_stop(int dev_index, void *cb_data)
496 {
497         /* Avoid compiler warnings. */
498         (void)dev_index;
499         (void)cb_data;
500
501         /* Stop generate thread. */
502         thread_running = 0;
503
504         return SR_OK;
505 }
506
507 SR_PRIV struct sr_dev_driver demo_driver_info = {
508         .name = "demo",
509         .longname = "Demo driver and pattern generator",
510         .api_version = 1,
511         .init = hw_init,
512         .cleanup = hw_cleanup,
513         .dev_open = hw_dev_open,
514         .dev_close = hw_dev_close,
515         .dev_info_get = hw_dev_info_get,
516         .dev_status_get = hw_dev_status_get,
517         .hwcap_get_all = hw_hwcap_get_all,
518         .dev_config_set = hw_dev_config_set,
519         .dev_acquisition_start = hw_dev_acquisition_start,
520         .dev_acquisition_stop = hw_dev_acquisition_stop,
521 };