]> sigrok.org Git - libsigrok.git/blob - hardware/demo/demo.c
91f105f356d524c31533aaf0a31d15d55c8e0f93
[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(const char *devinfo)
144 {
145         struct sr_dev_inst *sdi;
146
147         /* Avoid compiler warnings. */
148         (void)devinfo;
149
150         sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
151         if (!sdi) {
152                 sr_err("demo: %s: sr_dev_inst_new failed", __func__);
153                 return 0;
154         }
155
156         dev_insts = g_slist_append(dev_insts, sdi);
157
158         return 1;
159 }
160
161 static int hw_dev_open(int dev_index)
162 {
163         /* Avoid compiler warnings. */
164         (void)dev_index;
165
166         /* Nothing needed so far. */
167
168         return SR_OK;
169 }
170
171 static int hw_dev_close(int dev_index)
172 {
173         /* Avoid compiler warnings. */
174         (void)dev_index;
175
176         /* Nothing needed so far. */
177
178         return SR_OK;
179 }
180
181 static int hw_cleanup(void)
182 {
183         /* Nothing needed so far. */
184         return SR_OK;
185 }
186
187 static const void *hw_dev_info_get(int dev_index, int dev_info_id)
188 {
189         struct sr_dev_inst *sdi;
190         const void *info = NULL;
191
192         if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) {
193                 sr_err("demo: %s: sdi was NULL", __func__);
194                 return NULL;
195         }
196
197         switch (dev_info_id) {
198         case SR_DI_INST:
199                 info = sdi;
200                 break;
201         case SR_DI_NUM_PROBES:
202                 info = GINT_TO_POINTER(NUM_PROBES);
203                 break;
204         case SR_DI_PROBE_NAMES:
205                 info = probe_names;
206                 break;
207         case SR_DI_SAMPLERATES:
208                 info = &samplerates;
209                 break;
210         case SR_DI_CUR_SAMPLERATE:
211                 info = &cur_samplerate;
212                 break;
213         case SR_DI_PATTERNS:
214                 info = &pattern_strings;
215                 break;
216         }
217
218         return info;
219 }
220
221 static int hw_dev_status_get(int dev_index)
222 {
223         /* Avoid compiler warnings. */
224         (void)dev_index;
225
226         return SR_ST_ACTIVE;
227 }
228
229 static const int *hw_hwcap_get_all(void)
230 {
231         return hwcaps;
232 }
233
234 static int hw_dev_config_set(int dev_index, int hwcap, const void *value)
235 {
236         int ret;
237         const char *stropt;
238
239         /* Avoid compiler warnings. */
240         (void)dev_index;
241
242         if (hwcap == SR_HWCAP_PROBECONFIG) {
243                 /* Nothing to do, but must be supported */
244                 ret = SR_OK;
245         } else if (hwcap == SR_HWCAP_SAMPLERATE) {
246                 cur_samplerate = *(const uint64_t *)value;
247                 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
248                        cur_samplerate);
249                 ret = SR_OK;
250         } else if (hwcap == SR_HWCAP_LIMIT_SAMPLES) {
251                 limit_msec = 0;
252                 limit_samples = *(const uint64_t *)value;
253                 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
254                        limit_samples);
255                 ret = SR_OK;
256         } else if (hwcap == SR_HWCAP_LIMIT_MSEC) {
257                 limit_msec = *(const uint64_t *)value;
258                 limit_samples = 0;
259                 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
260                        limit_msec);
261                 ret = SR_OK;
262         } else if (hwcap == SR_HWCAP_PATTERN_MODE) {
263                 stropt = value;
264                 ret = SR_OK;
265                 if (!strcmp(stropt, "sigrok")) {
266                         default_pattern = PATTERN_SIGROK;
267                 } else if (!strcmp(stropt, "random")) {
268                         default_pattern = PATTERN_RANDOM;
269                 } else if (!strcmp(stropt, "incremental")) {
270                         default_pattern = PATTERN_INC;
271                 } else if (!strcmp(stropt, "all-low")) {
272                         default_pattern = PATTERN_ALL_LOW;
273                 } else if (!strcmp(stropt, "all-high")) {
274                         default_pattern = PATTERN_ALL_HIGH;
275                 } else {
276                         ret = SR_ERR;
277                 }
278                 sr_dbg("demo: %s: setting pattern to %d", __func__,
279                        default_pattern);
280         } else {
281                 ret = SR_ERR;
282         }
283
284         return ret;
285 }
286
287 static void samples_generator(uint8_t *buf, uint64_t size, void *data)
288 {
289         static uint64_t p = 0;
290         struct context *ctx = data;
291         uint64_t i;
292
293         /* TODO: Needed? */
294         memset(buf, 0, size);
295
296         switch (ctx->sample_generator) {
297         case PATTERN_SIGROK: /* sigrok pattern */
298                 for (i = 0; i < size; i++) {
299                         *(buf + i) = ~(pattern_sigrok[p] >> 1);
300                         if (++p == 64)
301                                 p = 0;
302                 }
303                 break;
304         case PATTERN_RANDOM: /* Random */
305                 for (i = 0; i < size; i++)
306                         *(buf + i) = (uint8_t)(rand() & 0xff);
307                 break;
308         case PATTERN_INC: /* Simple increment */
309                 for (i = 0; i < size; i++)
310                         *(buf + i) = i;
311                 break;
312         case PATTERN_ALL_LOW: /* All probes are low */
313                 memset(buf, 0x00, size);
314                 break;
315         case PATTERN_ALL_HIGH: /* All probes are high */
316                 memset(buf, 0xff, size);
317                 break;
318         default:
319                 sr_err("demo: %s: unknown pattern %d", __func__,
320                        ctx->sample_generator);
321                 break;
322         }
323 }
324
325 /* Thread function */
326 static void thread_func(void *data)
327 {
328         struct context *ctx = data;
329         uint8_t buf[BUFSIZE];
330         uint64_t nb_to_send = 0;
331         int bytes_written;
332         double time_cur, time_last, time_diff;
333
334         time_last = g_timer_elapsed(ctx->timer, NULL);
335
336         while (thread_running) {
337                 /* Rate control */
338                 time_cur = g_timer_elapsed(ctx->timer, NULL);
339
340                 time_diff = time_cur - time_last;
341                 time_last = time_cur;
342
343                 nb_to_send = cur_samplerate * time_diff;
344
345                 if (limit_samples) {
346                         nb_to_send = MIN(nb_to_send,
347                                       limit_samples - ctx->samples_counter);
348                 }
349
350                 /* Make sure we don't overflow. */
351                 nb_to_send = MIN(nb_to_send, BUFSIZE);
352
353                 if (nb_to_send) {
354                         samples_generator(buf, nb_to_send, data);
355                         ctx->samples_counter += nb_to_send;
356
357                         g_io_channel_write_chars(ctx->channels[1], (gchar *)&buf,
358                                 nb_to_send, (gsize *)&bytes_written, NULL);
359                 }
360
361                 /* Check if we're done. */
362                 if ((limit_msec && time_cur * 1000 > limit_msec) ||
363                     (limit_samples && ctx->samples_counter >= limit_samples))
364                 {
365                         close(ctx->pipe_fds[1]);
366                         thread_running = 0;
367                 }
368
369                 g_usleep(10);
370         }
371 }
372
373 /* Callback handling data */
374 static int receive_data(int fd, int revents, void *cb_data)
375 {
376         struct context *ctx = cb_data;
377         struct sr_datafeed_packet packet;
378         struct sr_datafeed_logic logic;
379         static uint64_t samples_received = 0;
380         unsigned char c[BUFSIZE];
381         gsize z;
382
383         /* Avoid compiler warnings. */
384         (void)fd;
385         (void)revents;
386
387         do {
388                 g_io_channel_read_chars(ctx->channels[0],
389                                         (gchar *)&c, BUFSIZE, &z, NULL);
390
391                 if (z > 0) {
392                         packet.type = SR_DF_LOGIC;
393                         packet.payload = &logic;
394                         logic.length = z;
395                         logic.unitsize = 1;
396                         logic.data = c;
397                         sr_session_send(ctx->session_dev_id, &packet);
398                         samples_received += z;
399                 }
400         } while (z > 0);
401
402         if (!thread_running && z <= 0) {
403                 /* Make sure we don't receive more packets. */
404                 g_io_channel_shutdown(ctx->channels[0], FALSE, NULL);
405
406                 /* Send last packet. */
407                 packet.type = SR_DF_END;
408                 sr_session_send(ctx->session_dev_id, &packet);
409
410                 return FALSE;
411         }
412
413         return TRUE;
414 }
415
416 static int hw_dev_acquisition_start(int dev_index, void *cb_data)
417 {
418         struct sr_datafeed_packet *packet;
419         struct sr_datafeed_header *header;
420         struct sr_datafeed_meta_logic meta;
421         struct context *ctx;
422
423         /* TODO: 'ctx' is never g_free()'d? */
424         if (!(ctx = g_try_malloc(sizeof(struct context)))) {
425                 sr_err("demo: %s: ctx malloc failed", __func__);
426                 return SR_ERR_MALLOC;
427         }
428
429         ctx->sample_generator = default_pattern;
430         ctx->session_dev_id = cb_data;
431         ctx->dev_index = dev_index;
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 /* TODO: This stops acquisition on ALL devices, ignoring dev_index. */
498 static int hw_dev_acquisition_stop(int dev_index, void *cb_data)
499 {
500         /* Avoid compiler warnings. */
501         (void)dev_index;
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         .dev_open = hw_dev_open,
517         .dev_close = hw_dev_close,
518         .dev_info_get = hw_dev_info_get,
519         .dev_status_get = hw_dev_status_get,
520         .hwcap_get_all = hw_hwcap_get_all,
521         .dev_config_set = hw_dev_config_set,
522         .dev_acquisition_start = hw_dev_acquisition_start,
523         .dev_acquisition_stop = hw_dev_acquisition_stop,
524 };