]>
Commit | Line | Data |
---|---|---|
a8e913c4 JL |
1 | /* |
2 | * This file is part of the libsigrok project. | |
3 | * | |
4 | * Copyright (C) 2017 Jan Luebbe <jluebbe@lasnet.de> | |
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 <config.h> | |
ca7d19b5 | 21 | #include <string.h> |
a8e913c4 JL |
22 | #include "protocol.h" |
23 | ||
ca7d19b5 JL |
24 | #define COMMAND_START_CAPTURE 0x01 |
25 | #define COMMAND_STOP_CAPTURE 0x02 | |
26 | #define COMMAND_READ_EEPROM 0x07 | |
27 | #define COMMAND_WRITE_REG 0x80 | |
28 | #define COMMAND_READ_REG 0x81 | |
29 | #define COMMAND_WRITE_I2C 0x87 | |
30 | #define COMMAND_READ_I2C 0x88 | |
31 | #define COMMAND_WAKE_I2C 0x89 | |
32 | #define COMMAND_READ_FW_VER 0x8b | |
33 | ||
34 | #define REG_LED_RED 0x0f | |
35 | #define REG_LED_GREEN 0x10 | |
36 | #define REG_LED_BLUE 0x11 | |
37 | ||
38 | static void iterate_lfsr(const struct sr_dev_inst *sdi) | |
39 | { | |
40 | struct dev_context *devc = sdi->priv; | |
41 | uint32_t lfsr = devc->lfsr; | |
42 | int i, max; | |
43 | ||
44 | max = (lfsr & 0x1f) + 34; | |
45 | for (i = 0; i <= max; i++) { | |
46 | lfsr = (lfsr >> 1) | \ | |
47 | ((lfsr ^ \ | |
48 | (lfsr >> 1) ^ \ | |
49 | (lfsr >> 21) ^ \ | |
50 | (lfsr >> 31) \ | |
51 | ) << 31); | |
52 | } | |
53 | sr_dbg("Iterate 0x%08x -> 0x%08x", devc->lfsr, lfsr); | |
54 | devc->lfsr = lfsr; | |
55 | } | |
56 | ||
57 | static void encrypt(const struct sr_dev_inst *sdi, const uint8_t *in, uint8_t *out, uint8_t len) | |
58 | { | |
59 | struct dev_context *devc = sdi->priv; | |
60 | uint32_t lfsr = devc->lfsr; | |
61 | uint8_t value, mask; | |
62 | int i; | |
63 | ||
64 | for (i = 0; i < len; i++) { | |
65 | value = in[i]; | |
bb0c5271 | 66 | mask = lfsr >> (i % 4 * 8); |
ca7d19b5 JL |
67 | if (i == 0) |
68 | value = (value & 0x28) | ((value ^ mask) & ~0x28); | |
69 | else | |
70 | value = value ^ mask; | |
71 | out[i] = value; | |
72 | } | |
73 | iterate_lfsr(sdi); | |
74 | } | |
75 | ||
76 | static void decrypt(const struct sr_dev_inst *sdi, uint8_t *data, uint8_t len) | |
77 | { | |
78 | struct dev_context *devc = sdi->priv; | |
79 | uint32_t lfsr = devc->lfsr; | |
80 | int i; | |
81 | ||
bb0c5271 UH |
82 | for (i = 0; i < len; i++) |
83 | data[i] ^= (lfsr >> (i % 4 * 8)); | |
ca7d19b5 JL |
84 | iterate_lfsr(sdi); |
85 | } | |
86 | ||
87 | static int transact(const struct sr_dev_inst *sdi, | |
88 | const uint8_t *req, uint8_t req_len, | |
89 | uint8_t *rsp, uint8_t rsp_len) | |
90 | { | |
91 | struct sr_usb_dev_inst *usb = sdi->conn; | |
92 | uint8_t *req_enc; | |
93 | uint8_t rsp_dummy[1] = {}; | |
94 | int ret, xfer; | |
95 | ||
96 | if (req_len < 2 || req_len > 64 || rsp_len > 128 || | |
97 | !req || (rsp_len > 0 && !rsp)) | |
98 | return SR_ERR_ARG; | |
99 | ||
100 | req_enc = g_malloc(req_len); | |
101 | encrypt(sdi, req, req_enc, req_len); | |
102 | ||
103 | ret = libusb_bulk_transfer(usb->devhdl, 1, req_enc, req_len, &xfer, 1000); | |
104 | if (ret != 0) { | |
105 | sr_dbg("Failed to send request 0x%02x: %s.", | |
106 | req[1], libusb_error_name(ret)); | |
107 | return SR_ERR; | |
108 | } | |
109 | if (xfer != req_len) { | |
110 | sr_dbg("Failed to send request 0x%02x: incorrect length " | |
111 | "%d != %d.", req[1], xfer, req_len); | |
112 | return SR_ERR; | |
113 | } | |
114 | ||
bb0c5271 | 115 | if (req[0] == 0x20) { /* Reseed. */ |
ca7d19b5 JL |
116 | return SR_OK; |
117 | } else if (rsp_len == 0) { | |
118 | rsp = rsp_dummy; | |
119 | rsp_len = sizeof(rsp_dummy); | |
120 | } | |
121 | ||
122 | ret = libusb_bulk_transfer(usb->devhdl, 0x80 | 1, rsp, rsp_len, | |
123 | &xfer, 1000); | |
124 | if (ret != 0) { | |
125 | sr_dbg("Failed to receive response to request 0x%02x: %s.", | |
126 | req[1], libusb_error_name(ret)); | |
127 | return SR_ERR; | |
128 | } | |
129 | if (xfer != rsp_len) { | |
130 | sr_dbg("Failed to receive response to request 0x%02x: " | |
131 | "incorrect length %d != %d.", req[1], xfer, rsp_len); | |
132 | return SR_ERR; | |
133 | } | |
134 | ||
135 | decrypt(sdi, rsp, rsp_len); | |
136 | ||
137 | return SR_OK; | |
138 | } | |
139 | ||
140 | static int reseed(const struct sr_dev_inst *sdi) | |
141 | { | |
142 | struct dev_context *devc = sdi->priv; | |
143 | uint8_t req[] = {0x20, 0x24, 0x4b, 0x35, 0x8e}; | |
144 | ||
145 | devc->lfsr = 0; | |
146 | return transact(sdi, req, sizeof(req), NULL, 0); | |
147 | } | |
148 | ||
149 | static int write_regs(const struct sr_dev_inst *sdi, uint8_t (*regs)[2], uint8_t cnt) | |
150 | { | |
151 | uint8_t req[64]; | |
152 | int i; | |
153 | ||
154 | if (cnt < 1 || cnt > 30) | |
155 | return SR_ERR_ARG; | |
156 | ||
157 | req[0] = 0x00; | |
158 | req[1] = COMMAND_WRITE_REG; | |
159 | req[2] = cnt; | |
160 | ||
161 | for (i = 0; i < cnt; i++) { | |
162 | req[3 + 2 * i] = regs[i][0]; | |
163 | req[4 + 2 * i] = regs[i][1]; | |
164 | } | |
165 | ||
bb0c5271 | 166 | return transact(sdi, req, 3 + (2 * cnt), NULL, 0); |
ca7d19b5 JL |
167 | } |
168 | ||
169 | static int write_reg(const struct sr_dev_inst *sdi, | |
170 | uint8_t address, uint8_t value) | |
171 | { | |
172 | uint8_t regs[2] = {address, value}; | |
173 | ||
174 | return write_regs(sdi, ®s, 1); | |
175 | } | |
176 | ||
177 | static int get_firmware_version(const struct sr_dev_inst *sdi) | |
a8e913c4 | 178 | { |
ca7d19b5 JL |
179 | uint8_t req[2] = {0x00, COMMAND_READ_FW_VER}; |
180 | uint8_t rsp[128] = {}; | |
181 | int ret; | |
182 | ||
183 | ret = transact(sdi, req, sizeof(req), rsp, sizeof(rsp)); | |
184 | if (ret == SR_OK) { | |
185 | rsp[63] = 0; | |
186 | sr_dbg("fw-version: %s", rsp); | |
187 | } | |
188 | ||
189 | return ret; | |
190 | } | |
a8e913c4 | 191 | |
ca7d19b5 JL |
192 | static int read_i2c(const struct sr_dev_inst *sdi, uint8_t *data, uint8_t len) |
193 | { | |
194 | uint8_t req[5]; | |
bb0c5271 | 195 | uint8_t rsp[1 + 128]; |
ca7d19b5 | 196 | int ret; |
a8e913c4 | 197 | |
ca7d19b5 JL |
198 | if (len < 1 || len > 128 || !data) |
199 | return SR_ERR_ARG; | |
a8e913c4 | 200 | |
ca7d19b5 JL |
201 | req[0] = 0x00; |
202 | req[1] = COMMAND_READ_I2C; | |
bb0c5271 | 203 | req[2] = 0xc0; /* Fixed address */ |
ca7d19b5 | 204 | req[3] = len; |
bb0c5271 | 205 | req[4] = 0; /* Len MSB? */ |
a8e913c4 | 206 | |
ca7d19b5 | 207 | ret = transact(sdi, req, sizeof(req), rsp, 1 + len); |
bb0c5271 | 208 | if (ret != SR_OK) |
ca7d19b5 | 209 | return ret; |
ca7d19b5 JL |
210 | if (rsp[0] != 0x02) { |
211 | sr_dbg("Failed to do I2C read (0x%02x).", rsp[0]); | |
212 | return SR_ERR; | |
a8e913c4 JL |
213 | } |
214 | ||
bb0c5271 | 215 | memcpy(data, rsp + 1, len); |
ca7d19b5 JL |
216 | return SR_OK; |
217 | } | |
218 | ||
219 | static int write_i2c(const struct sr_dev_inst *sdi, const uint8_t *data, uint8_t len) | |
220 | { | |
221 | uint8_t req[5 + 128]; | |
222 | uint8_t rsp[1]; | |
223 | int ret; | |
224 | ||
225 | if (len < 1 || len > 128 || !data) | |
226 | return SR_ERR_ARG; | |
227 | ||
228 | req[0] = 0x00; | |
229 | req[1] = COMMAND_WRITE_I2C; | |
bb0c5271 | 230 | req[2] = 0xc0; /* Fixed address */ |
ca7d19b5 | 231 | req[3] = len; |
bb0c5271 | 232 | req[4] = 0; /* Len MSB? */ |
ca7d19b5 JL |
233 | memcpy(req + 5, data, len); |
234 | ||
235 | ret = transact(sdi, req, 5 + len, rsp, sizeof(rsp)); | |
bb0c5271 | 236 | if (ret != SR_OK) |
ca7d19b5 | 237 | return ret; |
ca7d19b5 JL |
238 | if (rsp[0] != 0x02) { |
239 | sr_dbg("Failed to do I2C write (0x%02x).", rsp[0]); | |
240 | return SR_ERR; | |
241 | } | |
242 | ||
243 | return SR_OK; | |
244 | } | |
245 | ||
246 | static int wake_i2c(const struct sr_dev_inst *sdi) | |
247 | { | |
248 | uint8_t req[] = {0x00, COMMAND_WAKE_I2C}; | |
249 | uint8_t rsp[1] = {}; | |
bb0c5271 | 250 | uint8_t i2c_rsp[1 + 1 + 2] = {}; |
ca7d19b5 JL |
251 | int ret; |
252 | ||
253 | ret = transact(sdi, req, sizeof(req), rsp, sizeof(rsp)); | |
bb0c5271 | 254 | if (ret != SR_OK) |
ca7d19b5 | 255 | return ret; |
ca7d19b5 JL |
256 | if (rsp[0] != 0x00) { |
257 | sr_dbg("Failed to do I2C wake trigger (0x%02x).", rsp[0]); | |
258 | return SR_ERR; | |
259 | } | |
260 | ||
261 | ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); | |
262 | if (ret != SR_OK) { | |
263 | return ret; | |
264 | } | |
265 | if (i2c_rsp[1] != 0x11) { | |
266 | sr_dbg("Failed to do I2C wake read (0x%02x).", i2c_rsp[0]); | |
267 | return SR_ERR; | |
268 | } | |
269 | ||
270 | return SR_OK; | |
271 | } | |
272 | ||
273 | static int crypto_random(const struct sr_dev_inst *sdi, uint8_t *data) | |
274 | { | |
275 | uint8_t i2c_req[8] = {0x03, 0x07, 0x1b, 0x00, 0x00, 0x00, 0x24, 0xcd}; | |
bb0c5271 | 276 | uint8_t i2c_rsp[1 + 32 + 2] = {}; |
ca7d19b5 JL |
277 | int ret; |
278 | ||
279 | ret = write_i2c(sdi, i2c_req, sizeof(i2c_req)); | |
bb0c5271 | 280 | if (ret != SR_OK) |
ca7d19b5 | 281 | return ret; |
ca7d19b5 | 282 | |
bb0c5271 | 283 | g_usleep(100000); /* TODO: Poll instead. */ |
ca7d19b5 JL |
284 | |
285 | ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); | |
bb0c5271 | 286 | if (ret != SR_OK) |
ca7d19b5 | 287 | return ret; |
ca7d19b5 | 288 | |
bb0c5271 UH |
289 | if (data) |
290 | memcpy(data, i2c_rsp + 1, 32); | |
ca7d19b5 JL |
291 | |
292 | return SR_OK; | |
293 | } | |
294 | ||
295 | static int crypto_nonce(const struct sr_dev_inst *sdi, uint8_t *data) | |
296 | { | |
bb0c5271 UH |
297 | uint8_t i2c_req[6 + 20 + 2] = {0x03, 0x1b, 0x16, 0x00, 0x00, 0x00}; |
298 | uint8_t i2c_rsp[1 + 32 + 2] = {}; | |
ca7d19b5 JL |
299 | int ret; |
300 | ||
bb0c5271 | 301 | /* CRC */ |
ca7d19b5 JL |
302 | i2c_req[26] = 0x7d; |
303 | i2c_req[27] = 0xe0; | |
304 | ||
305 | ret = write_i2c(sdi, i2c_req, sizeof(i2c_req)); | |
bb0c5271 | 306 | if (ret != SR_OK) |
ca7d19b5 | 307 | return ret; |
ca7d19b5 | 308 | |
bb0c5271 | 309 | g_usleep(100000); /* TODO: Poll instead. */ |
ca7d19b5 JL |
310 | |
311 | ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); | |
bb0c5271 | 312 | if (ret != SR_OK) |
ca7d19b5 | 313 | return ret; |
ca7d19b5 | 314 | |
bb0c5271 UH |
315 | if (data) |
316 | memcpy(data, i2c_rsp + 1, 32); | |
ca7d19b5 JL |
317 | |
318 | return SR_OK; | |
319 | } | |
320 | ||
321 | static int crypto_sign(const struct sr_dev_inst *sdi, uint8_t *data, uint8_t *crc) | |
322 | { | |
323 | uint8_t i2c_req[8] = {0x03, 0x07, 0x41, 0x80, 0x00, 0x00, 0x28, 0x05}; | |
bb0c5271 | 324 | uint8_t i2c_rsp[1 + 64 + 2] = {}; |
ca7d19b5 JL |
325 | int ret; |
326 | ||
327 | ret = write_i2c(sdi, i2c_req, sizeof(i2c_req)); | |
bb0c5271 | 328 | if (ret != SR_OK) |
ca7d19b5 | 329 | return ret; |
ca7d19b5 | 330 | |
bb0c5271 | 331 | g_usleep(100000); /* TODO: Poll instead. */ |
ca7d19b5 JL |
332 | |
333 | ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); | |
bb0c5271 | 334 | if (ret != SR_OK) |
ca7d19b5 | 335 | return ret; |
ca7d19b5 | 336 | |
bb0c5271 UH |
337 | memcpy(data, i2c_rsp + 1, 64); |
338 | memcpy(crc, i2c_rsp + 1 + 64, 2); | |
ca7d19b5 JL |
339 | |
340 | return SR_OK; | |
341 | } | |
342 | ||
343 | static int authenticate(const struct sr_dev_inst *sdi) | |
344 | { | |
345 | struct dev_context *devc = sdi->priv; | |
346 | uint8_t random[32] = {}; | |
347 | uint8_t nonce[32] = {}; | |
348 | uint8_t sig[64] = {}; | |
349 | uint8_t sig_crc[64] = {}; | |
350 | uint32_t lfsr; | |
351 | int i, ret; | |
352 | ||
353 | ret = wake_i2c(sdi); | |
354 | if (ret != SR_OK) | |
355 | return ret; | |
356 | ||
357 | ret = crypto_random(sdi, random); | |
358 | if (ret != SR_OK) | |
359 | return ret; | |
360 | sr_dbg("random: 0x%02x 0x%02x 0x%02x 0x%02x", random[0], random[1], random[2], random[3]); | |
361 | ||
362 | ret = crypto_nonce(sdi, nonce); | |
363 | if (ret != SR_OK) | |
364 | return ret; | |
365 | sr_dbg("nonce: 0x%02x 0x%02x 0x%02x 0x%02x", nonce[0], nonce[1], nonce[2], nonce[3]); | |
366 | ||
367 | ret = crypto_nonce(sdi, nonce); | |
368 | if (ret != SR_OK) | |
369 | return ret; | |
370 | sr_dbg("nonce: 0x%02x 0x%02x 0x%02x 0x%02x", nonce[0], nonce[1], nonce[2], nonce[3]); | |
371 | ||
372 | ret = crypto_sign(sdi, sig, sig_crc); | |
373 | if (ret != SR_OK) | |
374 | return ret; | |
375 | sr_dbg("sig: 0x%02x 0x%02x 0x%02x 0x%02x", sig[0], sig[1], sig[2], sig[3]); | |
376 | sr_dbg("sig crc: 0x%02x 0x%02x", sig_crc[0], sig_crc[1]); | |
377 | ||
378 | lfsr = 0; | |
379 | for (i = 0; i < 28; i++) | |
bb0c5271 | 380 | lfsr ^= nonce[i] << (8 * (i % 4)); |
ca7d19b5 JL |
381 | lfsr ^= sig_crc[0] | sig_crc[1] << 8; |
382 | ||
383 | sr_dbg("Authenticate 0x%08x -> 0x%08x", devc->lfsr, lfsr); | |
384 | devc->lfsr = lfsr; | |
385 | ||
386 | return SR_OK; | |
387 | } | |
388 | ||
389 | static int set_led(const struct sr_dev_inst *sdi, uint8_t r, uint8_t g, uint8_t b) | |
390 | { | |
391 | uint8_t regs[][2] = { | |
392 | {REG_LED_RED, r}, | |
393 | {REG_LED_GREEN, g}, | |
394 | {REG_LED_BLUE, b}, | |
395 | }; | |
396 | ||
397 | authenticate(sdi); | |
398 | ||
399 | return write_regs(sdi, regs, G_N_ELEMENTS(regs)); | |
400 | } | |
401 | ||
402 | static int configure_channels(const struct sr_dev_inst *sdi) | |
403 | { | |
404 | struct dev_context *devc = sdi->priv; | |
405 | const struct sr_channel *c; | |
406 | const GSList *l; | |
407 | uint16_t mask; | |
408 | ||
409 | devc->dig_channel_cnt = 0; | |
410 | devc->dig_channel_mask = 0; | |
411 | for (l = sdi->channels; l; l = l->next) { | |
412 | c = l->data; | |
413 | if (!c->enabled) | |
414 | continue; | |
415 | ||
416 | mask = 1 << c->index; | |
417 | devc->dig_channel_masks[devc->dig_channel_cnt++] = mask; | |
418 | devc->dig_channel_mask |= mask; | |
419 | ||
420 | } | |
421 | sr_dbg("%d channels enabled (0x%04x)", | |
bb0c5271 | 422 | devc->dig_channel_cnt, devc->dig_channel_mask); |
ca7d19b5 JL |
423 | |
424 | return SR_OK; | |
425 | } | |
426 | ||
b6189f7c | 427 | SR_PRIV int saleae_logic_pro_init(const struct sr_dev_inst *sdi) |
ca7d19b5 JL |
428 | { |
429 | reseed(sdi); | |
430 | get_firmware_version(sdi); | |
bb0c5271 | 431 | /* Setting the LED doesn't work yet. */ |
ca7d19b5 JL |
432 | /* set_led(sdi, 0x00, 0x00, 0xff); */ |
433 | ||
434 | return SR_OK; | |
435 | } | |
436 | ||
b6189f7c | 437 | SR_PRIV int saleae_logic_pro_prepare(const struct sr_dev_inst *sdi) |
ca7d19b5 JL |
438 | { |
439 | struct dev_context *devc = sdi->priv; | |
440 | uint8_t regs_unknown[][2] = { | |
441 | {0x03, 0x0f}, | |
442 | {0x04, 0x00}, | |
443 | {0x05, 0x00}, | |
444 | }; | |
445 | uint8_t regs_config[][2] = { | |
446 | {0x00, 0x00}, | |
bb0c5271 UH |
447 | {0x08, 0x00}, /* Analog channel mask (LSB) */ |
448 | {0x09, 0x00}, /* Analog channel mask (MSB) */ | |
449 | {0x06, 0x01}, /* Digital channel mask (LSB) */ | |
450 | {0x07, 0x00}, /* Digital channel mask (MSB) */ | |
451 | {0x0a, 0x00}, /* Analog sample rate? */ | |
452 | {0x0b, 0x64}, /* Digital sample rate? */ | |
ca7d19b5 | 453 | {0x0c, 0x00}, |
bb0c5271 UH |
454 | {0x0d, 0x00}, /* Analog mux rate? */ |
455 | {0x0e, 0x01}, /* Digital mux rate? */ | |
ca7d19b5 JL |
456 | {0x12, 0x04}, |
457 | {0x13, 0x00}, | |
bb0c5271 | 458 | {0x14, 0xff}, /* Pre-divider? */ |
ca7d19b5 JL |
459 | }; |
460 | uint8_t start_req[] = {0x00, 0x01}; | |
461 | uint8_t start_rsp[2] = {}; | |
462 | ||
463 | configure_channels(sdi); | |
464 | ||
bb0c5271 | 465 | /* Digital channel mask and muxing */ |
ca7d19b5 JL |
466 | regs_config[3][1] = devc->dig_channel_mask; |
467 | regs_config[4][1] = devc->dig_channel_mask >> 8; | |
468 | regs_config[9][1] = devc->dig_channel_cnt; | |
469 | ||
bb0c5271 | 470 | /* Samplerate */ |
ca7d19b5 JL |
471 | switch (devc->dig_samplerate) { |
472 | case SR_MHZ(1): | |
473 | regs_config[6][1] = 0x64; | |
474 | break; | |
475 | case SR_MHZ(2): | |
476 | regs_config[6][1] = 0x32; | |
477 | break; | |
478 | case SR_KHZ(2500): | |
479 | regs_config[6][1] = 0x28; | |
480 | break; | |
481 | case SR_MHZ(10): | |
482 | regs_config[6][1] = 0x0a; | |
483 | break; | |
484 | case SR_MHZ(25): | |
485 | regs_config[6][1] = 0x04; | |
486 | regs_config[12][1] = 0x80; | |
487 | break; | |
488 | case SR_MHZ(50): | |
489 | regs_config[6][1] = 0x02; | |
490 | regs_config[12][1] = 0x40; | |
491 | break; | |
492 | default: | |
493 | return SR_ERR_ARG; | |
494 | } | |
495 | ||
496 | authenticate(sdi); | |
497 | ||
498 | write_reg(sdi, 0x15, 0x03); | |
499 | write_regs(sdi, regs_unknown, G_N_ELEMENTS(regs_unknown)); | |
500 | write_regs(sdi, regs_config, G_N_ELEMENTS(regs_config)); | |
501 | ||
502 | transact(sdi, start_req, sizeof(start_req), start_rsp, sizeof(start_rsp)); | |
503 | ||
504 | return SR_OK; | |
505 | } | |
506 | ||
b6189f7c | 507 | SR_PRIV int saleae_logic_pro_start(const struct sr_dev_inst *sdi) |
ca7d19b5 JL |
508 | { |
509 | struct dev_context *devc = sdi->priv; | |
510 | ||
511 | devc->conv_size = 0; | |
512 | devc->batch_index = 0; | |
513 | ||
514 | write_reg(sdi, 0x00, 0x01); | |
515 | ||
516 | return SR_OK; | |
517 | } | |
518 | ||
b6189f7c | 519 | SR_PRIV int saleae_logic_pro_stop(const struct sr_dev_inst *sdi) |
ca7d19b5 JL |
520 | { |
521 | uint8_t stop_req[] = {0x00, 0x02}; | |
522 | uint8_t stop_rsp[2] = {}; | |
523 | ||
524 | write_reg(sdi, 0x00, 0x00); | |
525 | transact(sdi, stop_req, sizeof(stop_req), stop_rsp, sizeof(stop_rsp)); | |
526 | ||
527 | return SR_OK; | |
528 | } | |
529 | ||
b6189f7c | 530 | static void saleae_logic_pro_send_data(const struct sr_dev_inst *sdi, |
ca7d19b5 JL |
531 | void *data, size_t length, size_t unitsize) |
532 | { | |
533 | const struct sr_datafeed_logic logic = { | |
534 | .length = length, | |
535 | .unitsize = unitsize, | |
536 | .data = data | |
537 | }; | |
538 | ||
539 | const struct sr_datafeed_packet packet = { | |
540 | .type = SR_DF_LOGIC, | |
541 | .payload = &logic | |
542 | }; | |
543 | ||
544 | sr_session_send(sdi, &packet); | |
545 | } | |
546 | ||
547 | /* | |
548 | * One batch from the device consists of 32 samples per active digital channel. | |
549 | * This stream of batches is packed into USB packets with 16384 bytes each. | |
550 | */ | |
b6189f7c | 551 | static void saleae_logic_pro_convert_data(const struct sr_dev_inst *sdi, |
ca7d19b5 JL |
552 | const uint32_t *src, size_t srccnt) |
553 | { | |
554 | struct dev_context *devc = sdi->priv; | |
555 | uint8_t *dst = devc->conv_buffer; | |
556 | uint32_t samples; | |
557 | uint16_t channel_mask; | |
558 | unsigned int sample_index, batch_index; | |
559 | uint16_t *dst_batch; | |
560 | ||
bb0c5271 UH |
561 | /* Copy partial batch to the beginning. */ |
562 | memcpy(dst, dst + devc->conv_size, CONV_BATCH_SIZE); | |
563 | /* Reset converted size. */ | |
ca7d19b5 JL |
564 | devc->conv_size = 0; |
565 | ||
566 | batch_index = devc->batch_index; | |
567 | while (srccnt--) { | |
568 | samples = *src++; | |
569 | dst_batch = (uint16_t*)dst; | |
570 | ||
bb0c5271 | 571 | /* First index of the batch. */ |
ca7d19b5 JL |
572 | if (batch_index == 0) |
573 | memset(dst, 0, CONV_BATCH_SIZE); | |
574 | ||
bb0c5271 | 575 | /* Convert one channel. */ |
ca7d19b5 JL |
576 | channel_mask = devc->dig_channel_masks[batch_index]; |
577 | for (sample_index = 0; sample_index <= 31; sample_index++) | |
bb0c5271 | 578 | if ((samples >> (31 - sample_index)) & 1) |
ca7d19b5 JL |
579 | dst_batch[sample_index] |= channel_mask; |
580 | ||
bb0c5271 | 581 | /* Last index of the batch. */ |
ca7d19b5 JL |
582 | if (++batch_index == devc->dig_channel_cnt) { |
583 | devc->conv_size += CONV_BATCH_SIZE; | |
584 | batch_index = 0; | |
585 | dst += CONV_BATCH_SIZE; | |
586 | } | |
587 | } | |
588 | devc->batch_index = batch_index; | |
589 | } | |
590 | ||
b6189f7c | 591 | SR_PRIV void LIBUSB_CALL saleae_logic_pro_receive_data(struct libusb_transfer *transfer) |
ca7d19b5 JL |
592 | { |
593 | const struct sr_dev_inst *sdi = transfer->user_data; | |
594 | struct dev_context *devc = sdi->priv; | |
595 | int ret; | |
596 | ||
597 | switch (transfer->status) { | |
598 | case LIBUSB_TRANSFER_NO_DEVICE: | |
599 | sr_dbg("FIXME no device"); | |
600 | return; | |
601 | case LIBUSB_TRANSFER_COMPLETED: | |
602 | case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */ | |
603 | break; | |
604 | default: | |
bb0c5271 | 605 | /* FIXME */ |
ca7d19b5 JL |
606 | return; |
607 | } | |
608 | ||
bb0c5271 | 609 | saleae_logic_pro_convert_data(sdi, (uint32_t*)transfer->buffer, 16 * 1024 / 4); |
b6189f7c | 610 | saleae_logic_pro_send_data(sdi, devc->conv_buffer, devc->conv_size, 2); |
ca7d19b5 JL |
611 | |
612 | if ((ret = libusb_submit_transfer(transfer)) != LIBUSB_SUCCESS) | |
613 | sr_dbg("FIXME resubmit failed"); | |
a8e913c4 | 614 | } |