openocd: fix SPDX tag format for files .c
[openocd.git] / src / jtag / drivers / ti_icdi_usb.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * *
5 * Copyright (C) 2012 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
7 ***************************************************************************/
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 /* project specific includes */
14 #include <helper/binarybuffer.h>
15 #include <jtag/adapter.h>
16 #include <jtag/interface.h>
17 #include <jtag/hla/hla_layout.h>
18 #include <jtag/hla/hla_transport.h>
19 #include <jtag/hla/hla_interface.h>
20 #include <target/target.h>
21
22 #include <target/cortex_m.h>
23
24 #include "libusb_helper.h"
25
26 #define ICDI_WRITE_ENDPOINT 0x02
27 #define ICDI_READ_ENDPOINT 0x83
28
29 #define ICDI_WRITE_TIMEOUT (LIBUSB_TIMEOUT_MS)
30 #define ICDI_READ_TIMEOUT (LIBUSB_TIMEOUT_MS)
31 #define ICDI_PACKET_SIZE 2048
32
33 #define PACKET_START "$"
34 #define PACKET_END "#"
35
36 struct icdi_usb_handle_s {
37 struct libusb_device_handle *usb_dev;
38
39 char *read_buffer;
40 char *write_buffer;
41 int max_packet;
42 int read_count;
43 uint32_t max_rw_packet; /* max X packet (read/write memory) transfers */
44 };
45
46 static int icdi_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
47 uint32_t count, uint8_t *buffer);
48 static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
49 uint32_t count, const uint8_t *buffer);
50
51 static int remote_escape_output(const char *buffer, int len, char *out_buf, int *out_len, int out_maxlen)
52 {
53 int input_index, output_index;
54
55 output_index = 0;
56
57 for (input_index = 0; input_index < len; input_index++) {
58
59 char b = buffer[input_index];
60
61 if (b == '$' || b == '#' || b == '}' || b == '*') {
62 /* These must be escaped. */
63 if (output_index + 2 > out_maxlen)
64 break;
65 out_buf[output_index++] = '}';
66 out_buf[output_index++] = b ^ 0x20;
67 } else {
68 if (output_index + 1 > out_maxlen)
69 break;
70 out_buf[output_index++] = b;
71 }
72 }
73
74 *out_len = input_index;
75 return output_index;
76 }
77
78 static int remote_unescape_input(const char *buffer, int len, char *out_buf, int out_maxlen)
79 {
80 int input_index, output_index;
81 int escaped;
82
83 output_index = 0;
84 escaped = 0;
85
86 for (input_index = 0; input_index < len; input_index++) {
87
88 char b = buffer[input_index];
89
90 if (output_index + 1 > out_maxlen)
91 LOG_ERROR("Received too much data from the target.");
92
93 if (escaped) {
94 out_buf[output_index++] = b ^ 0x20;
95 escaped = 0;
96 } else if (b == '}')
97 escaped = 1;
98 else
99 out_buf[output_index++] = b;
100 }
101
102 if (escaped)
103 LOG_ERROR("Unmatched escape character in target response.");
104
105 return output_index;
106 }
107
108 static int icdi_send_packet(void *handle, int len)
109 {
110 unsigned char cksum = 0;
111 struct icdi_usb_handle_s *h = handle;
112 int result, retry = 0;
113 int transferred = 0;
114
115 assert(handle);
116
117 /* check we have a large enough buffer for checksum "#00" */
118 if (len + 3 > h->max_packet) {
119 LOG_ERROR("packet buffer too small");
120 return ERROR_FAIL;
121 }
122
123 /* calculate checksum - offset start of packet */
124 for (int i = 1; i < len; i++)
125 cksum += h->write_buffer[i];
126
127 len += sprintf(&h->write_buffer[len], PACKET_END "%02x", cksum);
128
129 #ifdef _DEBUG_USB_COMMS_
130 char buffer[50];
131 char ch = h->write_buffer[1];
132 if (ch == 'x' || ch == 'X')
133 LOG_DEBUG("writing packet: <binary>");
134 else {
135 memcpy(buffer, h->write_buffer, len >= 50 ? 50-1 : len);
136 buffer[len] = 0;
137 LOG_DEBUG("writing packet: %s", buffer);
138 }
139 #endif
140
141 while (1) {
142
143 result = libusb_bulk_transfer(h->usb_dev, ICDI_WRITE_ENDPOINT, (unsigned char *)h->write_buffer, len,
144 &transferred, ICDI_WRITE_TIMEOUT);
145 if (result != 0 || transferred != len) {
146 LOG_DEBUG("Error TX Data %d", result);
147 return ERROR_FAIL;
148 }
149
150 /* check that the client got the message ok, or shall we resend */
151 result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer, h->max_packet,
152 &transferred, ICDI_READ_TIMEOUT);
153 if (result != 0 || transferred < 1) {
154 LOG_DEBUG("Error RX Data %d", result);
155 return ERROR_FAIL;
156 }
157
158 #ifdef _DEBUG_USB_COMMS_
159 LOG_DEBUG("received reply: '%c' : count %d", h->read_buffer[0], transferred);
160 #endif
161
162 if (h->read_buffer[0] == '-') {
163 LOG_DEBUG("Resending packet %d", ++retry);
164 } else {
165 if (h->read_buffer[0] != '+')
166 LOG_DEBUG("Unexpected Reply from ICDI: %c", h->read_buffer[0]);
167 break;
168 }
169
170 if (retry == 3) {
171 LOG_DEBUG("maximum nack retries attempted");
172 return ERROR_FAIL;
173 }
174 }
175
176 retry = 0;
177 h->read_count = transferred;
178
179 while (1) {
180
181 /* read reply from icdi */
182 result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer + h->read_count,
183 h->max_packet - h->read_count, &transferred, ICDI_READ_TIMEOUT);
184
185 #ifdef _DEBUG_USB_COMMS_
186 LOG_DEBUG("received data: count %d", transferred);
187 #endif
188
189 /* check for errors but retry for timeout */
190 if (result != 0) {
191
192 if (result == LIBUSB_ERROR_TIMEOUT) {
193 LOG_DEBUG("Error RX timeout %d", result);
194 } else {
195 LOG_DEBUG("Error RX Data %d", result);
196 return ERROR_FAIL;
197 }
198 }
199
200 h->read_count += transferred;
201
202 /* we need to make sure we have a full packet, including checksum */
203 if (h->read_count > 5) {
204
205 /* check that we have received an packet delimiter
206 * we do not validate the checksum
207 * reply should contain $...#AA - so we check for # */
208 if (h->read_buffer[h->read_count - 3] == '#')
209 return ERROR_OK;
210 }
211
212 if (retry++ == 3) {
213 LOG_DEBUG("maximum data retries attempted");
214 break;
215 }
216 }
217
218 return ERROR_FAIL;
219 }
220
221 static int icdi_send_cmd(void *handle, const char *cmd)
222 {
223 struct icdi_usb_handle_s *h = handle;
224
225 int cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "%s", cmd);
226 return icdi_send_packet(handle, cmd_len);
227 }
228
229 static int icdi_send_remote_cmd(void *handle, const char *data)
230 {
231 struct icdi_usb_handle_s *h = handle;
232
233 size_t cmd_len = sprintf(h->write_buffer, PACKET_START "qRcmd,");
234 cmd_len += hexify(h->write_buffer + cmd_len, (const uint8_t *)data,
235 strlen(data), h->max_packet - cmd_len);
236
237 return icdi_send_packet(handle, cmd_len);
238 }
239
240 static int icdi_get_cmd_result(void *handle)
241 {
242 struct icdi_usb_handle_s *h = handle;
243 int offset = 0;
244 char ch;
245
246 assert(handle);
247
248 do {
249 ch = h->read_buffer[offset++];
250 if (offset > h->read_count)
251 return ERROR_FAIL;
252 } while (ch != '$');
253
254 if (memcmp("OK", h->read_buffer + offset, 2) == 0)
255 return ERROR_OK;
256
257 if (h->read_buffer[offset] == 'E') {
258 /* get error code */
259 uint8_t result;
260 if (unhexify(&result, h->read_buffer + offset + 1, 1) != 1)
261 return ERROR_FAIL;
262 return result;
263 }
264
265 /* for now we assume everything else is ok */
266 return ERROR_OK;
267 }
268
269 static int icdi_usb_idcode(void *handle, uint32_t *idcode)
270 {
271 *idcode = 0;
272 return ERROR_OK;
273 }
274
275 static int icdi_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
276 {
277 uint8_t buf[4];
278 /* REVISIT: There's no target pointer here so there's no way to use target_buffer_set_u32().
279 * I guess all supported chips are little-endian anyway. */
280 h_u32_to_le(buf, val);
281 return icdi_usb_write_mem(handle, addr, 4, 1, buf);
282 }
283
284 static enum target_state icdi_usb_state(void *handle)
285 {
286 int result;
287 struct icdi_usb_handle_s *h = handle;
288 uint32_t dhcsr;
289 uint8_t buf[4];
290
291 result = icdi_usb_read_mem(h, DCB_DHCSR, 4, 1, buf);
292 if (result != ERROR_OK)
293 return TARGET_UNKNOWN;
294
295 /* REVISIT: There's no target pointer here so there's no way to use target_buffer_get_u32().
296 * I guess all supported chips are little-endian anyway. */
297 dhcsr = le_to_h_u32(buf);
298 if (dhcsr & S_HALT)
299 return TARGET_HALTED;
300
301 return TARGET_RUNNING;
302 }
303
304 static int icdi_usb_version(void *handle)
305 {
306 struct icdi_usb_handle_s *h = handle;
307
308 char version[20];
309
310 /* get info about icdi */
311 int result = icdi_send_remote_cmd(handle, "version");
312 if (result != ERROR_OK)
313 return result;
314
315 if (h->read_count < 8) {
316 LOG_ERROR("Invalid Reply Received");
317 return ERROR_FAIL;
318 }
319
320 /* convert reply */
321 if (unhexify((uint8_t *)version, h->read_buffer + 2, 4) != 4) {
322 LOG_WARNING("unable to get ICDI version");
323 return ERROR_OK;
324 }
325
326 /* null terminate and print info */
327 version[4] = 0;
328
329 LOG_INFO("ICDI Firmware version: %s", version);
330
331 return ERROR_OK;
332 }
333
334 static int icdi_usb_query(void *handle)
335 {
336 int result;
337
338 struct icdi_usb_handle_s *h = handle;
339
340 result = icdi_send_cmd(handle, "qSupported");
341 if (result != ERROR_OK)
342 return result;
343
344 /* check result */
345 result = icdi_get_cmd_result(handle);
346 if (result != ERROR_OK) {
347 LOG_ERROR("query supported failed: 0x%x", result);
348 return ERROR_FAIL;
349 }
350
351 /* from this we can get the max packet supported */
352
353 /* query packet buffer size */
354 char *offset = strstr(h->read_buffer, "PacketSize");
355 if (offset) {
356 char *separator;
357 int max_packet;
358
359 max_packet = strtol(offset + 11, &separator, 16);
360 if (!max_packet)
361 LOG_ERROR("invalid max packet, using defaults");
362 else
363 h->max_packet = max_packet;
364 LOG_DEBUG("max packet supported : %i bytes", h->max_packet);
365 }
366
367
368 /* if required re allocate packet buffer */
369 if (h->max_packet != ICDI_PACKET_SIZE) {
370 h->read_buffer = realloc(h->read_buffer, h->max_packet);
371 h->write_buffer = realloc(h->write_buffer, h->max_packet);
372 if (h->read_buffer == 0 || h->write_buffer == 0) {
373 LOG_ERROR("unable to reallocate memory");
374 return ERROR_FAIL;
375 }
376 }
377
378 /* set extended mode */
379 result = icdi_send_cmd(handle, "!");
380 if (result != ERROR_OK)
381 return result;
382
383 /* check result */
384 result = icdi_get_cmd_result(handle);
385 if (result != ERROR_OK) {
386 LOG_ERROR("unable to enable extended mode: 0x%x", result);
387 return ERROR_FAIL;
388 }
389
390 return ERROR_OK;
391 }
392
393 static int icdi_usb_reset(void *handle)
394 {
395 /* we do this in hla_target.c */
396 return ERROR_OK;
397 }
398
399 static int icdi_usb_assert_srst(void *handle, int srst)
400 {
401 /* TODO not supported yet */
402 return ERROR_COMMAND_NOTFOUND;
403 }
404
405 static int icdi_usb_run(void *handle)
406 {
407 int result;
408
409 /* resume target at current address */
410 result = icdi_send_cmd(handle, "c");
411 if (result != ERROR_OK)
412 return result;
413
414 /* check result */
415 result = icdi_get_cmd_result(handle);
416 if (result != ERROR_OK) {
417 LOG_ERROR("continue failed: 0x%x", result);
418 return ERROR_FAIL;
419 }
420
421 return result;
422 }
423
424 static int icdi_usb_halt(void *handle)
425 {
426 int result;
427
428 /* this query halts the target ?? */
429 result = icdi_send_cmd(handle, "?");
430 if (result != ERROR_OK)
431 return result;
432
433 /* check result */
434 result = icdi_get_cmd_result(handle);
435 if (result != ERROR_OK) {
436 LOG_ERROR("halt failed: 0x%x", result);
437 return ERROR_FAIL;
438 }
439
440 return result;
441 }
442
443 static int icdi_usb_step(void *handle)
444 {
445 int result;
446
447 /* step target at current address */
448 result = icdi_send_cmd(handle, "s");
449 if (result != ERROR_OK)
450 return result;
451
452 /* check result */
453 result = icdi_get_cmd_result(handle);
454 if (result != ERROR_OK) {
455 LOG_ERROR("step failed: 0x%x", result);
456 return ERROR_FAIL;
457 }
458
459 return result;
460 }
461
462 static int icdi_usb_read_regs(void *handle)
463 {
464 /* currently unsupported */
465 return ERROR_OK;
466 }
467
468 static int icdi_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val)
469 {
470 int result;
471 struct icdi_usb_handle_s *h = handle;
472 char cmd[10];
473
474 snprintf(cmd, sizeof(cmd), "p%x", regsel);
475 result = icdi_send_cmd(handle, cmd);
476 if (result != ERROR_OK)
477 return result;
478
479 /* check result */
480 result = icdi_get_cmd_result(handle);
481 if (result != ERROR_OK) {
482 LOG_ERROR("register read failed: 0x%x", result);
483 return ERROR_FAIL;
484 }
485
486 /* convert result */
487 uint8_t buf[4];
488 if (unhexify(buf, h->read_buffer + 2, 4) != 4) {
489 LOG_ERROR("failed to convert result");
490 return ERROR_FAIL;
491 }
492 *val = le_to_h_u32(buf);
493
494 return result;
495 }
496
497 static int icdi_usb_write_reg(void *handle, unsigned int regsel, uint32_t val)
498 {
499 int result;
500 char cmd[20];
501 uint8_t buf[4];
502 h_u32_to_le(buf, val);
503
504 int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", regsel);
505 hexify(cmd + cmd_len, buf, 4, sizeof(cmd));
506
507 result = icdi_send_cmd(handle, cmd);
508 if (result != ERROR_OK)
509 return result;
510
511 /* check result */
512 result = icdi_get_cmd_result(handle);
513 if (result != ERROR_OK) {
514 LOG_ERROR("register write failed: 0x%x", result);
515 return ERROR_FAIL;
516 }
517
518 return result;
519 }
520
521 static int icdi_usb_read_mem_int(void *handle, uint32_t addr, uint32_t len, uint8_t *buffer)
522 {
523 int result;
524 struct icdi_usb_handle_s *h = handle;
525 char cmd[20];
526
527 snprintf(cmd, sizeof(cmd), "x%" PRIx32 ",%" PRIx32, addr, len);
528 result = icdi_send_cmd(handle, cmd);
529 if (result != ERROR_OK)
530 return result;
531
532 /* check result */
533 result = icdi_get_cmd_result(handle);
534 if (result != ERROR_OK) {
535 LOG_ERROR("memory read failed: 0x%x", result);
536 return ERROR_FAIL;
537 }
538
539 /* unescape input */
540 int read_len = remote_unescape_input(h->read_buffer + 5, h->read_count - 8, (char *)buffer, len);
541 if (read_len != (int)len) {
542 LOG_ERROR("read more bytes than expected: actual 0x%x expected 0x%" PRIx32, read_len, len);
543 return ERROR_FAIL;
544 }
545
546 return ERROR_OK;
547 }
548
549 static int icdi_usb_write_mem_int(void *handle, uint32_t addr, uint32_t len, const uint8_t *buffer)
550 {
551 int result;
552 struct icdi_usb_handle_s *h = handle;
553
554 size_t cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "X%" PRIx32 ",%" PRIx32 ":", addr, len);
555
556 int out_len;
557 cmd_len += remote_escape_output((const char *)buffer, len, h->write_buffer + cmd_len,
558 &out_len, h->max_packet - cmd_len);
559
560 if (out_len < (int)len) {
561 /* for now issue a error as we have no way of allocating a larger buffer */
562 LOG_ERROR("memory buffer too small: requires 0x%x actual 0x%" PRIx32, out_len, len);
563 return ERROR_FAIL;
564 }
565
566 result = icdi_send_packet(handle, cmd_len);
567 if (result != ERROR_OK)
568 return result;
569
570 /* check result */
571 result = icdi_get_cmd_result(handle);
572 if (result != ERROR_OK) {
573 LOG_ERROR("memory write failed: 0x%x", result);
574 return ERROR_FAIL;
575 }
576
577 return ERROR_OK;
578 }
579
580 static int icdi_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
581 uint32_t count, uint8_t *buffer)
582 {
583 int retval = ERROR_OK;
584 struct icdi_usb_handle_s *h = handle;
585 uint32_t bytes_remaining;
586
587 /* calculate byte count */
588 count *= size;
589
590 while (count) {
591
592 bytes_remaining = h->max_rw_packet;
593 if (count < bytes_remaining)
594 bytes_remaining = count;
595
596 retval = icdi_usb_read_mem_int(handle, addr, bytes_remaining, buffer);
597 if (retval != ERROR_OK)
598 return retval;
599
600 buffer += bytes_remaining;
601 addr += bytes_remaining;
602 count -= bytes_remaining;
603 }
604
605 return retval;
606 }
607
608 static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
609 uint32_t count, const uint8_t *buffer)
610 {
611 int retval = ERROR_OK;
612 struct icdi_usb_handle_s *h = handle;
613 uint32_t bytes_remaining;
614
615 /* calculate byte count */
616 count *= size;
617
618 while (count) {
619
620 bytes_remaining = h->max_rw_packet;
621 if (count < bytes_remaining)
622 bytes_remaining = count;
623
624 retval = icdi_usb_write_mem_int(handle, addr, bytes_remaining, buffer);
625 if (retval != ERROR_OK)
626 return retval;
627
628 buffer += bytes_remaining;
629 addr += bytes_remaining;
630 count -= bytes_remaining;
631 }
632
633 return retval;
634 }
635
636 static int icdi_usb_override_target(const char *targetname)
637 {
638 return !strcmp(targetname, "cortex_m");
639 }
640
641 static int icdi_usb_close(void *handle)
642 {
643 struct icdi_usb_handle_s *h = handle;
644
645 if (!h)
646 return ERROR_OK;
647
648 if (h->usb_dev)
649 jtag_libusb_close(h->usb_dev);
650
651 free(h->read_buffer);
652 free(h->write_buffer);
653 free(handle);
654 return ERROR_OK;
655 }
656
657 static int icdi_usb_open(struct hl_interface_param_s *param, void **fd)
658 {
659 /* TODO: Convert remaining libusb_ calls to jtag_libusb_ */
660 int retval;
661 struct icdi_usb_handle_s *h;
662
663 LOG_DEBUG("icdi_usb_open");
664
665 h = calloc(1, sizeof(struct icdi_usb_handle_s));
666
667 if (h == 0) {
668 LOG_ERROR("unable to allocate memory");
669 return ERROR_FAIL;
670 }
671
672 for (uint8_t i = 0; param->vid[i] && param->pid[i]; ++i)
673 LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", param->transport,
674 param->vid[i], param->pid[i], adapter_get_required_serial() ? adapter_get_required_serial() : "");
675
676 /* TI (Stellaris) ICDI provides its serial number in the USB descriptor;
677 no need to provide a callback here. */
678 jtag_libusb_open(param->vid, param->pid, &h->usb_dev, NULL);
679
680 if (!h->usb_dev) {
681 LOG_ERROR("open failed");
682 goto error_open;
683 }
684
685 if (libusb_claim_interface(h->usb_dev, 2)) {
686 LOG_DEBUG("claim interface failed");
687 goto error_open;
688 }
689
690 /* check if mode is supported */
691 retval = ERROR_OK;
692
693 switch (param->transport) {
694 #if 0
695 /* TODO place holder as swd is not currently supported */
696 case HL_TRANSPORT_SWD:
697 #endif
698 case HL_TRANSPORT_JTAG:
699 break;
700 default:
701 retval = ERROR_FAIL;
702 break;
703 }
704
705 if (retval != ERROR_OK) {
706 LOG_ERROR("mode (transport) not supported by device");
707 goto error_open;
708 }
709
710 /* allocate buffer */
711 h->read_buffer = malloc(ICDI_PACKET_SIZE);
712 h->write_buffer = malloc(ICDI_PACKET_SIZE);
713 h->max_packet = ICDI_PACKET_SIZE;
714
715 if (h->read_buffer == 0 || h->write_buffer == 0) {
716 LOG_DEBUG("malloc failed");
717 goto error_open;
718 }
719
720 /* query icdi version etc */
721 retval = icdi_usb_version(h);
722 if (retval != ERROR_OK)
723 goto error_open;
724
725 /* query icdi support */
726 retval = icdi_usb_query(h);
727 if (retval != ERROR_OK)
728 goto error_open;
729
730 *fd = h;
731
732 /* set the max target read/write buffer in bytes
733 * as we are using gdb binary packets to transfer memory we have to
734 * reserve half the buffer for any possible escape chars plus
735 * at least 64 bytes for the gdb packet header */
736 h->max_rw_packet = (((h->max_packet - 64) / 4) * 4) / 2;
737
738 return ERROR_OK;
739
740 error_open:
741 icdi_usb_close(h);
742
743 return ERROR_FAIL;
744 }
745
746 struct hl_layout_api_s icdi_usb_layout_api = {
747 .open = icdi_usb_open,
748 .close = icdi_usb_close,
749 .idcode = icdi_usb_idcode,
750 .state = icdi_usb_state,
751 .reset = icdi_usb_reset,
752 .assert_srst = icdi_usb_assert_srst,
753 .run = icdi_usb_run,
754 .halt = icdi_usb_halt,
755 .step = icdi_usb_step,
756 .read_regs = icdi_usb_read_regs,
757 .read_reg = icdi_usb_read_reg,
758 .write_reg = icdi_usb_write_reg,
759 .read_mem = icdi_usb_read_mem,
760 .write_mem = icdi_usb_write_mem,
761 .write_debug_reg = icdi_usb_write_debug_reg,
762 .override_target = icdi_usb_override_target,
763 .custom_command = icdi_send_remote_cmd,
764 };

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)