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