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