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