]> sigrok.org Git - libsigrok.git/blob - session.c
MinGW: Build fix.
[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 <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <zip.h>
25 #include <glib.h>
26 #include <sigrok.h>
27 #include <config.h>
28
29 /* demo.c */
30 extern GIOChannel channels[2];
31
32 /* There can only be one session at a time. */
33 struct session *session;
34 int num_sources = 0;
35 /* These live in hwplugin.c, for the frontend to override. */
36 extern source_callback_add source_cb_add;
37 extern source_callback_remove source_cb_remove;
38
39 struct source {
40         int fd;
41         int events;
42         int timeout;
43         receive_data_callback cb;
44         void *user_data;
45 };
46
47 struct source *sources = NULL;
48 int source_timeout = -1;
49
50
51
52
53 struct session *session_load(const char *filename)
54 {
55         struct session *session;
56
57         /* Avoid compiler warnings. */
58         filename = filename;
59
60         /* TODO: Implement. */
61         session = NULL;
62
63         return session;
64 }
65
66 struct session *session_new(void)
67 {
68         session = calloc(1, sizeof(struct session));
69
70         return session;
71 }
72
73 void session_destroy(void)
74 {
75         g_slist_free(session->devices);
76
77         /* TODO: Loop over protocol decoders and free them. */
78
79         g_free(session);
80 }
81
82 void session_device_clear(void)
83 {
84         g_slist_free(session->devices);
85         session->devices = NULL;
86 }
87
88 int session_device_add(struct sr_device *device)
89 {
90         int ret;
91
92         if (device->plugin && device->plugin->open) {
93                 ret = device->plugin->open(device->plugin_index);
94                 if (ret != SR_OK)
95                         return ret;
96         }
97
98         session->devices = g_slist_append(session->devices, device);
99
100         return SR_OK;
101 }
102
103 void session_pa_clear(void)
104 {
105         /*
106          * The protocols are pointers to the global set of PA plugins,
107          * so don't free them.
108          */
109         g_slist_free(session->analyzers);
110         session->analyzers = NULL;
111 }
112
113 void session_pa_add(struct analyzer *an)
114 {
115         session->analyzers = g_slist_append(session->analyzers, an);
116 }
117
118 void session_datafeed_callback_clear(void)
119 {
120         g_slist_free(session->datafeed_callbacks);
121         session->datafeed_callbacks = NULL;
122 }
123
124 void session_datafeed_callback_add(datafeed_callback callback)
125 {
126         session->datafeed_callbacks =
127             g_slist_append(session->datafeed_callbacks, callback);
128 }
129
130 int session_start(void)
131 {
132         struct sr_device *device;
133         GSList *l;
134         int ret;
135
136         g_message("starting session");
137         for (l = session->devices; l; l = l->next) {
138                 device = l->data;
139                 if ((ret = device->plugin->start_acquisition(
140                                 device->plugin_index, device)) != SR_OK)
141                         break;
142         }
143
144         return ret;
145 }
146
147 void session_run(void)
148 {
149         GPollFD *fds, my_gpollfd;
150         int ret, i;
151
152         g_message("running session");
153         session->running = TRUE;
154         fds = NULL;
155         while (session->running) {
156                 if (fds)
157                         free(fds);
158
159                 /* Construct g_poll()'s array. */
160                 fds = malloc(sizeof(GPollFD) * num_sources);
161                 for (i = 0; i < num_sources; i++) {
162 #ifdef _WIN32
163                         g_io_channel_win32_make_pollfd(&channels[0],
164                                         sources[i].events, &my_gpollfd);
165 #else
166                         my_gpollfd.fd = sources[i].fd;
167                         my_gpollfd.events = sources[i].events;
168                         fds[i] = my_gpollfd;
169 #endif
170                 }
171
172                 ret = g_poll(fds, num_sources, source_timeout);
173
174                 for (i = 0; i < num_sources; i++) {
175                         if (fds[i].revents > 0 || (ret == 0
176                                 && source_timeout == sources[i].timeout)) {
177                                 /*
178                                  * Invoke the source's callback on an event,
179                                  * or if the poll timeout out and this source
180                                  * asked for that timeout.
181                                  */
182                                 sources[i].cb(fds[i].fd, fds[i].revents,
183                                               sources[i].user_data);
184                         }
185                 }
186         }
187         free(fds);
188
189 }
190
191 void session_halt(void)
192 {
193
194         g_message("halting session");
195         session->running = FALSE;
196
197 }
198
199 void session_stop(void)
200 {
201         struct sr_device *device;
202         GSList *l;
203
204         g_message("stopping session");
205         session->running = FALSE;
206         for (l = session->devices; l; l = l->next) {
207                 device = l->data;
208                 if (device->plugin)
209                         device->plugin->stop_acquisition(device->plugin_index, device);
210         }
211
212 }
213
214 void session_bus(struct sr_device *device, struct sr_datafeed_packet *packet)
215 {
216         GSList *l;
217         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 int session_save(char *filename)
230 {
231         GSList *l, *p, *d;
232         FILE *meta;
233         struct sr_device *device;
234         struct probe *probe;
235         struct datastore *ds;
236         struct zip *zipfile;
237         struct zip_source *versrc, *metasrc, *logicsrc;
238         int bufcnt, devcnt, tmpfile, ret, error;
239         char version[1], rawname[16], metafile[32], *newfn, *buf;
240
241         newfn = g_malloc(strlen(filename) + 10);
242         strcpy(newfn, filename);
243         if (strstr(filename, ".sigrok") != filename+strlen(filename)-7)
244                 strcat(newfn, ".sigrok");
245
246         /* Quietly delete it first, libzip wants replace ops otherwise. */
247         unlink(newfn);
248         if (!(zipfile = zip_open(newfn, ZIP_CREATE, &error)))
249                 return SR_ERR;
250         g_free(newfn);
251
252         /* "version" */
253         version[0] = '1';
254         if (!(versrc = zip_source_buffer(zipfile, version, 1, 0)))
255                 return SR_ERR;
256         if (zip_add(zipfile, "version", versrc) == -1) {
257                 g_message("error saving version into zipfile: %s",
258                           zip_strerror(zipfile));
259                 return SR_ERR;
260         }
261
262         /* init "metadata" */
263         strcpy(metafile, "sigrok-meta-XXXXXX");
264         if ((tmpfile = g_mkstemp(metafile)) == -1)
265                 return SR_ERR;
266         close(tmpfile);
267         meta = fopen(metafile, "wb");
268         fprintf(meta, "sigrok version = %s\n", PACKAGE_VERSION);
269         /* TODO: save protocol decoders used */
270
271         /* all datastores in all devices */
272         devcnt = 1;
273         for (l = session->devices; l; l = l->next) {
274                 device = l->data;
275                 /* metadata */
276                 fprintf(meta, "[device]\n");
277                 if (device->plugin)
278                         fprintf(meta, "driver = %s\n", device->plugin->name);
279
280                 ds = device->datastore;
281                 if (ds) {
282                         /* metadata */
283                         fprintf(meta, "capturefile = logic-%d\n", devcnt);
284                         for (p = device->probes; p; p = p->next) {
285                                 probe = p->data;
286                                 if (probe->enabled) {
287                                         fprintf(meta, "probe %d", probe->index);
288                                         if (probe->name)
289                                                 fprintf(meta, " name \"%s\"", probe->name);
290                                         if (probe->trigger)
291                                                 fprintf(meta, " trigger \"%s\"",
292                                                         probe->trigger);
293                                         fprintf(meta, "\n");
294                                 }
295                         }
296
297                         /* dump datastore into logic-n */
298                         buf = malloc(ds->num_units * ds->ds_unitsize +
299                                    DATASTORE_CHUNKSIZE);
300                         bufcnt = 0;
301                         for (d = ds->chunklist; d; d = d->next) {
302                                 memcpy(buf + bufcnt, d->data,
303                                        DATASTORE_CHUNKSIZE);
304                                 bufcnt += DATASTORE_CHUNKSIZE;
305                         }
306                         if (!(logicsrc = zip_source_buffer(zipfile, buf,
307                                        ds->num_units * ds->ds_unitsize, TRUE)))
308                                 return SR_ERR;
309                         snprintf(rawname, 15, "logic-%d", devcnt);
310                         if (zip_add(zipfile, rawname, logicsrc) == -1)
311                                 return SR_ERR;
312                 }
313                 devcnt++;
314         }
315         fclose(meta);
316
317         if (!(metasrc = zip_source_file(zipfile, metafile, 0, -1)))
318                 return SR_ERR;
319         if (zip_add(zipfile, "metadata", metasrc) == -1)
320                 return SR_ERR;
321
322         if ((ret = zip_close(zipfile)) == -1) {
323                 g_message("error saving zipfile: %s", zip_strerror(zipfile));
324                 return SR_ERR;
325         }
326
327         unlink(metafile);
328
329         return SR_OK;
330 }
331
332 void session_source_add(int fd, int events, int timeout,
333                 receive_data_callback callback, void *user_data)
334 {
335         struct source *new_sources, *s;
336
337         new_sources = calloc(1, sizeof(struct source) * (num_sources + 1));
338
339         if (sources) {
340                 memcpy(new_sources, sources,
341                        sizeof(struct source) * num_sources);
342                 free(sources);
343         }
344
345         s = &new_sources[num_sources++];
346         s->fd = fd;
347         s->events = events;
348         s->timeout = timeout;
349         s->cb = callback;
350         s->user_data = user_data;
351         sources = new_sources;
352
353         if (timeout != source_timeout && timeout > 0
354             && (source_timeout == -1 || timeout < source_timeout))
355                 source_timeout = timeout;
356 }
357
358 void session_source_remove(int fd)
359 {
360         struct source *new_sources;
361         int old, new;
362
363         if (!sources)
364                 return;
365
366         new_sources = calloc(1, sizeof(struct source) * num_sources);
367         for (old = 0; old < num_sources; old++)
368                 if (sources[old].fd != fd)
369                         memcpy(&new_sources[new++], &sources[old],
370                                sizeof(struct source));
371
372         if (old != new) {
373                 free(sources);
374                 sources = new_sources;
375                 num_sources--;
376         } else {
377                 /* Target fd was not found. */
378                 free(new_sources);
379         }
380 }
381