]> sigrok.org Git - libsigrok.git/blob - session.c
549666375ad5923e5889de906740f10ce7880daa
[libsigrok.git] / session.c
1 /*
2  * This file is part of the sigrok project.
3  *
4  * Copyright (C) 2010 Bert Vermeulen <bert@biot.com>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "config.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <glib.h>
26 #include <sigrok.h>
27 #include <sigrok-internal.h>
28
29 /* demo.c */
30 extern GIOChannel channels[2];
31
32 struct source {
33         int fd;
34         int events;
35         int timeout;
36         sr_receive_data_callback cb;
37         void *user_data;
38 };
39
40 /* There can only be one session at a time. */
41 struct sr_session *session;
42 int num_sources = 0;
43
44 struct source *sources = NULL;
45 int source_timeout = -1;
46
47
48 struct sr_session *sr_session_new(void)
49 {
50         session = calloc(1, sizeof(struct sr_session));
51
52         return session;
53 }
54
55 void sr_session_destroy(void)
56 {
57
58         g_slist_free(session->devices);
59
60         /* TODO: Loop over protocol decoders and free them. */
61
62         g_free(session);
63 }
64
65 void sr_session_device_clear(void)
66 {
67         g_slist_free(session->devices);
68         session->devices = NULL;
69 }
70
71 int sr_session_device_add(struct sr_device *device)
72 {
73         int ret;
74
75         if (device->plugin && device->plugin->opendev) {
76                 ret = device->plugin->opendev(device->plugin_index);
77                 if (ret != SR_OK)
78                         return ret;
79         }
80
81         session->devices = g_slist_append(session->devices, device);
82
83         return SR_OK;
84 }
85
86 #if 0
87 void sr_session_pa_clear(void)
88 {
89         /*
90          * The protocols are pointers to the global set of PA plugins,
91          * so don't free them.
92          */
93         g_slist_free(session->analyzers);
94         session->analyzers = NULL;
95 }
96
97 void sr_session_pa_add(struct sr_analyzer *an)
98 {
99         session->analyzers = g_slist_append(session->analyzers, an);
100 }
101 #endif
102
103 void sr_session_datafeed_callback_clear(void)
104 {
105         g_slist_free(session->datafeed_callbacks);
106         session->datafeed_callbacks = NULL;
107 }
108
109 void sr_session_datafeed_callback_add(sr_datafeed_callback callback)
110 {
111         session->datafeed_callbacks =
112             g_slist_append(session->datafeed_callbacks, callback);
113 }
114
115 static void sr_session_run_poll()
116 {
117         GPollFD *fds, my_gpollfd;
118         int ret, i;
119
120         fds = NULL;
121         while (session->running) {
122                 if (fds)
123                         free(fds);
124
125                 /* Construct g_poll()'s array. */
126                 fds = malloc(sizeof(GPollFD) * num_sources);
127                 for (i = 0; i < num_sources; i++) {
128 #ifdef _WIN32
129                         g_io_channel_win32_make_pollfd(&channels[0],
130                                         sources[i].events, &my_gpollfd);
131 #else
132                         my_gpollfd.fd = sources[i].fd;
133                         my_gpollfd.events = sources[i].events;
134                         fds[i] = my_gpollfd;
135 #endif
136                 }
137
138                 ret = g_poll(fds, num_sources, source_timeout);
139
140                 for (i = 0; i < num_sources; i++) {
141                         if (fds[i].revents > 0 || (ret == 0
142                                 && source_timeout == sources[i].timeout)) {
143                                 /*
144                                  * Invoke the source's callback on an event,
145                                  * or if the poll timeout out and this source
146                                  * asked for that timeout.
147                                  */
148                                 if (!sources[i].cb(fds[i].fd, fds[i].revents,
149                                                   sources[i].user_data))
150                                         sr_session_source_remove(sources[i].fd);
151                         }
152                 }
153         }
154         free(fds);
155
156 }
157
158 int sr_session_start(void)
159 {
160         struct sr_device *device;
161         GSList *l;
162         int ret;
163
164         sr_info("session: starting");
165         for (l = session->devices; l; l = l->next) {
166                 device = l->data;
167                 if ((ret = device->plugin->start_acquisition(
168                                 device->plugin_index, device)) != SR_OK)
169                         break;
170         }
171
172         return ret;
173 }
174
175 void sr_session_run(void)
176 {
177
178         sr_info("session: running");
179         session->running = TRUE;
180
181         /* do we have real sources? */
182         if (num_sources == 1 && sources[0].fd == -1)
183                 /* dummy source, freewheel over it */
184                 while (session->running)
185                         sources[0].cb(-1, 0, sources[0].user_data);
186         else
187                 /* real sources, use g_poll() main loop */
188                 sr_session_run_poll();
189
190 }
191
192 void sr_session_halt(void)
193 {
194
195         sr_info("session: halting");
196         session->running = FALSE;
197
198 }
199
200 void sr_session_stop(void)
201 {
202         struct sr_device *device;
203         GSList *l;
204
205         sr_info("session: stopping");
206         session->running = FALSE;
207         for (l = session->devices; l; l = l->next) {
208                 device = l->data;
209                 if (device->plugin && device->plugin->stop_acquisition)
210                         device->plugin->stop_acquisition(device->plugin_index, device);
211         }
212
213 }
214
215 static void datafeed_dump(struct sr_datafeed_packet *packet)
216 {
217         struct sr_datafeed_logic *logic;
218
219         switch (packet->type) {
220         case SR_DF_HEADER:
221                 sr_dbg("bus: received SR_DF_HEADER");
222                 break;
223         case SR_DF_TRIGGER:
224                 sr_dbg("bus: received SR_DF_TRIGGER at %lu ms",
225                                 packet->timeoffset / 1000000);
226                 break;
227         case SR_DF_LOGIC:
228                 logic = packet->payload;
229                 sr_dbg("bus: received SR_DF_LOGIC at %f ms duration %f ms, %"PRIu64" bytes",
230                                 packet->timeoffset / 1000000.0, packet->duration / 1000000.0,
231                                 logic->length);
232                 break;
233         case SR_DF_END:
234                 sr_dbg("bus: received SR_DF_END");
235                 break;
236         default:
237                 sr_dbg("bus: received unknown packet type %d", packet->type);
238         }
239
240 }
241
242 void sr_session_bus(struct sr_device *device, struct sr_datafeed_packet *packet)
243 {
244         GSList *l;
245         sr_datafeed_callback cb;
246
247         /*
248          * TODO: Send packet through PD pipe, and send the output of that to
249          * the callbacks as well.
250          */
251         for (l = session->datafeed_callbacks; l; l = l->next) {
252                 cb = l->data;
253                 datafeed_dump(packet);
254                 cb(device, packet);
255         }
256 }
257
258 void sr_session_source_add(int fd, int events, int timeout,
259                 sr_receive_data_callback callback, void *user_data)
260 {
261         struct source *new_sources, *s;
262
263         new_sources = calloc(1, sizeof(struct source) * (num_sources + 1));
264
265         if (sources) {
266                 memcpy(new_sources, sources,
267                        sizeof(struct source) * num_sources);
268                 free(sources);
269         }
270
271         s = &new_sources[num_sources++];
272         s->fd = fd;
273         s->events = events;
274         s->timeout = timeout;
275         s->cb = callback;
276         s->user_data = user_data;
277         sources = new_sources;
278
279         if (timeout != source_timeout && timeout > 0
280             && (source_timeout == -1 || timeout < source_timeout))
281                 source_timeout = timeout;
282 }
283
284 void sr_session_source_remove(int fd)
285 {
286         struct source *new_sources;
287         int old, new;
288
289         if (!sources)
290                 return;
291
292         new_sources = calloc(1, sizeof(struct source) * num_sources);
293         for (old = 0, new = 0; old < num_sources; old++)
294                 if (sources[old].fd != fd)
295                         memcpy(&new_sources[new++], &sources[old],
296                                sizeof(struct source));
297
298         if (old != new) {
299                 free(sources);
300                 sources = new_sources;
301                 num_sources--;
302         } else {
303                 /* Target fd was not found. */
304                 free(new_sources);
305         }
306 }
307