ab4fe77ab08312e115dfa99f6223b06166533ff2
[openocd.git] / src / jtag / usbprog.c
1 /***************************************************************************
2 * Copyright (C) 2007 by Benedikt Sauter sauter@ixbat.de *
3 * based on Dominic Rath's amt_jtagaccel.c *
4 * *
5 * usbprog is a free programming adapter. You can easily install *
6 * different firmware versions from an "online pool" over USB. *
7 * The adapter can be used for programming and debugging AVR and ARM *
8 * processors, as USB to RS232 converter, as JTAG interface or as *
9 * simple I/O interface (5 lines). *
10 * *
11 * http://www.embedded-projects.net/usbprog *
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 * This program is distributed in the hope that it will be useful, *
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
21 * GNU General Public License for more details. *
22 * *
23 * You should have received a copy of the GNU General Public License *
24 * along with this program; if not, write to the *
25 * Free Software Foundation, Inc., *
26 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
27 ***************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include "replacements.h"
34
35 #include "jtag.h"
36 #include <usb.h>
37
38 /* system includes */
39
40 #include "log.h"
41
42 #define VID 0x1781
43 #define PID 0x0c63
44
45 /* Pins at usbprog */
46 #define TDO_BIT 0
47 #define TDI_BIT 3
48 #define TCK_BIT 2
49 #define TMS_BIT 1
50
51 int usbprog_execute_queue(void);
52 int usbprog_speed(int speed);
53 int usbprog_register_commands(struct command_context_s *cmd_ctx);
54 int usbprog_init(void);
55 int usbprog_quit(void);
56
57 void usbprog_end_state(enum tap_state state);
58 void usbprog_state_move(void);
59 void usbprog_path_move(pathmove_command_t *cmd);
60 void usbprog_runtest(int num_cycles);
61 void usbprog_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size);
62
63 jtag_interface_t usbprog_interface =
64 {
65 .name = "usbprog",
66 .execute_queue = usbprog_execute_queue,
67 .speed = usbprog_speed,
68 .register_commands = usbprog_register_commands,
69 .init = usbprog_init,
70 .quit = usbprog_quit
71 };
72
73 #define UNKOWN_COMMAND 0x00
74 #define PORT_DIRECTION 0x01
75 #define PORT_SET 0x02
76 #define PORT_GET 0x03
77 #define PORT_SETBIT 0x04
78 #define PORT_GETBIT 0x05
79 #define WRITE_TDI 0x06
80 #define READ_TDO 0x07
81 #define WRITE_AND_READ 0x08
82 #define WRITE_TMS 0x09
83 #define WRITE_TMS_CHAIN 0x0A
84
85 struct usbprog_jtag
86 {
87 struct usb_dev_handle* usb_handle;
88 };
89
90 struct usbprog_jtag * usbprog_jtag_handle;
91
92 struct usbprog_jtag* usbprog_jtag_open();
93 void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag);
94 void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag);
95 unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen);
96
97 void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char * buffer, int size);
98 void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char * buffer, int size);
99 void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char * buffer, int size);
100 void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan);
101
102 char tms_chain[64];
103 int tms_chain_index;
104 void usbprog_jtag_tms_collect(char tms_scan);
105 void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag);
106
107 void usbprog_write(int tck, int tms, int tdi);
108 void usbprog_reset(int trst, int srst);
109
110 void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction);
111 void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag,unsigned char value);
112 unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag);
113 void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag,int bit, int value);
114 int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit);
115
116 int usbprog_speed(int speed)
117 {
118 return ERROR_OK;
119 }
120
121 int usbprog_register_commands(struct command_context_s *cmd_ctx)
122 {
123 return ERROR_OK;
124 }
125
126 int usbprog_execute_queue(void)
127 {
128 jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
129 int scan_size;
130 enum scan_type type;
131 u8 *buffer;
132
133 while (cmd)
134 {
135 switch (cmd->type)
136 {
137 case JTAG_END_STATE:
138 #ifdef _DEBUG_JTAG_IO_
139 DEBUG("end_state: %i", cmd->cmd.end_state->end_state);
140 #endif
141 if (cmd->cmd.end_state->end_state != -1)
142 usbprog_end_state(cmd->cmd.end_state->end_state);
143 break;
144 case JTAG_RESET:
145 #ifdef _DEBUG_JTAG_IO_
146 DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
147 #endif
148 if (cmd->cmd.reset->trst == 1)
149 {
150 cur_state = TAP_TLR;
151 }
152 usbprog_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
153 break;
154 case JTAG_RUNTEST:
155 #ifdef _DEBUG_JTAG_IO_
156 DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
157 #endif
158 if (cmd->cmd.runtest->end_state != -1)
159 usbprog_end_state(cmd->cmd.runtest->end_state);
160 usbprog_runtest(cmd->cmd.runtest->num_cycles);
161 break;
162 case JTAG_STATEMOVE:
163 #ifdef _DEBUG_JTAG_IO_
164 DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
165 #endif
166 if (cmd->cmd.statemove->end_state != -1)
167 usbprog_end_state(cmd->cmd.statemove->end_state);
168 usbprog_state_move();
169 break;
170 case JTAG_PATHMOVE:
171 #ifdef _DEBUG_JTAG_IO_
172 DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states,
173 cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
174 #endif
175 usbprog_path_move(cmd->cmd.pathmove);
176 break;
177 case JTAG_SCAN:
178 #ifdef _DEBUG_JTAG_IO_
179 DEBUG("scan end in %i", cmd->cmd.scan->end_state);
180 #endif
181 if (cmd->cmd.scan->end_state != -1)
182 usbprog_end_state(cmd->cmd.scan->end_state);
183 scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
184 type = jtag_scan_type(cmd->cmd.scan);
185 usbprog_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
186 if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
187 return ERROR_JTAG_QUEUE_FAILED;
188 if (buffer)
189 free(buffer);
190 break;
191 case JTAG_SLEEP:
192 #ifdef _DEBUG_JTAG_IO_
193 DEBUG("sleep %i", cmd->cmd.sleep->us);
194 #endif
195 jtag_sleep(cmd->cmd.sleep->us);
196 break;
197 default:
198 ERROR("BUG: unknown JTAG command type encountered");
199 exit(-1);
200 }
201
202 cmd = cmd->next;
203 }
204
205 return ERROR_OK;
206 }
207
208 int usbprog_init(void)
209 {
210 usbprog_jtag_handle = usbprog_jtag_open();
211
212 tms_chain_index = 0;
213 if (usbprog_jtag_handle == 0)
214 {
215 ERROR("Can't find USB JTAG Interface! Please check connection and permissions.");
216 return ERROR_JTAG_INIT_FAILED;
217 }
218
219 INFO("USB JTAG Interface ready!");
220
221 usbprog_jtag_init(usbprog_jtag_handle);
222 usbprog_reset(0, 0);
223 usbprog_write(0, 0, 0);
224
225 return ERROR_OK;
226 }
227
228 int usbprog_quit(void)
229 {
230 return ERROR_OK;
231 }
232
233 /*************** jtag execute commands **********************/
234 void usbprog_end_state(enum tap_state state)
235 {
236 if (tap_move_map[state] != -1)
237 end_state = state;
238 else
239 {
240 ERROR("BUG: %i is not a valid end state", state);
241 exit(-1);
242 }
243 }
244
245 void usbprog_state_move(void)
246 {
247 int i = 0, tms = 0;
248 u8 tms_scan = TAP_MOVE(cur_state, end_state);
249
250 usbprog_jtag_write_tms(usbprog_jtag_handle, (char)tms_scan);
251 for (i = 0; i < 7; i++)
252 {
253 tms = (tms_scan >> i) & 1;
254 }
255
256 cur_state = end_state;
257 }
258
259 void usbprog_path_move(pathmove_command_t *cmd)
260 {
261 int num_states = cmd->num_states;
262 int state_count;
263
264 state_count = 0;
265 while (num_states)
266 {
267 if (tap_transitions[cur_state].low == cmd->path[state_count])
268 {
269 //INFO("1");
270 usbprog_write(0, 0, 0);
271 usbprog_write(1, 0, 0);
272 }
273 else if (tap_transitions[cur_state].high == cmd->path[state_count])
274 {
275 //INFO("2");
276 usbprog_write(0, 1, 0);
277 usbprog_write(1, 1, 0);
278 }
279 else
280 {
281 ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_strings[cur_state], tap_state_strings[cmd->path[state_count]]);
282 exit(-1);
283 }
284
285 cur_state = cmd->path[state_count];
286 state_count++;
287 num_states--;
288 }
289
290 end_state = cur_state;
291 }
292
293 void usbprog_runtest(int num_cycles)
294 {
295 int i;
296
297 /* only do a state_move when we're not already in RTI */
298 if (cur_state != TAP_RTI)
299 {
300 usbprog_end_state(TAP_RTI);
301 usbprog_state_move();
302 }
303
304 /* execute num_cycles */
305 if (num_cycles > 0)
306 {
307 usbprog_jtag_tms_send(usbprog_jtag_handle);
308 usbprog_write(0, 0, 0);
309 }
310 else
311 {
312 usbprog_jtag_tms_send(usbprog_jtag_handle);
313 //INFO("NUM CYCLES %i",num_cycles);
314 }
315
316 for (i = 0; i < num_cycles; i++)
317 {
318 usbprog_write(1, 0, 0);
319 usbprog_write(0, 0, 0);
320 }
321
322 /* finish in end_state */
323 /*
324 usbprog_end_state(saved_end_state);
325 if (cur_state != end_state)
326 usbprog_state_move();
327 */
328 }
329
330 void usbprog_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
331 {
332 enum tap_state saved_end_state = end_state;
333
334 if (ir_scan)
335 usbprog_end_state(TAP_SI);
336 else
337 usbprog_end_state(TAP_SD);
338
339 //usbprog_jtag_tms_send(usbprog_jtag_handle);
340
341 usbprog_state_move();
342 usbprog_end_state(saved_end_state);
343
344 usbprog_jtag_tms_send(usbprog_jtag_handle);
345
346 if (type == SCAN_OUT)
347 {
348 usbprog_jtag_write_tdi(usbprog_jtag_handle,buffer, scan_size);
349 }
350 if (type == SCAN_IN)
351 {
352 usbprog_jtag_read_tdo(usbprog_jtag_handle,buffer, scan_size);
353 }
354 if (type == SCAN_IO)
355 {
356 usbprog_jtag_write_and_read(usbprog_jtag_handle,buffer, scan_size);
357 }
358
359 if (ir_scan)
360 cur_state = TAP_PI;
361 else
362 cur_state = TAP_PD;
363
364 if (cur_state != end_state)
365 usbprog_state_move();
366 }
367
368 /*************** jtag wrapper functions *********************/
369
370 void usbprog_write(int tck, int tms, int tdi)
371 {
372 unsigned char output_value=0x00;
373
374 if (tms)
375 output_value |= (1<<TMS_BIT);
376 if (tdi)
377 output_value |= (1<<TDI_BIT);
378 if (tck)
379 output_value |= (1<<TCK_BIT);
380
381 usbprog_jtag_write_slice(usbprog_jtag_handle,output_value);
382 }
383
384 /* (1) assert or (0) deassert reset lines */
385 void usbprog_reset(int trst, int srst)
386 {
387 DEBUG("trst: %i, srst: %i", trst, srst);
388
389 if (trst)
390 usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 0);
391 else
392 usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 1);
393
394 if (srst)
395 usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 0);
396 else
397 usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 1);
398 }
399
400 /*************** jtag lowlevel functions ********************/
401
402 struct usb_bus *busses;
403
404 struct usbprog_jtag* usbprog_jtag_open()
405 {
406 struct usb_bus *bus;
407 struct usb_device *dev;
408
409 struct usbprog_jtag *tmp;
410
411 tmp = (struct usbprog_jtag*)malloc(sizeof(struct usbprog_jtag));
412
413 usb_set_debug(10);
414 usb_init();
415 usb_find_busses();
416 usb_find_devices();
417
418 busses = usb_get_busses();
419
420 /* find usbprog_jtag device in usb bus */
421
422 for (bus = busses; bus; bus = bus->next)
423 {
424 for (dev = bus->devices; dev; dev = dev->next)
425 {
426 /* condition for sucessfully hit (too bad, I only check the vendor id)*/
427 if (dev->descriptor.idVendor == VID && dev->descriptor.idProduct == PID)
428 {
429 tmp->usb_handle = usb_open(dev);
430 usb_set_configuration(tmp->usb_handle, 1);
431 usb_claim_interface(tmp->usb_handle, 0);
432 usb_set_altinterface(tmp->usb_handle, 0);
433 return tmp;
434 }
435 }
436 }
437 return 0;
438 }
439
440 void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag)
441 {
442 usb_close(usbprog_jtag->usb_handle);
443 free(usbprog_jtag);
444 }
445
446 unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen)
447 {
448 int res = usb_bulk_write(usbprog_jtag->usb_handle, 3, msg,msglen, 100);
449 if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || \
450 (msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9))
451 return 1;
452 if (res == msglen)
453 {
454 //INFO("HALLLLOOO %i",(int)msg[0]);
455 res = usb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100);
456 if (res > 0)
457 return (unsigned char)msg[1];
458 else
459 return -1;
460 }
461 else
462 return -1;
463 return 0;
464 }
465
466 void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag)
467 {
468 usbprog_jtag_set_direction(usbprog_jtag, 0xFE);
469 }
470
471 void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char * buffer, int size)
472 {
473 char tmp[64]; // fastes packet size for usb controller
474 int send_bits, bufindex = 0, fillindex = 0, i, loops;
475
476 char swap;
477 // 61 byte can be transfered (488 bit)
478
479 while (size > 0)
480 {
481 if (size > 488)
482 {
483 send_bits = 488;
484 size = size - 488;
485 loops = 61;
486 }
487 else
488 {
489 send_bits = size;
490 loops = size / 8;
491 loops++;
492 size = 0;
493 }
494 tmp[0] = WRITE_AND_READ;
495 tmp[1] = (char)(send_bits >> 8); // high
496 tmp[2] = (char)(send_bits); // low
497 i = 0;
498
499 for (i = 0; i < loops; i++)
500 {
501 tmp[3 + i] = buffer[bufindex];
502 bufindex++;
503 }
504
505 if (usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000) == 64)
506 {
507 //INFO("HALLLLOOO2 %i",(int)tmp[0]);
508 usleep(1);
509 int timeout = 0;
510 while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000) < 1)
511 {
512 timeout++;
513 if (timeout > 10)
514 break;
515 }
516
517 for (i = 0; i < loops; i++)
518 {
519 swap = tmp[3 + i];
520 buffer[fillindex++] = swap;
521 }
522 }
523 }
524 }
525
526 void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char * buffer, int size)
527 {
528 char tmp[64]; // fastes packet size for usb controller
529 int send_bits, fillindex = 0, i, loops;
530
531 char swap;
532 // 61 byte can be transfered (488 bit)
533
534 while (size > 0)
535 {
536 if (size > 488)
537 {
538 send_bits = 488;
539 size = size - 488;
540 loops = 61;
541 }
542 else
543 {
544 send_bits = size;
545 loops = size / 8;
546 loops++;
547 size = 0;
548 }
549 tmp[0] = WRITE_AND_READ;
550 tmp[1] = (char)(send_bits >> 8); // high
551 tmp[2] = (char)(send_bits); // low
552
553 usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000);
554
555 //INFO("HALLLLOOO3 %i",(int)tmp[0]);
556 int timeout = 0;
557 usleep(1);
558 while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10) < 1)
559 {
560 timeout++;
561 if (timeout > 10)
562 break;
563 }
564
565 for (i = 0; i < loops; i++)
566 {
567 swap = tmp[3 + i];
568 buffer[fillindex++] = swap;
569 }
570 }
571 }
572
573 void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char * buffer, int size)
574 {
575 char tmp[64]; // fastes packet size for usb controller
576 int send_bits, bufindex = 0, i, loops;
577
578 // 61 byte can be transfered (488 bit)
579 while (size > 0)
580 {
581 if (size > 488)
582 {
583 send_bits = 488;
584 size = size - 488;
585 loops = 61;
586 }
587 else
588 {
589 send_bits = size;
590 loops = size/8;
591 //if(loops==0)
592 loops++;
593 size = 0;
594 }
595 tmp[0] = WRITE_TDI;
596 tmp[1] = (char)(send_bits >> 8); // high
597 tmp[2] = (char)(send_bits); // low
598 i = 0;
599
600 for (i = 0; i < loops; i++)
601 {
602 tmp[3 + i] = buffer[bufindex];
603 bufindex++;
604 }
605 usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000);
606 }
607 }
608
609 void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan)
610 {
611 usbprog_jtag_tms_collect(tms_scan);
612 }
613
614 void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction)
615 {
616 char tmp[2];
617 tmp[0] = PORT_DIRECTION;
618 tmp[1] = (char)direction;
619 usbprog_jtag_message(usbprog_jtag, tmp, 2);
620 }
621
622 void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag,unsigned char value)
623 {
624 char tmp[2];
625 tmp[0] = PORT_SET;
626 tmp[1] = (char)value;
627 usbprog_jtag_message(usbprog_jtag, tmp, 2);
628 }
629
630 unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag)
631 {
632 char tmp[2];
633 tmp[0] = PORT_GET;
634 tmp[1] = 0x00;
635 return usbprog_jtag_message(usbprog_jtag, tmp, 2);
636 }
637
638 void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag,int bit, int value)
639 {
640 char tmp[3];
641 tmp[0] = PORT_SETBIT;
642 tmp[1] = (char)bit;
643 if (value == 1)
644 tmp[2] = 0x01;
645 else
646 tmp[2] = 0x00;
647 usbprog_jtag_message(usbprog_jtag, tmp, 3);
648 }
649
650 int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit)
651 {
652 char tmp[2];
653 tmp[0] = PORT_GETBIT;
654 tmp[1] = (char)bit;
655
656 if (usbprog_jtag_message(usbprog_jtag, tmp, 2) > 0)
657 return 1;
658 else
659 return 0;
660 }
661
662 void usbprog_jtag_tms_collect(char tms_scan)
663 {
664 tms_chain[tms_chain_index] = tms_scan;
665 tms_chain_index++;
666 }
667
668 void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag)
669 {
670 int i;
671 //INFO("TMS SEND");
672 if (tms_chain_index > 0)
673 {
674 char tmp[tms_chain_index + 2];
675 tmp[0] = WRITE_TMS_CHAIN;
676 tmp[1] = (char)(tms_chain_index);
677 for (i = 0; i < tms_chain_index + 1; i++)
678 tmp[2 + i] = tms_chain[i];
679 usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000);
680 tms_chain_index = 0;
681 }
682 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)