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