]> sigrok.org Git - libsigrok.git/blob - session.c
better cleanup of device/plugin resources
[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                                 sources[i].cb(fds[i].fd, fds[i].revents,
149                                                   sources[i].user_data);
150                         }
151                 }
152         }
153         free(fds);
154
155 }
156
157 int sr_session_start(void)
158 {
159         struct sr_device *device;
160         GSList *l;
161         int ret;
162
163         sr_info("session: starting");
164         for (l = session->devices; l; l = l->next) {
165                 device = l->data;
166                 if ((ret = device->plugin->start_acquisition(
167                                 device->plugin_index, device)) != SR_OK)
168                         break;
169         }
170
171         return ret;
172 }
173
174 void sr_session_run(void)
175 {
176
177         sr_info("session: running");
178         session->running = TRUE;
179
180         /* do we have real sources? */
181         if (num_sources == 1 && sources[0].fd == -1)
182                 /* dummy source, freewheel over it */
183                 while (session->running)
184                         sources[0].cb(-1, 0, sources[0].user_data);
185         else
186                 /* real sources, use g_poll() main loop */
187                 sr_session_run_poll();
188
189 }
190
191 void sr_session_halt(void)
192 {
193
194         sr_info("session: halting");
195         session->running = FALSE;
196
197 }
198
199 void sr_session_stop(void)
200 {
201         struct sr_device *device;
202         GSList *l;
203
204         sr_info("session: stopping");
205         session->running = FALSE;
206         for (l = session->devices; l; l = l->next) {
207                 device = l->data;
208                 if (device->plugin && device->plugin->stop_acquisition)
209                         device->plugin->stop_acquisition(device->plugin_index, device);
210         }
211
212 }
213
214 void sr_session_bus(struct sr_device *device, struct sr_datafeed_packet *packet)
215 {
216         GSList *l;
217         sr_datafeed_callback cb;
218
219         /*
220          * TODO: Send packet through PD pipe, and send the output of that to
221          * the callbacks as well.
222          */
223         for (l = session->datafeed_callbacks; l; l = l->next) {
224                 cb = l->data;
225                 cb(device, packet);
226         }
227 }
228
229 void sr_session_source_add(int fd, int events, int timeout,
230                 sr_receive_data_callback callback, void *user_data)
231 {
232         struct source *new_sources, *s;
233
234         new_sources = calloc(1, sizeof(struct source) * (num_sources + 1));
235
236         if (sources) {
237                 memcpy(new_sources, sources,
238                        sizeof(struct source) * num_sources);
239                 free(sources);
240         }
241
242         s = &new_sources[num_sources++];
243         s->fd = fd;
244         s->events = events;
245         s->timeout = timeout;
246         s->cb = callback;
247         s->user_data = user_data;
248         sources = new_sources;
249
250         if (timeout != source_timeout && timeout > 0
251             && (source_timeout == -1 || timeout < source_timeout))
252                 source_timeout = timeout;
253 }
254
255 void sr_session_source_remove(int fd)
256 {
257         struct source *new_sources;
258         int old, new;
259
260         if (!sources)
261                 return;
262
263         new_sources = calloc(1, sizeof(struct source) * num_sources);
264         for (old = 0; old < num_sources; old++)
265                 if (sources[old].fd != fd)
266                         memcpy(&new_sources[new++], &sources[old],
267                                sizeof(struct source));
268
269         if (old != new) {
270                 free(sources);
271                 sources = new_sources;
272                 num_sources--;
273         } else {
274                 /* Target fd was not found. */
275                 free(new_sources);
276         }
277 }
278