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