]>
Commit | Line | Data |
---|---|---|
c463dcf0 MC |
1 | /* |
2 | * This file is part of the libsigrok project. | |
3 | * | |
4 | * Copyright (C) 2013 Marcus Comstedt <marcus@mc.pp.se> | |
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 "protocol.h" | |
21 | ||
15abcf0f MC |
22 | #include <stdint.h> |
23 | #include <string.h> | |
24 | #include <glib.h> | |
25 | #include <glib/gstdio.h> | |
26 | #include <stdio.h> | |
27 | #include <errno.h> | |
28 | #include <math.h> | |
29 | #include "libsigrok.h" | |
30 | #include "libsigrok-internal.h" | |
31 | ||
32 | #define FPGA_FIRMWARE_18 FIRMWARE_DIR"/saleae-logic16-fpga-18.bitstream" | |
33 | #define FPGA_FIRMWARE_33 FIRMWARE_DIR"/saleae-logic16-fpga-33.bitstream" | |
34 | ||
35 | #define COMMAND_START_ACQUISITION 1 | |
36 | #define COMMAND_ABORT_ACQUISITION_ASYNC 2 | |
37 | #define COMMAND_WRITE_EEPROM 6 | |
38 | #define COMMAND_READ_EEPROM 7 | |
39 | #define COMMAND_WRITE_LED_TABLE 0x7a | |
40 | #define COMMAND_SET_LED_MODE 0x7b | |
41 | #define COMMAND_RETURN_TO_BOOTLOADER 0x7c | |
42 | #define COMMAND_ABORT_ACQUISITION_SYNC 0x7d | |
43 | #define COMMAND_FPGA_UPLOAD_INIT 0x7e | |
44 | #define COMMAND_FPGA_UPLOAD_SEND_DATA 0x7f | |
45 | #define COMMAND_FPGA_WRITE_REGISTER 0x80 | |
46 | #define COMMAND_FPGA_READ_REGISTER 0x81 | |
47 | #define COMMAND_GET_REVID 0x82 | |
48 | ||
49 | #define WRITE_EEPROM_COOKIE1 0x42 | |
50 | #define WRITE_EEPROM_COOKIE2 0x55 | |
51 | #define READ_EEPROM_COOKIE1 0x33 | |
52 | #define READ_EEPROM_COOKIE2 0x81 | |
53 | #define ABORT_ACQUISITION_SYNC_PATTERN 0x55 | |
54 | ||
55 | ||
56 | static void encrypt(uint8_t *dest, const uint8_t *src, uint8_t cnt) | |
57 | { | |
58 | uint8_t state1 = 0x9b, state2 = 0x54; | |
59 | int i; | |
60 | ||
61 | for (i=0; i<cnt; i++) { | |
62 | uint8_t t, v = src[i]; | |
63 | t = (((v ^ state2 ^ 0x2b) - 0x05) ^ 0x35) - 0x39; | |
64 | t = (((t ^ state1 ^ 0x5a) - 0xb0) ^ 0x38) - 0x45; | |
65 | dest[i] = state2 = t; | |
66 | state1 = v; | |
67 | } | |
68 | } | |
69 | ||
70 | static void decrypt(uint8_t *dest, const uint8_t *src, uint8_t cnt) | |
71 | { | |
72 | uint8_t state1 = 0x9b, state2 = 0x54; | |
73 | int i; | |
74 | for (i=0; i<cnt; i++) { | |
75 | uint8_t t, v = src[i]; | |
76 | t = (((v + 0x45) ^ 0x38) + 0xb0) ^ 0x5a ^ state1; | |
77 | t = (((t + 0x39) ^ 0x35) + 0x05) ^ 0x2b ^ state2; | |
78 | dest[i] = state1 = t; | |
79 | state2 = v; | |
80 | } | |
81 | } | |
82 | ||
83 | static int do_ep1_command(const struct sr_dev_inst *sdi, | |
84 | const uint8_t *command, uint8_t cmd_len, | |
85 | uint8_t *reply, uint8_t reply_len) | |
86 | { | |
87 | uint8_t buf[64]; | |
88 | struct sr_usb_dev_inst *usb; | |
89 | int ret, xfer; | |
90 | ||
91 | usb = sdi->conn; | |
92 | ||
93 | if (cmd_len < 1 || cmd_len > 64 || reply_len > 64 || | |
94 | command == NULL || (reply_len > 0 && reply == NULL)) | |
95 | return SR_ERR_ARG; | |
96 | ||
97 | encrypt(buf, command, cmd_len); | |
98 | ||
99 | ret = libusb_bulk_transfer(usb->devhdl, 1, buf, cmd_len, &xfer, 1000); | |
100 | if (ret != 0) { | |
101 | sr_dbg("Failed to send EP1 command 0x%02x: %s", | |
102 | command[0], libusb_error_name(ret)); | |
103 | return SR_ERR; | |
104 | } | |
105 | if (xfer != cmd_len) { | |
106 | sr_dbg("Failed to send EP1 command 0x%02x: incorrect length %d != %d", | |
107 | xfer, cmd_len); | |
108 | return SR_ERR; | |
109 | } | |
110 | ||
111 | if (reply_len == 0) | |
112 | return SR_OK; | |
113 | ||
114 | ret = libusb_bulk_transfer(usb->devhdl, 0x80 | 1, buf, reply_len, &xfer, 1000); | |
115 | if (ret != 0) { | |
116 | sr_dbg("Failed to receive reply to EP1 command 0x%02x: %s", | |
117 | command[0], libusb_error_name(ret)); | |
118 | return SR_ERR; | |
119 | } | |
120 | if (xfer != reply_len) { | |
121 | sr_dbg("Failed to receive reply to EP1 command 0x%02x: incorrect length %d != %d", | |
122 | xfer, reply_len); | |
123 | return SR_ERR; | |
124 | } | |
125 | ||
126 | decrypt(reply, buf, reply_len); | |
127 | ||
128 | return SR_OK; | |
129 | } | |
130 | ||
131 | static int read_eeprom(const struct sr_dev_inst *sdi, | |
132 | uint8_t address, uint8_t length, uint8_t *buf) | |
133 | { | |
134 | uint8_t command[5] = { | |
135 | COMMAND_READ_EEPROM, | |
136 | READ_EEPROM_COOKIE1, | |
137 | READ_EEPROM_COOKIE2, | |
138 | address, | |
139 | length, | |
140 | }; | |
141 | ||
142 | return do_ep1_command(sdi, command, 5, buf, length); | |
143 | } | |
144 | ||
145 | static int upload_led_table(const struct sr_dev_inst *sdi, | |
146 | const uint8_t *table, uint8_t offset, uint8_t cnt) | |
147 | { | |
148 | uint8_t command[64]; | |
149 | int ret; | |
150 | ||
151 | if (cnt < 1 || cnt+offset > 64 || table == NULL) | |
152 | return SR_ERR_ARG; | |
153 | ||
154 | while (cnt > 0) { | |
155 | uint8_t chunk = (cnt > 32? 32 : cnt); | |
156 | ||
157 | command[0] = COMMAND_WRITE_LED_TABLE; | |
158 | command[1] = offset; | |
159 | command[2] = chunk; | |
160 | memcpy(command+3, table, chunk); | |
161 | ||
162 | if ((ret = do_ep1_command(sdi, command, 3+chunk, NULL, 0)) != SR_OK) | |
163 | return ret; | |
164 | ||
165 | table += chunk; | |
166 | offset += chunk; | |
167 | cnt -= chunk; | |
168 | } | |
169 | ||
170 | return SR_OK; | |
171 | } | |
172 | ||
173 | static int set_led_mode(const struct sr_dev_inst *sdi, | |
174 | uint8_t animate, uint16_t t2reload, uint8_t div, | |
175 | uint8_t repeat) | |
176 | { | |
177 | uint8_t command[6] = { | |
178 | COMMAND_SET_LED_MODE, | |
179 | animate, | |
180 | t2reload&0xff, | |
181 | t2reload>>8, | |
182 | div, | |
183 | repeat, | |
184 | }; | |
185 | ||
186 | return do_ep1_command(sdi, command, 6, NULL, 0); | |
187 | } | |
188 | ||
189 | static int read_fpga_register(const struct sr_dev_inst *sdi, | |
190 | uint8_t address, uint8_t *value) | |
191 | { | |
192 | uint8_t command[3] = { | |
193 | COMMAND_FPGA_READ_REGISTER, | |
194 | 1, | |
195 | address, | |
196 | }; | |
197 | ||
198 | return do_ep1_command(sdi, command, 3, value, 1); | |
199 | } | |
200 | ||
201 | static int write_fpga_registers(const struct sr_dev_inst *sdi, | |
202 | uint8_t (*regs)[2], uint8_t cnt) | |
203 | { | |
204 | uint8_t command[64]; | |
205 | int i; | |
206 | ||
207 | if (cnt < 1 || cnt > 31) | |
208 | return SR_ERR_ARG; | |
209 | ||
210 | command[0] = COMMAND_FPGA_WRITE_REGISTER; | |
211 | command[1] = cnt; | |
212 | for (i=0; i<cnt; i++) { | |
213 | command[2+2*i] = regs[i][0]; | |
214 | command[3+2*i] = regs[i][1]; | |
215 | } | |
216 | ||
217 | return do_ep1_command(sdi, command, 2*(cnt+1), NULL, 0); | |
218 | } | |
219 | ||
220 | static int write_fpga_register(const struct sr_dev_inst *sdi, | |
221 | uint8_t address, uint8_t value) | |
222 | { | |
223 | uint8_t regs[2] = { address, value }; | |
224 | return write_fpga_registers(sdi, ®s, 1); | |
225 | } | |
226 | ||
227 | ||
228 | static uint8_t map_eeprom_data(uint8_t v) | |
229 | { | |
230 | /* ??? */ | |
231 | switch (v) { | |
232 | case 0x00: return 0x7a; | |
233 | case 0x01: return 0x79; | |
234 | case 0x05: return 0x85; | |
235 | case 0x10: return 0x6a; | |
236 | case 0x11: return 0x69; | |
237 | case 0x14: return 0x76; | |
238 | case 0x15: return 0x75; | |
239 | case 0x41: return 0x39; | |
240 | case 0x50: return 0x2a; | |
241 | case 0x51: return 0x29; | |
242 | case 0x55: return 0x35; | |
243 | default: | |
244 | sr_err("No mapping of 0x%02x defined", v); | |
245 | return 0xff; | |
246 | } | |
247 | } | |
248 | ||
249 | static int prime_fpga(const struct sr_dev_inst *sdi) | |
250 | { | |
251 | uint8_t eeprom_data[16]; | |
252 | uint8_t old_reg_10, status; | |
253 | uint8_t regs[8][2] = { | |
254 | {10, 0x00}, | |
255 | {10, 0x40}, | |
256 | {12, 0}, | |
257 | {10, 0xc0}, | |
258 | {10, 0x40}, | |
259 | { 6, 0}, | |
260 | { 7, 1}, | |
261 | { 7, 0} | |
262 | }; | |
263 | int i, ret; | |
264 | ||
265 | if ((ret = read_eeprom(sdi, 16, 16, eeprom_data)) != SR_OK) | |
266 | return ret; | |
267 | ||
268 | if ((ret = read_fpga_register(sdi, 10, &old_reg_10)) != SR_OK) | |
269 | return ret; | |
270 | ||
271 | for (i=0; i<16; i++) { | |
272 | regs[2][1] = eeprom_data[i]; | |
273 | regs[5][1] = map_eeprom_data(eeprom_data[i]); | |
274 | if (i) | |
275 | ret = write_fpga_registers(sdi, ®s[2], 6); | |
276 | else | |
277 | ret = write_fpga_registers(sdi, ®s[0], 8); | |
278 | if (ret != SR_OK) | |
279 | return ret; | |
280 | } | |
281 | ||
282 | if ((ret = write_fpga_register(sdi, 10, old_reg_10)) != SR_OK) | |
283 | return ret; | |
284 | ||
285 | if ((ret = read_fpga_register(sdi, 0, &status)) != SR_OK) | |
286 | return ret; | |
287 | ||
288 | if (status != 0x10) { | |
289 | sr_err("Invalid FPGA status: 0x%02x != 0x10", status); | |
290 | return SR_ERR; | |
291 | } | |
292 | ||
293 | return SR_OK; | |
294 | } | |
295 | ||
296 | static void make_heartbeat(uint8_t *table, int len) | |
297 | { | |
298 | int i, j; | |
299 | ||
300 | memset(table, 0, len); | |
301 | len >>= 3; | |
302 | for (i=0; i<2; i++) | |
303 | for (j=0; j<len; j++) | |
304 | *table++ = sin(j*M_PI/len)*255; | |
305 | } | |
306 | ||
307 | static int configure_led(const struct sr_dev_inst *sdi) | |
308 | { | |
309 | uint8_t table[64]; | |
310 | int ret; | |
311 | ||
312 | make_heartbeat(table, 64); | |
313 | if ((ret = upload_led_table(sdi, table, 0, 64)) != SR_OK) | |
314 | return ret; | |
315 | ||
316 | return set_led_mode(sdi, 1, 6250, 0, 1); | |
317 | } | |
318 | ||
319 | static int upload_fpga_bitstream(const struct sr_dev_inst *sdi, | |
320 | enum voltage_range vrange) | |
321 | { | |
322 | struct dev_context *devc; | |
323 | int offset, chunksize, ret; | |
324 | const char *filename; | |
325 | FILE *fw; | |
326 | unsigned char buf[256*62]; | |
327 | ||
328 | devc = sdi->priv; | |
329 | ||
330 | if (devc->cur_voltage_range == vrange) | |
331 | return SR_OK; | |
332 | ||
333 | switch (vrange) { | |
334 | case VOLTAGE_RANGE_18_33_V: | |
335 | filename = FPGA_FIRMWARE_18; | |
336 | break; | |
337 | case VOLTAGE_RANGE_5_V: | |
338 | filename = FPGA_FIRMWARE_33; | |
339 | break; | |
340 | default: | |
341 | sr_err("Unsupported voltage range"); | |
342 | return SR_ERR; | |
343 | } | |
344 | ||
345 | sr_info("Uploading FPGA bitstream at %s", filename); | |
346 | if ((fw = g_fopen(filename, "rb")) == NULL) { | |
347 | sr_err("Unable to open bitstream file %s for reading: %s", | |
348 | filename, strerror(errno)); | |
349 | return SR_ERR; | |
350 | } | |
351 | ||
352 | buf[0] = COMMAND_FPGA_UPLOAD_INIT; | |
353 | if ((ret = do_ep1_command(sdi, buf, 1, NULL, 0)) != SR_OK) { | |
354 | fclose(fw); | |
355 | return ret; | |
356 | } | |
357 | ||
358 | while (1) { | |
359 | chunksize = fread(buf, 1, sizeof(buf), fw); | |
360 | if (chunksize == 0) | |
361 | break; | |
362 | ||
363 | for (offset = 0; offset < chunksize; offset += 62) { | |
364 | uint8_t command[64]; | |
365 | uint8_t len = (offset + 62 > chunksize? | |
366 | chunksize - offset : 62); | |
367 | command[0] = COMMAND_FPGA_UPLOAD_SEND_DATA; | |
368 | command[1] = len; | |
369 | memcpy(command+2, buf+offset, len); | |
370 | if ((ret = do_ep1_command(sdi, command, len+2, NULL, 0)) != SR_OK) { | |
371 | fclose(fw); | |
372 | return ret; | |
373 | } | |
374 | } | |
375 | ||
376 | sr_info("Uploaded %d bytes", chunksize); | |
377 | } | |
378 | fclose(fw); | |
379 | sr_info("FPGA bitstream upload done"); | |
380 | ||
381 | if ((ret = prime_fpga(sdi)) != SR_OK) | |
382 | return ret; | |
383 | ||
384 | if ((ret = configure_led(sdi)) != SR_OK) | |
385 | return ret; | |
386 | ||
387 | /* XXX */ | |
388 | if ((ret = configure_led(sdi)) != SR_OK) | |
389 | return ret; | |
390 | ||
391 | devc->cur_voltage_range = vrange; | |
392 | return SR_OK; | |
393 | } | |
394 | ||
395 | SR_PRIV int saleae_logic16_abort_acquisition(const struct sr_dev_inst *sdi) | |
396 | { | |
397 | static const uint8_t command[2] = { | |
398 | COMMAND_ABORT_ACQUISITION_SYNC, | |
399 | ABORT_ACQUISITION_SYNC_PATTERN, | |
400 | }; | |
401 | uint8_t reply, expected_reply; | |
402 | int ret; | |
403 | ||
404 | if ((ret = do_ep1_command(sdi, command, 2, &reply, 1)) != SR_OK) | |
405 | return ret; | |
406 | ||
407 | expected_reply = ~command[1]; | |
408 | if (reply != expected_reply) { | |
409 | sr_err("Invalid response for abort acquisition command: " | |
410 | "0x%02x != 0x%02x", reply, expected_reply); | |
411 | return SR_ERR; | |
412 | } | |
413 | ||
414 | return SR_OK; | |
415 | } | |
416 | ||
417 | SR_PRIV int saleae_logic16_init_device(const struct sr_dev_inst *sdi) | |
418 | { | |
419 | struct dev_context *devc; | |
420 | int ret; | |
421 | ||
422 | devc = sdi->priv; | |
423 | ||
424 | devc->cur_voltage_range = VOLTAGE_RANGE_UNKNOWN; | |
425 | ||
426 | if ((ret = saleae_logic16_abort_acquisition(sdi)) != SR_OK) | |
427 | return ret; | |
428 | ||
429 | if ((ret = read_eeprom(sdi, 8, 8, devc->eeprom_data)) != SR_OK) | |
430 | return ret; | |
431 | ||
432 | if ((ret = upload_fpga_bitstream(sdi, VOLTAGE_RANGE_18_33_V)) != SR_OK) | |
433 | return ret; | |
434 | ||
435 | return SR_OK; | |
436 | } | |
437 | ||
c463dcf0 MC |
438 | SR_PRIV int saleae_logic16_receive_data(int fd, int revents, void *cb_data) |
439 | { | |
440 | (void)fd; | |
441 | ||
442 | const struct sr_dev_inst *sdi; | |
443 | struct dev_context *devc; | |
444 | ||
445 | if (!(sdi = cb_data)) | |
446 | return TRUE; | |
447 | ||
448 | if (!(devc = sdi->priv)) | |
449 | return TRUE; | |
450 | ||
451 | if (revents == G_IO_IN) { | |
452 | /* TODO */ | |
453 | } | |
454 | ||
455 | return TRUE; | |
456 | } |