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