]> sigrok.org Git - libsigrok.git/blame - src/hardware/chromium-twinkie/protocol.c
CHROMIUM: Add driver for Chromium Twinkie dongle
[libsigrok.git] / src / hardware / chromium-twinkie / protocol.c
CommitLineData
744e43bc
VP
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright 2014 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
31SR_PRIV int twinkie_start_acquisition(const struct sr_dev_inst *sdi)
32{
33 (void)sdi;
34
35 return SR_OK;
36}
37
38SR_PRIV int twinkie_init_device(const struct sr_dev_inst *sdi)
39{
40 (void)sdi;
41
42 return SR_OK;
43}
44
45static void finish_acquisition(struct sr_dev_inst *sdi)
46{
47 struct sr_datafeed_packet packet;
48 struct dev_context *devc = sdi->priv;
49
50 /* Terminate session. */
51 packet.type = SR_DF_END;
52 sr_session_send(sdi, &packet);
53
54 /* Remove fds from polling. */
55 usb_source_remove(sdi->session, devc->ctx);
56
57 devc->num_transfers = 0;
58 g_free(devc->transfers);
59 g_free(devc->convbuffer);
60}
61
62static void free_transfer(struct libusb_transfer *transfer)
63{
64 struct sr_dev_inst *sdi;
65 struct dev_context *devc;
66 unsigned int i;
67
68 sdi = transfer->user_data;
69 devc = sdi->priv;
70
71 g_free(transfer->buffer);
72 transfer->buffer = NULL;
73 libusb_free_transfer(transfer);
74
75 for (i = 0; i < devc->num_transfers; i++) {
76 if (devc->transfers[i] == transfer) {
77 devc->transfers[i] = NULL;
78 break;
79 }
80 }
81
82 devc->submitted_transfers--;
83 if (devc->submitted_transfers == 0)
84 finish_acquisition(sdi);
85}
86
87static void export_samples(const struct sr_dev_inst *sdi, size_t cnt)
88{
89 struct sr_datafeed_packet packet;
90 struct sr_datafeed_logic logic;
91 struct dev_context *devc = sdi->priv;
92
93 /* export the received data */
94 packet.type = SR_DF_LOGIC;
95 packet.payload = &logic;
96 if (devc->limit_samples &&
97 cnt > devc->limit_samples - devc->sent_samples)
98 cnt = devc->limit_samples - devc->sent_samples;
99 logic.length = cnt;
100 logic.unitsize = 1;
101 logic.data = devc->convbuffer;
102 sr_session_send(sdi, &packet);
103 devc->sent_samples += cnt;
104}
105
106static void expand_sample_data(const struct sr_dev_inst *sdi,
107 const uint8_t *src, size_t srccnt)
108{
109 struct dev_context *devc = sdi->priv;
110 int i, f;
111 size_t b;
112 size_t rdy_samples, left_samples;
113 int frames = srccnt / 64;
114
115 for (f = 0; f < frames; f++) {
116 int ch = (src[1] >> 4) & 3; /* samples channel number */
117 int bit = 1 << ch; /* channel bit mask */
118 struct cc_context *cc = devc->cc + ch;
119 uint8_t *dest = devc->convbuffer + cc->idx;
120
121 if (ch >= 2) /* only acquires CCx channels */
122 continue;
123
124 /* TODO: check timestamp, overflow, sequence number */
125
126 /* skip header, go to edges data */
127 src+=4;
128 for (i = 0; i < 60; i++,src++)
129 if (*src == cc->prev_src) {
130 cc->rollbacks++;
131 } else {
132 uint8_t diff = *src - cc->prev_src;
133 int fixup = cc->rollbacks && (((int)*src < (int)cc->prev_src) || (*src == 0xff));
134 size_t total = (fixup ? cc->rollbacks - 1 : cc->rollbacks) * 256 + diff;
135
136 if (total + cc->idx > devc->convbuffer_size) {
137 sr_warn("overflow %d+%zd/%zd\n",
138 cc->idx, total,
139 devc->convbuffer_size);
140 /* reset current decoding */
141 cc->rollbacks = 0;
142 break;
143 }
144
145 /* insert bits in the buffer */
146 if (cc->level)
147 for (b = 0 ; b < total ; b++, dest++)
148 *dest |= bit;
149 else
150 dest += total;
151 cc->idx += total;
152
153 /* flip level on the next edge */
154 cc->level = ~cc->level;
155
156 cc->rollbacks = 0;
157 cc->prev_src = *src;
158 }
159 /* expand repeated rollbacks */
160 if (cc->rollbacks > 1) {
161 size_t total = 256 * (cc->rollbacks - 1);
162 if (total + cc->idx > devc->convbuffer_size) {
163 sr_warn("overflow %d+%zd/%zd\n",
164 cc->idx, total, devc->convbuffer_size);
165 /* reset current decoding */
166 total = 0;
167 }
168 /* insert bits in the buffer */
169 if (cc->level)
170 for (b = 0 ; b < total ; b++, dest++)
171 *dest |= bit ;
172 cc->idx += total;
173 cc->rollbacks = 1;
174 }
175 }
176
177 /* samples ready to be pushed (with both channels) */
178 rdy_samples = MIN(devc->cc[0].idx, devc->cc[1].idx);
179 left_samples = MAX(devc->cc[0].idx, devc->cc[1].idx) - rdy_samples;
180 /* skip empty transfer */
181 if (rdy_samples == 0)
182 return;
183
184 export_samples(sdi, rdy_samples);
185
186 /* clean up what we have sent */
187 memmove(devc->convbuffer, devc->convbuffer + rdy_samples, left_samples);
188 memset(devc->convbuffer + left_samples, 0, rdy_samples);
189 devc->cc[0].idx -= rdy_samples;
190 devc->cc[1].idx -= rdy_samples;
191}
192
193SR_PRIV void LIBUSB_CALL twinkie_receive_transfer(struct libusb_transfer *transfer)
194{
195 gboolean packet_has_error = FALSE;
196 struct sr_dev_inst *sdi;
197 struct dev_context *devc;
198
199 sdi = transfer->user_data;
200 devc = sdi->priv;
201
202 /*
203 * If acquisition has already ended, just free any queued up
204 * transfer that come in.
205 */
206 if (devc->sent_samples < 0) {
207 free_transfer(transfer);
208 return;
209 }
210
211 if (transfer->status || transfer->actual_length)
212 sr_info("receive_transfer(): status %d received %d bytes.",
213 transfer->status, transfer->actual_length);
214
215 switch (transfer->status) {
216 case LIBUSB_TRANSFER_NO_DEVICE:
217 devc->sent_samples = -2;
218 free_transfer(transfer);
219 return;
220 case LIBUSB_TRANSFER_COMPLETED:
221 case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */
222 break;
223 default:
224 packet_has_error = TRUE;
225 break;
226 }
227
228 if (transfer->actual_length % 64) {
229 sr_err("Bad USB packet size.");
230 packet_has_error = TRUE;
231 }
232
233 if (transfer->actual_length == 0 || packet_has_error)
234 goto resubmit;
235
236 /* decode received edges */
237 expand_sample_data(sdi, transfer->buffer, transfer->actual_length);
238
239 if (devc->limit_samples &&
240 (uint64_t)devc->sent_samples >= devc->limit_samples) {
241 devc->sent_samples = -2;
242 free_transfer(transfer);
243 return;
244 }
245resubmit:
246 if (libusb_submit_transfer(transfer) != LIBUSB_SUCCESS)
247 free_transfer(transfer);
248}