]> sigrok.org Git - libsigrok.git/blob - session_driver.c
implement session loading based on a virtual device driver
[libsigrok.git] / session_driver.c
1 /*
2  * This file is part of the sigrok project.
3  *
4  * Copyright (C) 2011 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 <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <sys/time.h>
25 #include <zip.h>
26 #include <sigrok.h>
27
28 /* size of payloads sent across the session bus */
29 #define CHUNKSIZE 4096
30
31 struct session_vdevice {
32         char *capturefile;
33         struct zip *archive;
34         struct zip_file *capfile;
35         uint64_t samplerate;
36         int unitsize;
37         int num_probes;
38 };
39
40 static char *sessionfile = NULL;
41 static GSList *device_instances = NULL;
42 static int capabilities[] = {
43         SR_HWCAP_CAPTUREFILE,
44         SR_HWCAP_CAPTURE_UNITSIZE,
45         0,
46 };
47
48
49 static struct session_vdevice *get_vdevice_by_index(int device_index)
50 {
51         struct sr_device_instance *sdi;
52         struct session_vdevice *vdevice;
53
54         if (!(sdi = sr_get_device_instance(device_instances, device_index)))
55                 return NULL;
56
57         vdevice = sdi->priv;
58
59         return vdevice;
60 }
61
62 static int feed_chunk(int fd, int revents, void *user_data)
63 {
64         struct sr_device_instance *sdi;
65         struct session_vdevice *vdevice;
66         struct sr_datafeed_packet packet;
67         GSList *l;
68         void *buf;
69         int ret, got_data;
70
71         /* avoid compiler warning */
72         fd = fd;
73         revents = revents;
74
75         g_debug("session_driver: feed chunk");
76
77         got_data = FALSE;
78         for (l = device_instances; l; l = l->next) {
79                 sdi = l->data;
80                 vdevice = sdi->priv;
81                 if (!vdevice)
82                         /* already done with this instance */
83                         continue;
84
85                 buf = g_malloc(CHUNKSIZE);
86                 ret = zip_fread(vdevice->capfile, buf, CHUNKSIZE);
87                 if (ret > 0) {
88                         got_data = TRUE;
89                         packet.type = SR_DF_LOGIC;
90                         packet.length = ret;
91                         packet.unitsize = vdevice->unitsize;
92                         packet.payload = buf;
93                         session_bus(user_data, &packet);
94                 } else {
95                         /* done with this capture file */
96                         zip_fclose(vdevice->capfile);
97                         g_free(vdevice->capturefile);
98                         g_free(vdevice);
99                         sdi->priv = NULL;
100                 }
101         }
102
103         if (!got_data) {
104                 packet.type = SR_DF_END;
105                 packet.length = 0;
106                 session_bus(user_data, &packet);
107         }
108
109         return TRUE;
110 }
111
112 /* driver callbacks */
113
114 static int hw_init(char *deviceinfo)
115 {
116
117         sessionfile = g_strdup(deviceinfo);
118
119         return 0;
120 }
121
122 static void hw_cleanup(void)
123 {
124         GSList *l;
125
126         for (l = device_instances; l; l = l->next)
127                 sr_device_instance_free(l->data);
128
129         g_free(sessionfile);
130
131 }
132
133 static int hw_opendev(int device_index)
134 {
135         struct sr_device_instance *sdi;
136
137         sdi = sr_device_instance_new(device_index, SR_ST_INITIALIZING,
138                 NULL, NULL, NULL);
139         if (!sdi)
140                 return SR_ERR;
141         sdi->priv = g_malloc0(sizeof(struct session_vdevice));
142         if (!sdi->priv)
143                 return SR_ERR;
144         device_instances = g_slist_append(device_instances, sdi);
145
146         return SR_OK;
147 }
148
149 static void hw_closedev(int device_index)
150 {
151
152         /* avoid compiler warning */
153         device_index = device_index;
154
155 }
156
157 static void *hw_get_device_info(int device_index, int device_info_id)
158 {
159         struct session_vdevice *vdevice;
160         void *info;
161
162         if (!(vdevice = get_vdevice_by_index(device_index)))
163                 return NULL;
164
165         info = &vdevice->samplerate;
166
167         return info;
168 }
169
170 static int hw_get_status(int device_index)
171 {
172
173         /* avoid compiler warning */
174         device_index = device_index;
175
176         if (devices)
177                 return SR_OK;
178         else
179                 return SR_ERR;
180 }
181
182 static int *hw_get_capabilities(void)
183 {
184
185         return capabilities;
186 }
187
188 static int hw_set_configuration(int device_index, int capability, void *value)
189 {
190         struct session_vdevice *vdevice;
191         uint64_t *tmp_u64;
192
193         if (!(vdevice = get_vdevice_by_index(device_index)))
194                 return SR_ERR;
195
196         switch (capability) {
197         case SR_HWCAP_SAMPLERATE:
198                 tmp_u64 = value;
199                 vdevice->samplerate = *tmp_u64;
200                 break;
201         case SR_HWCAP_CAPTUREFILE:
202                 vdevice->capturefile = g_strdup(value);
203                 break;
204         case SR_HWCAP_CAPTURE_UNITSIZE:
205                 tmp_u64 = value;
206                 vdevice->unitsize = *tmp_u64;
207                 break;
208         case SR_HWCAP_CAPTURE_NUM_PROBES:
209                 tmp_u64 = value;
210                 vdevice->num_probes = *tmp_u64;
211                 break;
212         default:
213                 return SR_ERR;
214         }
215
216         return SR_OK;
217 }
218
219 static int hw_start_acquisition(int device_index, gpointer session_device_id)
220 {
221         struct zip_stat zs;
222         struct session_vdevice *vdevice;
223         struct sr_datafeed_header *header;
224         struct sr_datafeed_packet *packet;
225         int err;
226
227         /* avoid compiler warning */
228         session_device_id = session_device_id;
229
230         if (!(vdevice = get_vdevice_by_index(device_index)))
231                 return SR_ERR;
232
233         g_message("session_driver: opening archive %s file %s",
234                         sessionfile, vdevice->capturefile);
235
236         if (!(vdevice->archive = zip_open(sessionfile, 0, &err))) {
237                 g_warning("Failed to open session file '%s': zip error %d\n",
238                                 sessionfile, err);
239                 return SR_ERR;
240         }
241
242         if (zip_stat(vdevice->archive, vdevice->capturefile, 0, &zs) == -1) {
243                 g_warning("Failed to check capture file '%s' in session file '%s'.",
244                                 vdevice->capturefile, sessionfile);
245                 return SR_ERR;
246         }
247
248         if (!(vdevice->capfile = zip_fopen(vdevice->archive, vdevice->capturefile, 0))) {
249                 g_warning("Failed to open capture file '%s' in session file '%s'.",
250                                 vdevice->capturefile, sessionfile);
251                 return SR_ERR;
252         }
253
254         /* freewheeling source */
255         session_source_add(-1, 0, 0, feed_chunk, session_device_id);
256
257         /* Send header packet to the session bus. */
258         packet = g_malloc(sizeof(struct sr_datafeed_packet));
259         header = g_malloc(sizeof(struct sr_datafeed_header));
260         if (!packet || !header)
261                 return SR_ERR;
262         packet->type = SR_DF_HEADER;
263         packet->length = sizeof(struct sr_datafeed_header);
264         packet->payload = (unsigned char *)header;
265         header->feed_version = 1;
266         gettimeofday(&header->starttime, NULL);
267         header->samplerate = 0;
268         header->protocol_id = SR_PROTO_RAW;
269         header->num_logic_probes = vdevice->num_probes;
270         header->num_analog_probes = 0;
271         session_bus(session_device_id, packet);
272         g_free(header);
273         g_free(packet);
274
275         return SR_OK;
276 }
277
278 static void hw_stop_acquisition(int device_index, gpointer session_device_id)
279 {
280         struct session_vdevice *vdevice;
281
282         /* avoid compiler warning */
283         session_device_id = session_device_id;
284
285 //      vdevice = get_vdevice_by_index(device_index);
286 //      zip_fclose(vdevice->capfile);
287 //      zip_close(vdevice->archive);
288
289 }
290
291
292 struct sr_device_plugin session_driver = {
293         "session",
294         "Session-emulating driver",
295         1,
296         hw_init,
297         hw_cleanup,
298         hw_opendev,
299         hw_closedev,
300         hw_get_device_info,
301         hw_get_status,
302         hw_get_capabilities,
303         hw_set_configuration,
304         hw_start_acquisition,
305         hw_stop_acquisition,
306 };