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