]> sigrok.org Git - libsigrok.git/blob - hardware/demo/demo.c
sr: Fix some TODOs, improve comments/docs.
[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 "sigrok.h"
31 #include "sigrok-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 SR_PRIV GIOChannel *channels[2];
68
69 struct databag {
70         int pipe_fds[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 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 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 void *hw_dev_info_get(int dev_index, int dev_info_id)
188 {
189         struct sr_dev_inst *sdi;
190         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_PATTERNMODES:
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 int *hw_hwcap_get_all(void)
230 {
231         return hwcaps;
232 }
233
234 static int hw_dev_config_set(int dev_index, int hwcap, void *value)
235 {
236         int ret;
237         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 = *(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_samples = *(uint64_t *)value;
252                 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
253                        limit_samples);
254                 ret = SR_OK;
255         } else if (hwcap == SR_HWCAP_LIMIT_MSEC) {
256                 limit_msec = *(uint64_t *)value;
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 databag *mydata = data;
289         uint64_t i;
290
291         /* TODO: Needed? */
292         memset(buf, 0, size);
293
294         switch (mydata->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                        mydata->sample_generator);
319                 break;
320         }
321 }
322
323 /* Thread function */
324 static void thread_func(void *data)
325 {
326         struct databag *mydata = 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(mydata->timer, NULL);
333
334         while (thread_running) {
335                 /* Rate control */
336                 time_cur = g_timer_elapsed(mydata->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 - mydata->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                         mydata->samples_counter += nb_to_send;
354
355                         g_io_channel_write_chars(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 && mydata->samples_counter >= limit_samples))
362                 {
363                         close(mydata->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 sr_datafeed_packet packet;
375         struct sr_datafeed_logic logic;
376         static uint64_t samples_received = 0;
377         unsigned char c[BUFSIZE];
378         gsize z;
379
380         /* Avoid compiler warnings. */
381         (void)fd;
382         (void)revents;
383
384         do {
385                 g_io_channel_read_chars(channels[0],
386                                         (gchar *)&c, BUFSIZE, &z, NULL);
387
388                 if (z > 0) {
389                         packet.type = SR_DF_LOGIC;
390                         packet.payload = &logic;
391                         logic.length = z;
392                         logic.unitsize = 1;
393                         logic.data = c;
394                         sr_session_send(cb_data, &packet);
395                         samples_received += z;
396                 }
397         } while (z > 0);
398
399         if (!thread_running && z <= 0) {
400                 /* Make sure we don't receive more packets. */
401                 g_io_channel_close(channels[0]);
402
403                 /* Send last packet. */
404                 packet.type = SR_DF_END;
405                 sr_session_send(cb_data, &packet);
406
407                 return FALSE;
408         }
409
410         return TRUE;
411 }
412
413 static int hw_dev_acquisition_start(int dev_index, void *cb_data)
414 {
415         struct sr_datafeed_packet *packet;
416         struct sr_datafeed_header *header;
417         struct databag *mydata;
418
419         /* TODO: 'mydata' is never g_free()'d? */
420         if (!(mydata = g_try_malloc(sizeof(struct databag)))) {
421                 sr_err("demo: %s: mydata malloc failed", __func__);
422                 return SR_ERR_MALLOC;
423         }
424
425         mydata->sample_generator = default_pattern;
426         mydata->session_dev_id = cb_data;
427         mydata->dev_index = dev_index;
428         mydata->samples_counter = 0;
429
430         if (pipe(mydata->pipe_fds)) {
431                 /* TODO: Better error message. */
432                 sr_err("demo: %s: pipe() failed", __func__);
433                 return SR_ERR;
434         }
435
436         channels[0] = g_io_channel_unix_new(mydata->pipe_fds[0]);
437         channels[1] = g_io_channel_unix_new(mydata->pipe_fds[1]);
438
439         /* Set channel encoding to binary (default is UTF-8). */
440         g_io_channel_set_encoding(channels[0], NULL, NULL);
441         g_io_channel_set_encoding(channels[1], NULL, NULL);
442
443         /* Make channels to unbuffered. */
444         g_io_channel_set_buffered(channels[0], FALSE);
445         g_io_channel_set_buffered(channels[1], FALSE);
446
447         sr_source_add(mydata->pipe_fds[0], G_IO_IN | G_IO_ERR, 40,
448                       receive_data, mydata->session_dev_id);
449
450         /* Run the demo thread. */
451         g_thread_init(NULL);
452         /* This must to be done between g_thread_init() & g_thread_create(). */
453         mydata->timer = g_timer_new();
454         thread_running = 1;
455         my_thread =
456             g_thread_create((GThreadFunc)thread_func, mydata, TRUE, NULL);
457         if (!my_thread) {
458                 sr_err("demo: %s: g_thread_create failed", __func__);
459                 return SR_ERR; /* TODO */
460         }
461
462         if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
463                 sr_err("demo: %s: packet malloc failed", __func__);
464                 return SR_ERR_MALLOC;
465         }
466
467         if (!(header = g_try_malloc(sizeof(struct sr_datafeed_header)))) {
468                 sr_err("demo: %s: header malloc failed", __func__);
469                 return SR_ERR_MALLOC;
470         }
471
472         packet->type = SR_DF_HEADER;
473         packet->payload = header;
474         header->feed_version = 1;
475         gettimeofday(&header->starttime, NULL);
476         header->samplerate = cur_samplerate;
477         header->num_logic_probes = NUM_PROBES;
478         sr_session_send(mydata->session_dev_id, packet);
479         g_free(header);
480         g_free(packet);
481
482         return SR_OK;
483 }
484
485 /* TODO: This stops acquisition on ALL devices, ignoring dev_index. */
486 static int hw_dev_acquisition_stop(int dev_index, void *cb_data)
487 {
488         /* Avoid compiler warnings. */
489         (void)dev_index;
490         (void)cb_data;
491
492         /* Stop generate thread. */
493         thread_running = 0;
494
495         return SR_OK;
496 }
497
498 SR_PRIV struct sr_dev_driver demo_driver_info = {
499         .name = "demo",
500         .longname = "Demo driver and pattern generator",
501         .api_version = 1,
502         .init = hw_init,
503         .cleanup = hw_cleanup,
504         .dev_open = hw_dev_open,
505         .dev_close = hw_dev_close,
506         .dev_info_get = hw_dev_info_get,
507         .dev_status_get = hw_dev_status_get,
508         .hwcap_get_all = hw_hwcap_get_all,
509         .dev_config_set = hw_dev_config_set,
510         .dev_acquisition_start = hw_dev_acquisition_start,
511         .dev_acquisition_stop = hw_dev_acquisition_stop,
512 };