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