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