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