]> sigrok.org Git - libsigrok.git/blob - src/hardware/chromium-twinkie/protocol.c
chromium-twinkie: add analog VBUS channels
[libsigrok.git] / src / hardware / chromium-twinkie / protocol.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright 2017 Google, Inc
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 2 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 <stdint.h>
22 #include <string.h>
23 #include <libusb.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <math.h>
27 #include <libsigrok/libsigrok.h>
28 #include "libsigrok-internal.h"
29 #include "protocol.h"
30
31 /* 'twinkie vbus' command output format */
32 #define VBUS_FORMAT "VBUS = %d mV ; %d mA"
33
34 SR_PRIV int twinkie_start_acquisition(const struct sr_dev_inst *sdi)
35 {
36         struct dev_context *devc = sdi->priv;
37         struct timespec tsample;
38
39         clock_gettime(CLOCK_REALTIME, &tsample);
40         devc->vbus_t0 = tsample.tv_nsec + (uint64_t)tsample.tv_sec *1000000000ULL;
41
42         return SR_OK;
43 }
44
45 SR_PRIV int twinkie_init_device(const struct sr_dev_inst *sdi)
46 {
47         (void)sdi;
48
49         return SR_OK;
50 }
51
52 static void finish_acquisition(struct sr_dev_inst *sdi)
53 {
54         struct sr_datafeed_packet packet;
55         struct dev_context *devc = sdi->priv;
56
57         /* Terminate session. */
58         packet.type = SR_DF_END;
59         sr_session_send(sdi, &packet);
60
61         /* Remove fds from polling. */
62         usb_source_remove(sdi->session, devc->ctx);
63
64         devc->num_transfers = 0;
65         g_free(devc->transfers);
66         g_free(devc->convbuffer);
67 }
68
69 static void free_transfer(struct libusb_transfer *transfer)
70 {
71         struct sr_dev_inst *sdi;
72         struct dev_context *devc;
73         unsigned int i;
74
75         sdi = transfer->user_data;
76         devc = sdi->priv;
77
78         g_free(transfer->buffer);
79         transfer->buffer = NULL;
80         libusb_free_transfer(transfer);
81
82         for (i = 0; i < devc->num_transfers; i++) {
83                 if (devc->transfers[i] == transfer) {
84                         devc->transfers[i] = NULL;
85                         break;
86                 }
87         }
88
89         devc->submitted_transfers--;
90         if (devc->submitted_transfers == 0)
91                 finish_acquisition(sdi);
92 }
93
94 static void export_samples(const struct sr_dev_inst *sdi, size_t cnt)
95 {
96         struct sr_datafeed_packet packet;
97         struct sr_datafeed_logic logic;
98         struct dev_context *devc = sdi->priv;
99
100         /* export the received data */
101         packet.type = SR_DF_LOGIC;
102         packet.payload = &logic;
103         if (devc->limit_samples &&
104             cnt > devc->limit_samples - devc->sent_samples)
105                 cnt = devc->limit_samples - devc->sent_samples;
106         logic.length = cnt;
107         logic.unitsize = 1;
108         logic.data = devc->convbuffer;
109         sr_session_send(sdi, &packet);
110         devc->sent_samples += cnt;
111 }
112
113 static void expand_sample_data(const struct sr_dev_inst *sdi,
114                                const uint8_t *src, size_t srccnt)
115 {
116         struct dev_context *devc = sdi->priv;
117         int i, f;
118         size_t b;
119         size_t rdy_samples, left_samples;
120         int frames = srccnt / 64;
121
122         for (f = 0; f < frames; f++) {
123                 int ch = (src[1] >> 4) & 3; /* samples channel number */
124                 int bit = 1 << ch; /* channel bit mask */
125                 struct cc_context *cc = devc->cc + ch;
126                 uint8_t *dest = devc->convbuffer + cc->idx;
127
128                 if (ch >= 2) /* only acquires CCx channels */
129                         continue;
130
131                 /* TODO: check timestamp, overflow, sequence number */
132
133                 /* skip header, go to edges data */
134                 src+=4;
135                 for (i = 0; i < 60; i++,src++)
136                         if (*src == cc->prev_src) {
137                                 cc->rollbacks++;
138                         } else {
139                                 uint8_t diff = *src - cc->prev_src;
140                                 int fixup = cc->rollbacks && (((int)*src < (int)cc->prev_src) || (*src == 0xff));
141                                 size_t total = (fixup ? cc->rollbacks - 1 : cc->rollbacks) * 256 + diff;
142
143                                 if (total + cc->idx > devc->convbuffer_size) {
144                                         sr_warn("overflow %d+%zd/%zd\n",
145                                                 cc->idx, total,
146                                                 devc->convbuffer_size);
147                                         /* reset current decoding */
148                                         cc->rollbacks = 0;
149                                         break;
150                                 }
151
152                                 /* insert bits in the buffer */
153                                 if (cc->level)
154                                         for (b = 0 ; b < total ; b++, dest++)
155                                                 *dest |= bit;
156                                 else
157                                         dest += total;
158                                 cc->idx += total;
159
160                                 /* flip level on the next edge */
161                                 cc->level = ~cc->level;
162
163                                 cc->rollbacks = 0;
164                                 cc->prev_src = *src;
165                         }
166                 /* expand repeated rollbacks */
167                 if (cc->rollbacks > 1) {
168                         size_t total = 256 * (cc->rollbacks - 1);
169                         if (total + cc->idx > devc->convbuffer_size) {
170                                 sr_warn("overflow %d+%zd/%zd\n",
171                                         cc->idx, total, devc->convbuffer_size);
172                                 /* reset current decoding */
173                                 total = 0;
174                         }
175                         /* insert bits in the buffer */
176                         if (cc->level)
177                                 for (b = 0 ; b < total ; b++, dest++)
178                                         *dest |= bit ;
179                         cc->idx += total;
180                         cc->rollbacks = 1;
181                 }
182         }
183
184         /* samples ready to be pushed (with both channels) */
185         rdy_samples = MIN(devc->cc[0].idx, devc->cc[1].idx);
186         left_samples = MAX(devc->cc[0].idx, devc->cc[1].idx) - rdy_samples;
187         /* skip empty transfer */
188         if (rdy_samples == 0)
189                 return;
190
191         export_samples(sdi, rdy_samples);
192
193         /* clean up what we have sent */
194         memmove(devc->convbuffer, devc->convbuffer + rdy_samples, left_samples);
195         memset(devc->convbuffer + left_samples, 0, rdy_samples);
196         devc->cc[0].idx -= rdy_samples;
197         devc->cc[1].idx -= rdy_samples;
198 }
199
200 SR_PRIV void LIBUSB_CALL twinkie_receive_transfer(struct libusb_transfer *transfer)
201 {
202         gboolean packet_has_error = FALSE;
203         struct sr_dev_inst *sdi;
204         struct dev_context *devc;
205
206         sdi = transfer->user_data;
207         devc = sdi->priv;
208
209         /*
210          * If acquisition has already ended, just free any queued up
211          * transfer that come in.
212          */
213         if (devc->sent_samples < 0) {
214                 free_transfer(transfer);
215                 return;
216         }
217
218         if (transfer->status || transfer->actual_length)
219                 sr_info("receive_transfer(): status %d received %d bytes.",
220                         transfer->status, transfer->actual_length);
221
222         switch (transfer->status) {
223         case LIBUSB_TRANSFER_NO_DEVICE:
224                 devc->sent_samples = -2;
225                 free_transfer(transfer);
226                 return;
227         case LIBUSB_TRANSFER_COMPLETED:
228         case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */
229                 break;
230         default:
231                 packet_has_error = TRUE;
232                 break;
233         }
234
235         if (transfer->actual_length % 64) {
236                 sr_err("Bad USB packet size.");
237                 packet_has_error = TRUE;
238         }
239
240         if (transfer->actual_length == 0 || packet_has_error)
241                 goto resubmit;
242
243         /* decode received edges */
244         expand_sample_data(sdi, transfer->buffer, transfer->actual_length);
245
246         if (devc->limit_samples &&
247                         (uint64_t)devc->sent_samples >= devc->limit_samples) {
248                 devc->sent_samples = -2;
249                 free_transfer(transfer);
250                 return;
251         }
252 resubmit:
253         if (libusb_submit_transfer(transfer) != LIBUSB_SUCCESS)
254                 free_transfer(transfer);
255 }
256
257 static void export_vbus(const struct sr_dev_inst *sdi, int mv, int ma)
258 {
259         static float tmp_data[VBUS_GRP_COUNT][32768];
260         struct dev_context *devc = sdi->priv;
261         struct sr_datafeed_packet packet[VBUS_GRP_COUNT];
262         uint64_t tlen = devc->vbus_delta * 24 / 10000;
263         uint64_t len = MIN(32768, tlen);
264         unsigned i;
265         int g;
266
267         for (g = 0; g < devc->vbus_channels; g++) {
268                 float val = g == VBUS_V ? mv/1000.0 : ma/1000.0;
269                 packet[g].type = SR_DF_ANALOG;
270                 packet[g].payload = &devc->vbus_packet[g];
271                 devc->vbus_packet[g].data = tmp_data[g];
272                 for (i = 0; i < len; i++)
273                         tmp_data[g][i] = val;
274         }
275
276         do {
277                 for (g = 0; g < devc->vbus_channels; g++) {
278                         devc->vbus_packet[g].num_samples = len;
279                         sr_session_send(sdi, &packet[g]);
280                 }
281                 tlen -= len;
282                 len = MIN(32768, tlen);
283         } while (tlen);
284 }
285
286 SR_PRIV void LIBUSB_CALL twinkie_vbus_sent(struct libusb_transfer *transfer)
287 {
288         struct sr_dev_inst *sdi = transfer->user_data;
289         struct dev_context *devc = sdi->priv;
290         struct libusb_transfer *in_xfer = devc->transfers[11];
291         struct timespec tsample;
292         uint64_t now;
293
294         /* acquisition has already ended */
295         if (devc->sent_samples < 0 || transfer->status == LIBUSB_TRANSFER_NO_DEVICE)
296                 goto abort_vbus;
297
298         if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
299                 goto abort_vbus;
300
301         clock_gettime(CLOCK_REALTIME, &tsample);
302         now = tsample.tv_nsec + (uint64_t)tsample.tv_sec *1000000000ULL;
303         devc->vbus_delta = now - devc->vbus_t0;
304         devc->vbus_t0 = now;
305         if (libusb_submit_transfer(in_xfer) != LIBUSB_SUCCESS)
306                 goto abort_vbus;
307
308         return;
309 abort_vbus:
310         libusb_free_transfer(transfer);
311         libusb_free_transfer(in_xfer);
312         devc->transfers[10] = NULL;
313         devc->transfers[11] = NULL;
314         devc->submitted_transfers--;
315         if (devc->submitted_transfers == 0)
316                 finish_acquisition(sdi);
317 }
318
319 SR_PRIV void LIBUSB_CALL twinkie_vbus_recv(struct libusb_transfer *transfer)
320 {
321         struct sr_dev_inst *sdi = transfer->user_data;
322         struct dev_context *devc = sdi->priv;
323         struct libusb_transfer *out_xfer = devc->transfers[10];
324
325         /* acquisition has already ended */
326         if (devc->sent_samples < 0 || transfer->status == LIBUSB_TRANSFER_NO_DEVICE)
327                 goto abort_vbus;
328
329         if (transfer->status == LIBUSB_TRANSFER_COMPLETED &&
330                 transfer->actual_length) {
331                 int vbus_ma, vbus_mv;
332                 int len = transfer->actual_length;
333                 if (len > 63)
334                         len = 63;
335                 devc->vbus_data[len] = 0;
336                 if (sscanf(devc->vbus_data, VBUS_FORMAT, &vbus_mv, &vbus_ma) == 2) {
337                         export_vbus(sdi, vbus_mv, vbus_ma);
338                 }
339         }
340
341         if (libusb_submit_transfer(out_xfer) != LIBUSB_SUCCESS)
342                 goto abort_vbus;
343
344         return;
345 abort_vbus:
346         libusb_free_transfer(transfer);
347         libusb_free_transfer(out_xfer);
348         devc->transfers[10] = NULL;
349         devc->transfers[11] = NULL;
350         devc->submitted_transfers--;
351         if (devc->submitted_transfers == 0)
352                 finish_acquisition(sdi);
353 }