]> sigrok.org Git - libsigrok.git/blame - hardware/demo/demo.c
demo: Rename GENMODE_DEFAULT to GENMODE_SIGROK.
[libsigrok.git] / hardware / demo / demo.c
CommitLineData
6239c175
UH
1/*
2 * This file is part of the sigrok project.
3 *
4 * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
fc96e6f8 5 * Copyright (C) 2011 Olivier Fauchon <olivier@aixmarseille.com>
6239c175
UH
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>
85b5af06 23#include <unistd.h>
6239c175
UH
24#include <string.h>
25#include <sigrok.h>
4af22da5 26#include <sigrok-internal.h>
d35aaf02
UH
27#ifdef _WIN32
28#include <io.h>
29#include <fcntl.h>
30#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
31#endif
6239c175
UH
32#include "config.h"
33
e15f48c2
BV
34#define NUM_PROBES 8
35#define DEMONAME "Demo device"
36/* size of chunks to send through the session bus */
37#define BUFSIZE 4096
85b5af06 38
0d31276b 39/* Supported patterns which we can generate */
e15f48c2 40enum {
0d31276b
UH
41 /**
42 * Pattern which spells "sigrok" using '0's (with '1's as "background")
43 * when displayed using the 'bits' output format.
44 */
45 GENMODE_SIGROK,
46
47 /**
48 * Pattern which consists of (pseudo-)random values on all probes.
49 */
e15f48c2 50 GENMODE_RANDOM,
0d31276b
UH
51
52 /**
53 * Pattern which consists of incrementing numbers.
54 * TODO: Better description.
55 */
e15f48c2
BV
56 GENMODE_INC,
57};
85b5af06 58
29cbfeaf 59/* FIXME: Should not be global. */
d35aaf02
UH
60GIOChannel *channels[2];
61
e15f48c2
BV
62struct databag {
63 int pipe_fds[2];
64 uint8_t sample_generator;
65 uint8_t thread_running;
66 uint64_t samples_counter;
67 int device_index;
e15f48c2 68 gpointer session_device_id;
b9cc3629 69 GTimer *timer;
e15f48c2 70};
85b5af06 71
6239c175 72static int capabilities[] = {
5a2326a7 73 SR_HWCAP_LOGIC_ANALYZER,
4bfbf9fc 74 SR_HWCAP_SAMPLERATE,
5a2326a7
UH
75 SR_HWCAP_PATTERN_MODE,
76 SR_HWCAP_LIMIT_SAMPLES,
77 SR_HWCAP_LIMIT_MSEC,
78 SR_HWCAP_CONTINUOUS,
6239c175
UH
79};
80
4bfbf9fc 81static struct sr_samplerates samplerates = {
c9140419 82 SR_HZ(1),
59df0c77 83 SR_GHZ(1),
c9140419 84 SR_HZ(1),
4bfbf9fc
BV
85 NULL,
86};
87
02440dd8 88static const char *patternmodes[] = {
e15f48c2
BV
89 "random",
90 "incremental",
02440dd8 91 NULL,
85b5af06
UH
92};
93
0d31276b 94static uint8_t genmode_sigrok[] = {
917e0e71
BV
95 0x4c, 0x92, 0x92, 0x92, 0x64, 0x00, 0x00, 0x00,
96 0x82, 0xfe, 0xfe, 0x82, 0x00, 0x00, 0x00, 0x00,
97 0x7c, 0x82, 0x82, 0x92, 0x74, 0x00, 0x00, 0x00,
98 0xfe, 0x12, 0x12, 0x32, 0xcc, 0x00, 0x00, 0x00,
99 0x7c, 0x82, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00,
100 0xfe, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0xbe, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103};
104
a00ba012 105/* List of struct sr_device_instance, maintained by opendev()/closedev(). */
85b5af06 106static GSList *device_instances = NULL;
59df0c77 107static uint64_t cur_samplerate = SR_KHZ(200);
b9cc3629
BV
108static uint64_t limit_samples = 0;
109static uint64_t limit_msec = 0;
0d31276b 110static int default_genmode = GENMODE_SIGROK;
b9cc3629
BV
111static GThread *my_thread;
112static int thread_running;
6239c175 113
6239c175
UH
114static void hw_stop_acquisition(int device_index, gpointer session_device_id);
115
54ac5277 116static int hw_init(const char *deviceinfo)
6239c175 117{
a00ba012 118 struct sr_device_instance *sdi;
85b5af06 119
e15f48c2
BV
120 /* Avoid compiler warnings. */
121 deviceinfo = deviceinfo;
85b5af06 122
5a2326a7 123 sdi = sr_device_instance_new(0, SR_ST_ACTIVE, DEMONAME, NULL, NULL);
85b5af06
UH
124 if (!sdi)
125 return 0;
e15f48c2 126
85b5af06
UH
127 device_instances = g_slist_append(device_instances, sdi);
128
129 return 1;
6239c175
UH
130}
131
132static int hw_opendev(int device_index)
133{
17e1afcb 134 /* Avoid compiler warnings. */
6239c175
UH
135 device_index = device_index;
136
137 /* Nothing needed so far. */
697785d1 138
e46b8fb1 139 return SR_OK;
6239c175
UH
140}
141
697785d1 142static int hw_closedev(int device_index)
6239c175 143{
17e1afcb 144 /* Avoid compiler warnings. */
6239c175
UH
145 device_index = device_index;
146
147 /* Nothing needed so far. */
697785d1
UH
148
149 return SR_OK;
6239c175
UH
150}
151
152static void hw_cleanup(void)
153{
154 /* Nothing needed so far. */
155}
156
157static void *hw_get_device_info(int device_index, int device_info_id)
158{
a00ba012 159 struct sr_device_instance *sdi;
85b5af06
UH
160 void *info = NULL;
161
d32d961d 162 if (!(sdi = sr_get_device_instance(device_instances, device_index)))
85b5af06
UH
163 return NULL;
164
6239c175 165 switch (device_info_id) {
5a2326a7 166 case SR_DI_INSTANCE:
85b5af06 167 info = sdi;
6239c175 168 break;
5a2326a7 169 case SR_DI_NUM_PROBES:
6239c175
UH
170 info = GINT_TO_POINTER(NUM_PROBES);
171 break;
4bfbf9fc
BV
172 case SR_DI_SAMPLERATES:
173 info = &samplerates;
174 break;
5a2326a7 175 case SR_DI_CUR_SAMPLERATE:
6239c175
UH
176 info = &cur_samplerate;
177 break;
5a2326a7 178 case SR_DI_PATTERNMODES:
e15f48c2
BV
179 info = &patternmodes;
180 break;
6239c175
UH
181 }
182
183 return info;
184}
185
186static int hw_get_status(int device_index)
187{
17e1afcb 188 /* Avoid compiler warnings. */
6239c175 189 device_index = device_index;
5096c6a6 190
5a2326a7 191 return SR_ST_ACTIVE;
6239c175
UH
192}
193
194static int *hw_get_capabilities(void)
195{
196 return capabilities;
197}
198
199static int hw_set_configuration(int device_index, int capability, void *value)
200{
201 int ret;
e15f48c2 202 char *stropt;
6239c175 203
17e1afcb 204 /* Avoid compiler warnings. */
6239c175
UH
205 device_index = device_index;
206
5a2326a7 207 if (capability == SR_HWCAP_PROBECONFIG) {
d81d2933
BV
208 /* Nothing to do, but must be supported */
209 ret = SR_OK;
210 } else if (capability == SR_HWCAP_SAMPLERATE) {
68c12597 211 cur_samplerate = *(uint64_t *)value;
6f422264
UH
212 sr_dbg("demo: %s: setting samplerate to %" PRIu64, __func__,
213 cur_samplerate);
e46b8fb1 214 ret = SR_OK;
5a2326a7 215 } else if (capability == SR_HWCAP_LIMIT_SAMPLES) {
68c12597 216 limit_samples = *(uint64_t *)value;
6f422264
UH
217 sr_dbg("demo: %s: setting limit_samples to %" PRIu64, __func__,
218 limit_samples);
e46b8fb1 219 ret = SR_OK;
5a2326a7 220 } else if (capability == SR_HWCAP_LIMIT_MSEC) {
68c12597 221 limit_msec = *(uint64_t *)value;
6f422264
UH
222 sr_dbg("demo: %s: setting limit_msec to %" PRIu64, __func__,
223 limit_msec);
e46b8fb1 224 ret = SR_OK;
5a2326a7 225 } else if (capability == SR_HWCAP_PATTERN_MODE) {
e15f48c2
BV
226 stropt = value;
227 if (!strcmp(stropt, "random")) {
228 default_genmode = GENMODE_RANDOM;
e46b8fb1 229 ret = SR_OK;
e15f48c2
BV
230 } else if (!strcmp(stropt, "incremental")) {
231 default_genmode = GENMODE_INC;
e46b8fb1 232 ret = SR_OK;
e15f48c2 233 } else {
e46b8fb1 234 ret = SR_ERR;
e15f48c2 235 }
6f422264
UH
236 sr_dbg("demo: %s: setting patternmode to %d", __func__,
237 default_genmode);
6239c175 238 } else {
e46b8fb1 239 ret = SR_ERR;
6239c175
UH
240 }
241
242 return ret;
243}
244
5096c6a6 245static void samples_generator(uint8_t *buf, uint64_t size, void *data)
85b5af06 246{
cddd1c5f 247 static uint64_t p = 0;
85b5af06 248 struct databag *mydata = data;
cddd1c5f 249 uint64_t i;
85b5af06 250
5096c6a6 251 memset(buf, 0, size);
85b5af06
UH
252
253 switch (mydata->sample_generator) {
0d31276b 254 case GENMODE_SIGROK:
917e0e71 255 for (i = 0; i < size; i++) {
0d31276b 256 *(buf + i) = ~(genmode_sigrok[p] >> 1);
917e0e71
BV
257 if (++p == 64)
258 p = 0;
259 }
260 break;
85b5af06 261 case GENMODE_RANDOM: /* Random */
5096c6a6
UH
262 for (i = 0; i < size; i++)
263 *(buf + i) = (uint8_t)(rand() & 0xff);
85b5af06
UH
264 break;
265 case GENMODE_INC: /* Simple increment */
5096c6a6 266 for (i = 0; i < size; i++)
85b5af06
UH
267 *(buf + i) = i;
268 break;
269 }
270}
271
272/* Thread function */
273static void thread_func(void *data)
274{
275 struct databag *mydata = data;
276 uint8_t buf[BUFSIZE];
277 uint64_t nb_to_send = 0;
d35aaf02 278 int bytes_written;
1924f59f
HE
279
280 double time_cur, time_last, time_diff;
281
282 time_last = g_timer_elapsed(mydata->timer, NULL);
85b5af06
UH
283
284 while (thread_running) {
1924f59f
HE
285 /* Rate control */
286 time_cur = g_timer_elapsed(mydata->timer, NULL);
287
288 time_diff = time_cur - time_last;
289 time_last = time_cur;
290
291 nb_to_send = cur_samplerate * time_diff;
292
ba3d481b 293 if (limit_samples)
1924f59f
HE
294 nb_to_send = MIN(nb_to_send,
295 limit_samples - mydata->samples_counter);
296
297 /* Make sure we don't overflow. */
298 nb_to_send = MIN(nb_to_send, BUFSIZE);
299
300 if (nb_to_send) {
301 samples_generator(buf, nb_to_send, data);
302 mydata->samples_counter += nb_to_send;
070befcd
BV
303
304 g_io_channel_write_chars(channels[1], (gchar *)&buf,
305 nb_to_send, (gsize *)&bytes_written, NULL);
b9cc3629
BV
306 }
307
1924f59f
HE
308 /* Check if we're done. */
309 if ((limit_msec && time_cur * 1000 > limit_msec) ||
310 (limit_samples && mydata->samples_counter >= limit_samples))
311 {
85b5af06
UH
312 close(mydata->pipe_fds[1]);
313 thread_running = 0;
85b5af06
UH
314 }
315
1924f59f 316 g_usleep(10);
85b5af06
UH
317 }
318}
319
320/* Callback handling data */
321static int receive_data(int fd, int revents, void *user_data)
322{
b9c735a2 323 struct sr_datafeed_packet packet;
26ce0bbf 324 char c[BUFSIZE];
108a5bfb 325 gsize z;
1924f59f 326
26ce0bbf
UH
327 /* Avoid compiler warnings. */
328 fd = fd;
329 revents = revents;
1924f59f
HE
330
331 do {
332 g_io_channel_read_chars(channels[0],
070befcd 333 (gchar *)&c, BUFSIZE, &z, NULL);
1924f59f
HE
334
335 if (z > 0) {
5a2326a7 336 packet.type = SR_DF_LOGIC;
1924f59f
HE
337 packet.length = z;
338 packet.unitsize = 1;
339 packet.payload = c;
8a2efef2 340 sr_session_bus(user_data, &packet);
1924f59f
HE
341 }
342 } while (z > 0);
85b5af06 343
1924f59f
HE
344 if (!thread_running && z <= 0)
345 {
346 /* Make sure we don't receive more packets */
347 g_io_channel_close(channels[0]);
d35aaf02 348
1924f59f 349 /* Send last packet. */
5a2326a7 350 packet.type = SR_DF_END;
8a2efef2 351 sr_session_bus(user_data, &packet);
1924f59f
HE
352
353 return FALSE;
85b5af06 354 }
1924f59f 355
85b5af06
UH
356 return TRUE;
357}
358
6239c175
UH
359static int hw_start_acquisition(int device_index, gpointer session_device_id)
360{
b9c735a2
UH
361 struct sr_datafeed_packet *packet;
362 struct sr_datafeed_header *header;
85b5af06 363 struct databag *mydata;
6239c175 364
27a3a6fe
UH
365 /* TODO: 'mydata' is never g_free()'d? */
366 if (!(mydata = g_try_malloc(sizeof(struct databag)))) {
367 sr_err("demo: %s: mydata malloc failed", __func__);
e46b8fb1 368 return SR_ERR_MALLOC;
27a3a6fe 369 }
85b5af06 370
e15f48c2 371 mydata->sample_generator = default_genmode;
85b5af06
UH
372 mydata->session_device_id = session_device_id;
373 mydata->device_index = device_index;
374 mydata->samples_counter = 0;
85b5af06 375
e15f48c2 376 if (pipe(mydata->pipe_fds))
e46b8fb1 377 return SR_ERR;
85b5af06 378
d35aaf02
UH
379 channels[0] = g_io_channel_unix_new(mydata->pipe_fds[0]);
380 channels[1] = g_io_channel_unix_new(mydata->pipe_fds[1]);
381
382 /* Set channel encoding to binary (default is UTF-8). */
383 g_io_channel_set_encoding(channels[0], NULL, NULL);
384 g_io_channel_set_encoding(channels[1], NULL, NULL);
385
386 /* Make channels to unbuffered. */
387 g_io_channel_set_buffered(channels[0], FALSE);
388 g_io_channel_set_buffered(channels[1], FALSE);
389
6f1be0a2
UH
390 sr_source_add(mydata->pipe_fds[0], G_IO_IN | G_IO_ERR, 40,
391 receive_data, session_device_id);
85b5af06
UH
392
393 /* Run the demo thread. */
394 g_thread_init(NULL);
cddd1c5f 395 /* this needs to be done between g_thread_init() and g_thread_create() */
1924f59f 396 mydata->timer = g_timer_new();
85b5af06
UH
397 thread_running = 1;
398 my_thread =
399 g_thread_create((GThreadFunc)thread_func, mydata, TRUE, NULL);
e15f48c2 400 if (!my_thread)
e46b8fb1 401 return SR_ERR;
6239c175 402
27a3a6fe
UH
403 if (!(packet = g_try_malloc(sizeof(struct sr_datafeed_packet)))) {
404 sr_err("demo: %s: packet malloc failed", __func__);
e46b8fb1 405 return SR_ERR_MALLOC;
27a3a6fe
UH
406 }
407
408 if (!(header = g_try_malloc(sizeof(struct sr_datafeed_header)))) {
409 sr_err("demo: %s: header malloc failed", __func__);
410 return SR_ERR_MALLOC;
411 }
6239c175 412
5a2326a7 413 packet->type = SR_DF_HEADER;
b9c735a2 414 packet->length = sizeof(struct sr_datafeed_header);
6239c175
UH
415 packet->payload = (unsigned char *)header;
416 header->feed_version = 1;
417 gettimeofday(&header->starttime, NULL);
418 header->samplerate = cur_samplerate;
5a2326a7 419 header->protocol_id = SR_PROTO_RAW;
c2616fb9
DR
420 header->num_logic_probes = NUM_PROBES;
421 header->num_analog_probes = 0;
8a2efef2 422 sr_session_bus(session_device_id, packet);
27a3a6fe
UH
423 g_free(header);
424 g_free(packet);
6239c175 425
e46b8fb1 426 return SR_OK;
6239c175
UH
427}
428
6239c175
UH
429static void hw_stop_acquisition(int device_index, gpointer session_device_id)
430{
17e1afcb 431 /* Avoid compiler warnings. */
6239c175 432 device_index = device_index;
1924f59f 433 session_device_id = session_device_id;
6239c175 434
1924f59f
HE
435 /* Stop generate thread. */
436 thread_running = 0;
6239c175
UH
437}
438
5c2d46d1 439struct sr_device_plugin demo_plugin_info = {
e519ba86
UH
440 .name = "demo",
441 .longname = "Demo driver and pattern generator",
442 .api_version = 1,
443 .init = hw_init,
444 .cleanup = hw_cleanup,
86f5e3d8
UH
445 .opendev = hw_opendev,
446 .closedev = hw_closedev,
e519ba86
UH
447 .get_device_info = hw_get_device_info,
448 .get_status = hw_get_status,
449 .get_capabilities = hw_get_capabilities,
450 .set_configuration = hw_set_configuration,
451 .start_acquisition = hw_start_acquisition,
452 .stop_acquisition = hw_stop_acquisition,
6239c175 453};