]> sigrok.org Git - libsigrok.git/blob - hardware/demo/demo.c
add SR_HWCAP_DEMO_DEVICE capability
[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 "config.h"
31 #include "sigrok.h"
32 #include "sigrok-internal.h"
33
34 /* TODO: Number of probes should be configurable. */
35 #define NUM_PROBES             8
36
37 #define DEMONAME               "Demo device"
38
39 /* The size of chunks to send through the session bus. */
40 /* TODO: Should be configurable. */
41 #define BUFSIZE                4096
42
43 /* Supported patterns which we can generate */
44 enum {
45         /**
46          * Pattern which spells "sigrok" using '0's (with '1's as "background")
47          * when displayed using the 'bits' output format.
48          */
49         PATTERN_SIGROK,
50
51         /** Pattern which consists of (pseudo-)random values on all probes. */
52         PATTERN_RANDOM,
53
54         /**
55          * Pattern which consists of incrementing numbers.
56          * TODO: Better description.
57          */
58         PATTERN_INC,
59
60         /** Pattern where all probes have a low logic state. */
61         PATTERN_ALL_LOW,
62
63         /** Pattern where all probes have a high logic state. */
64         PATTERN_ALL_HIGH,
65 };
66
67 /* FIXME: Should not be global. */
68 GIOChannel *channels[2];
69
70 struct databag {
71         int pipe_fds[2];
72         uint8_t sample_generator;
73         uint8_t thread_running;
74         uint64_t samples_counter;
75         int device_index;
76         gpointer session_data;
77         GTimer *timer;
78 };
79
80 static int capabilities[] = {
81         SR_HWCAP_LOGIC_ANALYZER,
82         SR_HWCAP_DEMO_DEVICE,
83         SR_HWCAP_SAMPLERATE,
84         SR_HWCAP_PATTERN_MODE,
85         SR_HWCAP_LIMIT_SAMPLES,
86         SR_HWCAP_LIMIT_MSEC,
87         SR_HWCAP_CONTINUOUS,
88 };
89
90 static struct sr_samplerates samplerates = {
91         SR_HZ(1),
92         SR_GHZ(1),
93         SR_HZ(1),
94         NULL,
95 };
96
97 static const char *pattern_strings[] = {
98         "sigrok",
99         "random",
100         "incremental",
101         "all-low",
102         "all-high",
103         NULL,
104 };
105
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 /* List of struct sr_device_instance, maintained by opendev()/closedev(). */
130 static GSList *device_instances = NULL;
131 static uint64_t cur_samplerate = SR_KHZ(200);
132 static uint64_t period_ps = 5000000;
133 static uint64_t limit_samples = 0;
134 static uint64_t limit_msec = 0;
135 static int default_pattern = PATTERN_SIGROK;
136 static GThread *my_thread;
137 static int thread_running;
138
139 static void hw_stop_acquisition(int device_index, gpointer session_data);
140
141 static int hw_init(const char *deviceinfo)
142 {
143         struct sr_device_instance *sdi;
144
145         /* Avoid compiler warnings. */
146         (void)deviceinfo;
147
148         sdi = sr_device_instance_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
149         if (!sdi) {
150                 sr_err("demo: %s: sr_device_instance_new failed", __func__);
151                 return 0;
152         }
153
154         device_instances = g_slist_append(device_instances, sdi);
155
156         return 1;
157 }
158
159 static int hw_opendev(int device_index)
160 {
161         /* Avoid compiler warnings. */
162         (void)device_index;
163
164         /* Nothing needed so far. */
165
166         return SR_OK;
167 }
168
169 static int hw_closedev(int device_index)
170 {
171         /* Avoid compiler warnings. */
172         (void)device_index;
173
174         /* Nothing needed so far. */
175
176         return SR_OK;
177 }
178
179 static void hw_cleanup(void)
180 {
181         /* Nothing needed so far. */
182 }
183
184 static void *hw_get_device_info(int device_index, int device_info_id)
185 {
186         struct sr_device_instance *sdi;
187         void *info = NULL;
188
189         if (!(sdi = sr_get_device_instance(device_instances, device_index))) {
190                 sr_err("demo: %s: sdi was NULL", __func__);
191                 return NULL;
192         }
193
194         switch (device_info_id) {
195         case SR_DI_INSTANCE:
196                 info = sdi;
197                 break;
198         case SR_DI_NUM_PROBES:
199                 info = GINT_TO_POINTER(NUM_PROBES);
200                 break;
201         case SR_DI_PROBE_NAMES:
202                 info = probe_names;
203                 break;
204         case SR_DI_SAMPLERATES:
205                 info = &samplerates;
206                 break;
207         case SR_DI_CUR_SAMPLERATE:
208                 info = &cur_samplerate;
209                 break;
210         case SR_DI_PATTERNMODES:
211                 info = &pattern_strings;
212                 break;
213         }
214
215         return info;
216 }
217
218 static int hw_get_status(int device_index)
219 {
220         /* Avoid compiler warnings. */
221         (void)device_index;
222
223         return SR_ST_ACTIVE;
224 }
225
226 static int *hw_get_capabilities(void)
227 {
228         return capabilities;
229 }
230
231 static int hw_set_configuration(int device_index, int capability, void *value)
232 {
233         int ret;
234         char *stropt;
235
236         /* Avoid compiler warnings. */
237         (void)device_index;
238
239         if (capability == SR_HWCAP_PROBECONFIG) {
240                 /* Nothing to do, but must be supported */
241                 ret = SR_OK;
242         } else if (capability == SR_HWCAP_SAMPLERATE) {
243                 cur_samplerate = *(uint64_t *)value;
244                 period_ps = 1000000000000 / cur_samplerate;
245                 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
246                        cur_samplerate);
247                 ret = SR_OK;
248         } else if (capability == SR_HWCAP_LIMIT_SAMPLES) {
249                 limit_samples = *(uint64_t *)value;
250                 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
251                        limit_samples);
252                 ret = SR_OK;
253         } else if (capability == SR_HWCAP_LIMIT_MSEC) {
254                 limit_msec = *(uint64_t *)value;
255                 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
256                        limit_msec);
257                 ret = SR_OK;
258         } else if (capability == SR_HWCAP_PATTERN_MODE) {
259                 stropt = value;
260                 ret = SR_OK;
261                 if (!strcmp(stropt, "sigrok")) {
262                         default_pattern = PATTERN_SIGROK;
263                 } else if (!strcmp(stropt, "random")) {
264                         default_pattern = PATTERN_RANDOM;
265                 } else if (!strcmp(stropt, "incremental")) {
266                         default_pattern = PATTERN_INC;
267                 } else if (!strcmp(stropt, "all-low")) {
268                         default_pattern = PATTERN_ALL_LOW;
269                 } else if (!strcmp(stropt, "all-high")) {
270                         default_pattern = PATTERN_ALL_HIGH;
271                 } else {
272                         ret = SR_ERR;
273                 }
274                 sr_dbg("demo: %s: setting pattern to %d", __func__,
275                        default_pattern);
276         } else {
277                 ret = SR_ERR;
278         }
279
280         return ret;
281 }
282
283 static void samples_generator(uint8_t *buf, uint64_t size, void *data)
284 {
285         static uint64_t p = 0;
286         struct databag *mydata = data;
287         uint64_t i;
288
289         /* TODO: Needed? */
290         memset(buf, 0, size);
291
292         switch (mydata->sample_generator) {
293         case PATTERN_SIGROK: /* sigrok pattern */
294                 for (i = 0; i < size; i++) {
295                         *(buf + i) = ~(pattern_sigrok[p] >> 1);
296                         if (++p == 64)
297                                 p = 0;
298                 }
299                 break;
300         case PATTERN_RANDOM: /* Random */
301                 for (i = 0; i < size; i++)
302                         *(buf + i) = (uint8_t)(rand() & 0xff);
303                 break;
304         case PATTERN_INC: /* Simple increment */
305                 for (i = 0; i < size; i++)
306                         *(buf + i) = i;
307                 break;
308         case PATTERN_ALL_LOW: /* All probes are low */
309                 memset(buf, 0x00, size);
310                 break;
311         case PATTERN_ALL_HIGH: /* All probes are high */
312                 memset(buf, 0xff, size);
313                 break;
314         default:
315                 /* TODO: Error handling. */
316                 break;
317         }
318 }
319
320 /* Thread function */
321 static void thread_func(void *data)
322 {
323         struct databag *mydata = data;
324         uint8_t buf[BUFSIZE];
325         uint64_t nb_to_send = 0;
326         int bytes_written;
327         double time_cur, time_last, time_diff;
328
329         time_last = g_timer_elapsed(mydata->timer, NULL);
330
331         while (thread_running) {
332                 /* Rate control */
333                 time_cur = g_timer_elapsed(mydata->timer, NULL);
334
335                 time_diff = time_cur - time_last;
336                 time_last = time_cur;
337
338                 nb_to_send = cur_samplerate * time_diff;
339
340                 if (limit_samples) {
341                         nb_to_send = MIN(nb_to_send,
342                                       limit_samples - mydata->samples_counter);
343                 }
344
345                 /* Make sure we don't overflow. */
346                 nb_to_send = MIN(nb_to_send, BUFSIZE);
347
348                 if (nb_to_send) {
349                         samples_generator(buf, nb_to_send, data);
350                         mydata->samples_counter += nb_to_send;
351
352                         g_io_channel_write_chars(channels[1], (gchar *)&buf,
353                                 nb_to_send, (gsize *)&bytes_written, NULL);
354                 }
355
356                 /* Check if we're done. */
357                 if ((limit_msec && time_cur * 1000 > limit_msec) ||
358                     (limit_samples && mydata->samples_counter >= limit_samples))
359                 {
360                         close(mydata->pipe_fds[1]);
361                         thread_running = 0;
362                 }
363
364                 g_usleep(10);
365         }
366 }
367
368 /* Callback handling data */
369 static int receive_data(int fd, int revents, void *session_data)
370 {
371         struct sr_datafeed_packet packet;
372         struct sr_datafeed_logic logic;
373         static uint64_t samples_received = 0;
374         unsigned char c[BUFSIZE];
375         gsize z;
376
377         /* Avoid compiler warnings. */
378         (void)fd;
379         (void)revents;
380
381         do {
382                 g_io_channel_read_chars(channels[0],
383                                         (gchar *)&c, BUFSIZE, &z, NULL);
384
385                 if (z > 0) {
386                         packet.type = SR_DF_LOGIC;
387                         packet.payload = &logic;
388                         packet.timeoffset =  samples_received * period_ps;
389                         packet.duration = z * period_ps;
390                         logic.length = z;
391                         logic.unitsize = 1;
392                         logic.data = c;
393                         sr_session_bus(session_data, &packet);
394                         samples_received += z;
395                 }
396         } while (z > 0);
397
398         if (!thread_running && z <= 0) {
399                 /* Make sure we don't receive more packets. */
400                 g_io_channel_close(channels[0]);
401
402                 /* Send last packet. */
403                 packet.type = SR_DF_END;
404                 sr_session_bus(session_data, &packet);
405
406                 return FALSE;
407         }
408
409         return TRUE;
410 }
411
412 static int hw_start_acquisition(int device_index, gpointer session_data)
413 {
414         struct sr_datafeed_packet *packet;
415         struct sr_datafeed_header *header;
416         struct databag *mydata;
417
418         /* TODO: 'mydata' is never g_free()'d? */
419         if (!(mydata = g_try_malloc(sizeof(struct databag)))) {
420                 sr_err("demo: %s: mydata malloc failed", __func__);
421                 return SR_ERR_MALLOC;
422         }
423
424         mydata->sample_generator = default_pattern;
425         mydata->session_data = session_data;
426         mydata->device_index = device_index;
427         mydata->samples_counter = 0;
428
429         if (pipe(mydata->pipe_fds)) {
430                 /* TODO: Better error message. */
431                 sr_err("demo: %s: pipe() failed", __func__);
432                 return SR_ERR;
433         }
434
435         channels[0] = g_io_channel_unix_new(mydata->pipe_fds[0]);
436         channels[1] = g_io_channel_unix_new(mydata->pipe_fds[1]);
437
438         /* Set channel encoding to binary (default is UTF-8). */
439         g_io_channel_set_encoding(channels[0], NULL, NULL);
440         g_io_channel_set_encoding(channels[1], NULL, NULL);
441
442         /* Make channels to unbuffered. */
443         g_io_channel_set_buffered(channels[0], FALSE);
444         g_io_channel_set_buffered(channels[1], FALSE);
445
446         sr_source_add(mydata->pipe_fds[0], G_IO_IN | G_IO_ERR, 40,
447                       receive_data, session_data);
448
449         /* Run the demo thread. */
450         g_thread_init(NULL);
451         /* This must to be done between g_thread_init() & g_thread_create(). */
452         mydata->timer = g_timer_new();
453         thread_running = 1;
454         my_thread =
455             g_thread_create((GThreadFunc)thread_func, mydata, TRUE, NULL);
456         if (!my_thread) {
457                 sr_err("demo: %s: g_thread_create failed", __func__);
458                 return SR_ERR; /* TODO */
459         }
460
461         if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
462                 sr_err("demo: %s: packet malloc failed", __func__);
463                 return SR_ERR_MALLOC;
464         }
465
466         if (!(header = g_try_malloc(sizeof(struct sr_datafeed_header)))) {
467                 sr_err("demo: %s: header malloc failed", __func__);
468                 return SR_ERR_MALLOC;
469         }
470
471         packet->type = SR_DF_HEADER;
472         packet->payload = header;
473         packet->timeoffset = 0;
474         packet->duration = 0;
475         header->feed_version = 1;
476         gettimeofday(&header->starttime, NULL);
477         header->samplerate = cur_samplerate;
478         header->num_logic_probes = NUM_PROBES;
479         header->num_analog_probes = 0;
480         sr_session_bus(session_data, packet);
481         g_free(header);
482         g_free(packet);
483
484         return SR_OK;
485 }
486
487 static void hw_stop_acquisition(int device_index, gpointer session_data)
488 {
489         /* Avoid compiler warnings. */
490         (void)device_index;
491         (void)session_data;
492
493         /* Stop generate thread. */
494         thread_running = 0;
495 }
496
497 struct sr_device_plugin demo_plugin_info = {
498         .name = "demo",
499         .longname = "Demo driver and pattern generator",
500         .api_version = 1,
501         .init = hw_init,
502         .cleanup = hw_cleanup,
503         .opendev = hw_opendev,
504         .closedev = hw_closedev,
505         .get_device_info = hw_get_device_info,
506         .get_status = hw_get_status,
507         .get_capabilities = hw_get_capabilities,
508         .set_configuration = hw_set_configuration,
509         .start_acquisition = hw_start_acquisition,
510         .stop_acquisition = hw_stop_acquisition,
511 };