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