stlink: add read/write 8bit memory
[openocd.git] / src / jtag / drivers / stlink_usb.c
1 /***************************************************************************
2 * Copyright (C) 2011 by Mathias Kuester *
3 * Mathias Kuester <kesmtp@freenet.de> *
4 * *
5 * This code is based on https://github.com/texane/stlink *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 /* project specific includes */
28 #include <helper/binarybuffer.h>
29 #include <jtag/interface.h>
30 #include <jtag/stlink/stlink_layout.h>
31 #include <jtag/stlink/stlink_interface.h>
32 #include <target/target.h>
33
34 #include "libusb_common.h"
35
36 #define ENDPOINT_IN 0x80
37 #define ENDPOINT_OUT 0x00
38
39 #define STLINK_RX_EP (1|ENDPOINT_IN)
40 #define STLINK_TX_EP (2|ENDPOINT_OUT)
41 #define STLINK_CMD_SIZE (16)
42 #define STLINK_TX_SIZE (4*128)
43 #define STLINK_RX_SIZE (4*128)
44
45 /** */
46 struct stlink_usb_handle_s {
47 /** */
48 struct jtag_libusb_device_handle *fd;
49 /** */
50 struct libusb_transfer *trans;
51 /** */
52 uint8_t txbuf[STLINK_TX_SIZE];
53 /** */
54 uint8_t rxbuf[STLINK_RX_SIZE];
55 };
56
57 #define STLINK_OK 0x80
58 #define STLINK_FALSE 0x81
59 #define STLINK_CORE_RUNNING 0x80
60 #define STLINK_CORE_HALTED 0x81
61 #define STLINK_CORE_STAT_UNKNOWN -1
62
63 #define STLINK_GET_VERSION 0xf1
64 #define STLINK_GET_CURRENT_MODE 0xf5
65
66 #define STLINK_DEBUG_COMMAND 0xF2
67 #define STLINK_DFU_COMMAND 0xF3
68 #define STLINK_DFU_EXIT 0x07
69
70 #define STLINK_DEV_DFU_MODE 0x00
71 #define STLINK_DEV_MASS_MODE 0x01
72 #define STLINK_DEV_DEBUG_MODE 0x02
73 #define STLINK_DEV_UNKNOWN_MODE -1
74
75 #define STLINK_DEBUG_ENTER 0x20
76 #define STLINK_DEBUG_EXIT 0x21
77 #define STLINK_DEBUG_READCOREID 0x22
78
79 #define STLINK_DEBUG_GETSTATUS 0x01
80 #define STLINK_DEBUG_FORCEDEBUG 0x02
81 #define STLINK_DEBUG_RESETSYS 0x03
82 #define STLINK_DEBUG_READALLREGS 0x04
83 #define STLINK_DEBUG_READREG 0x05
84 #define STLINK_DEBUG_WRITEREG 0x06
85 #define STLINK_DEBUG_READMEM_32BIT 0x07
86 #define STLINK_DEBUG_WRITEMEM_32BIT 0x08
87 #define STLINK_DEBUG_RUNCORE 0x09
88 #define STLINK_DEBUG_STEPCORE 0x0a
89 #define STLINK_DEBUG_SETFP 0x0b
90 #define STLINK_DEBUG_READMEM_8BIT 0x0c
91 #define STLINK_DEBUG_WRITEMEM_8BIT 0x0d
92 #define STLINK_DEBUG_CLEARFP 0x0e
93 #define STLINK_DEBUG_WRITEDEBUGREG 0x0f
94 #define STLINK_DEBUG_ENTER_SWD 0xa3
95 #define STLINK_DEBUG_ENTER_JTAG 0x00
96
97 #define STLINK_SWD_ENTER 0x30
98 #define STLINK_SWD_READCOREID 0x32
99
100 /** */
101 int stlink_usb_recv(void *handle, const uint8_t *txbuf, int txsize, uint8_t *rxbuf,
102 int rxsize)
103 {
104 struct stlink_usb_handle_s *h;
105
106 assert(handle != NULL);
107
108 h = (struct stlink_usb_handle_s *)handle;
109
110 if (jtag_libusb_bulk_write(h->fd, STLINK_TX_EP, (char *)txbuf, txsize,
111 1000) != txsize) {
112 return ERROR_FAIL;
113 }
114 if (rxsize && rxbuf) {
115 if (jtag_libusb_bulk_read(h->fd, STLINK_RX_EP, (char *)rxbuf,
116 rxsize, 1000) != rxsize) {
117 return ERROR_FAIL;
118 }
119 }
120 return ERROR_OK;
121 }
122
123 /** */
124 void stlink_usb_init_buffer(void *handle)
125 {
126 struct stlink_usb_handle_s *h;
127
128 assert(handle != NULL);
129
130 h = (struct stlink_usb_handle_s *)handle;
131
132 memset(h->txbuf, 0, STLINK_CMD_SIZE);
133 }
134
135 /** */
136 int stlink_usb_version(void *handle)
137 {
138 int res;
139 uint16_t v;
140 struct stlink_usb_handle_s *h;
141
142 assert(handle != NULL);
143
144 h = (struct stlink_usb_handle_s *)handle;
145
146 stlink_usb_init_buffer(handle);
147
148 h->txbuf[0] = STLINK_GET_VERSION;
149
150 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 6);
151
152 if (res != ERROR_OK)
153 return res;
154
155 v = (h->rxbuf[0] << 8) | h->rxbuf[1];
156
157 LOG_DEBUG("STLINK v%d", (v >> 12) & 0x0f);
158 LOG_DEBUG("JTAG v%d", (v >> 6) & 0x3f);
159 LOG_DEBUG("SWIM v%d", v & 0x3f);
160 LOG_DEBUG("VID %04X", buf_get_u32(h->rxbuf, 16, 16));
161 LOG_DEBUG("PID %04X", buf_get_u32(h->rxbuf, 32, 16));
162
163 return ERROR_OK;
164 }
165
166 /** */
167 int stlink_usb_current_mode(void *handle, uint8_t *mode)
168 {
169 int res;
170 struct stlink_usb_handle_s *h;
171
172 assert(handle != NULL);
173
174 h = (struct stlink_usb_handle_s *)handle;
175
176 stlink_usb_init_buffer(handle);
177
178 h->txbuf[0] = STLINK_GET_CURRENT_MODE;
179
180 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
181
182 if (res != ERROR_OK)
183 return res;
184
185 *mode = h->rxbuf[0];
186
187 return ERROR_OK;
188 }
189
190 /** */
191 int stlink_usb_dfu_mode_leave(void *handle)
192 {
193 int res;
194 struct stlink_usb_handle_s *h;
195
196 assert(handle != NULL);
197
198 h = (struct stlink_usb_handle_s *)handle;
199
200 stlink_usb_init_buffer(handle);
201
202 h->txbuf[0] = STLINK_DFU_COMMAND;
203 h->txbuf[1] = STLINK_DFU_EXIT;
204
205 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, 0, 0);
206
207 if (res != ERROR_OK)
208 return res;
209
210 return ERROR_OK;
211 }
212
213 /** */
214 int stlink_usb_swd_mode_enter(void *handle)
215 {
216 int res;
217 struct stlink_usb_handle_s *h;
218
219 assert(handle != NULL);
220
221 h = (struct stlink_usb_handle_s *)handle;
222
223 stlink_usb_init_buffer(handle);
224
225 h->txbuf[0] = STLINK_DEBUG_COMMAND;
226 h->txbuf[1] = STLINK_DEBUG_ENTER;
227 h->txbuf[2] = STLINK_DEBUG_ENTER_SWD;
228
229 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, 0, 0);
230 if (res != ERROR_OK)
231 return res;
232
233 return ERROR_OK;
234 }
235
236 /** */
237 int stlink_usb_debug_mode_leave(void *handle)
238 {
239 int res;
240 struct stlink_usb_handle_s *h;
241
242 assert(handle != NULL);
243
244 h = (struct stlink_usb_handle_s *)handle;
245
246 stlink_usb_init_buffer(handle);
247
248 h->txbuf[0] = STLINK_DEBUG_COMMAND;
249 h->txbuf[1] = STLINK_DEBUG_EXIT;
250
251 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, 0, 0);
252 if (res != ERROR_OK)
253 return res;
254
255 return ERROR_OK;
256 }
257
258 /** */
259 int stlink_usb_init_mode(void *handle)
260 {
261 int res;
262 uint8_t mode;
263
264 assert(handle != NULL);
265
266 res = stlink_usb_current_mode(handle, &mode);
267
268 if (res != ERROR_OK)
269 return res;
270
271 LOG_DEBUG("MODE: %02X", mode);
272
273 if (mode == STLINK_DEV_DFU_MODE) {
274 res = stlink_usb_dfu_mode_leave(handle);
275
276 if (res != ERROR_OK)
277 return res;
278 }
279
280 res = stlink_usb_current_mode(handle, &mode);
281
282 if (res != ERROR_OK)
283 return res;
284
285 LOG_DEBUG("MODE: %02X", mode);
286
287 if (mode != STLINK_DEV_DEBUG_MODE) {
288 res = stlink_usb_swd_mode_enter(handle);
289
290 if (res != ERROR_OK)
291 return res;
292 }
293
294 res = stlink_usb_current_mode(handle, &mode);
295
296 if (res != ERROR_OK)
297 return res;
298
299 LOG_DEBUG("MODE: %02X", mode);
300
301 return ERROR_OK;
302 }
303
304 /** */
305 int stlink_usb_idcode(void *handle, uint32_t *idcode)
306 {
307 int res;
308 struct stlink_usb_handle_s *h;
309
310 assert(handle != NULL);
311
312 h = (struct stlink_usb_handle_s *)handle;
313
314 stlink_usb_init_buffer(handle);
315
316 h->txbuf[0] = STLINK_DEBUG_COMMAND;
317 h->txbuf[1] = STLINK_DEBUG_READCOREID;
318
319 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 4);
320
321 if (res != ERROR_OK)
322 return res;
323
324 *idcode = le_to_h_u32(h->rxbuf);
325
326 LOG_DEBUG("IDCODE: %08X", *idcode);
327
328 return ERROR_OK;
329 }
330
331 /** */
332 enum target_state stlink_usb_state(void *handle)
333 {
334 int res;
335 struct stlink_usb_handle_s *h;
336
337 assert(handle != NULL);
338
339 h = (struct stlink_usb_handle_s *)handle;
340
341 stlink_usb_init_buffer(handle);
342
343 h->txbuf[0] = STLINK_DEBUG_COMMAND;
344 h->txbuf[1] = STLINK_DEBUG_GETSTATUS;
345
346 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
347
348 if (res != ERROR_OK)
349 return TARGET_UNKNOWN;
350
351 if (h->rxbuf[0] == STLINK_CORE_RUNNING)
352 return TARGET_RUNNING;
353 if (h->rxbuf[0] == STLINK_CORE_HALTED)
354 return TARGET_HALTED;
355
356 return TARGET_UNKNOWN;
357 }
358
359 /** */
360 int stlink_usb_reset(void *handle)
361 {
362 int res;
363 struct stlink_usb_handle_s *h;
364
365 assert(handle != NULL);
366
367 h = (struct stlink_usb_handle_s *)handle;
368
369 stlink_usb_init_buffer(handle);
370
371 h->txbuf[0] = STLINK_DEBUG_COMMAND;
372 h->txbuf[1] = STLINK_DEBUG_RESETSYS;
373
374 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
375
376 if (res != ERROR_OK)
377 return res;
378
379 LOG_DEBUG("RESET: %08X", h->rxbuf[0]);
380
381 return ERROR_OK;
382 }
383
384 /** */
385 int stlink_usb_run(void *handle)
386 {
387 int res;
388 struct stlink_usb_handle_s *h;
389
390 assert(handle != NULL);
391
392 h = (struct stlink_usb_handle_s *)handle;
393
394 stlink_usb_init_buffer(handle);
395
396 h->txbuf[0] = STLINK_DEBUG_COMMAND;
397 h->txbuf[1] = STLINK_DEBUG_RUNCORE;
398
399 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
400
401 if (res != ERROR_OK)
402 return res;
403
404 return ERROR_OK;
405 }
406
407 /** */
408 int stlink_usb_halt(void *handle)
409 {
410 int res;
411 struct stlink_usb_handle_s *h;
412
413 assert(handle != NULL);
414
415 h = (struct stlink_usb_handle_s *)handle;
416
417 stlink_usb_init_buffer(handle);
418
419 h->txbuf[0] = STLINK_DEBUG_COMMAND;
420 h->txbuf[1] = STLINK_DEBUG_FORCEDEBUG;
421
422 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
423
424 if (res != ERROR_OK)
425 return res;
426
427 return ERROR_OK;
428 }
429
430 /** */
431 int stlink_usb_step(void *handle)
432 {
433 int res;
434 struct stlink_usb_handle_s *h;
435
436 assert(handle != NULL);
437
438 h = (struct stlink_usb_handle_s *)handle;
439
440 stlink_usb_init_buffer(handle);
441
442 h->txbuf[0] = STLINK_DEBUG_COMMAND;
443 h->txbuf[1] = STLINK_DEBUG_STEPCORE;
444
445 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
446
447 if (res != ERROR_OK)
448 return res;
449
450 return ERROR_OK;
451 }
452
453 /** */
454 int stlink_usb_read_regs(void *handle)
455 {
456 int res;
457 struct stlink_usb_handle_s *h;
458
459 assert(handle != NULL);
460
461 h = (struct stlink_usb_handle_s *)handle;
462
463 stlink_usb_init_buffer(handle);
464
465 h->txbuf[0] = STLINK_DEBUG_COMMAND;
466 h->txbuf[1] = STLINK_DEBUG_READALLREGS;
467
468 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 84);
469
470 if (res != ERROR_OK)
471 return res;
472
473 return ERROR_OK;
474 }
475
476 /** */
477 int stlink_usb_read_reg(void *handle, int num, uint32_t *val)
478 {
479 int res;
480 struct stlink_usb_handle_s *h;
481
482 assert(handle != NULL);
483
484 h = (struct stlink_usb_handle_s *)handle;
485
486 stlink_usb_init_buffer(handle);
487
488 h->txbuf[0] = STLINK_DEBUG_COMMAND;
489 h->txbuf[1] = STLINK_DEBUG_READREG;
490 h->txbuf[2] = num;
491
492 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 4);
493
494 if (res != ERROR_OK)
495 return res;
496
497 *val = le_to_h_u32(h->rxbuf);
498
499 return ERROR_OK;
500 }
501
502 /** */
503 int stlink_usb_write_reg(void *handle, int num, uint32_t val)
504 {
505 int res;
506 struct stlink_usb_handle_s *h;
507
508 assert(handle != NULL);
509
510 h = (struct stlink_usb_handle_s *)handle;
511
512 stlink_usb_init_buffer(handle);
513
514 h->txbuf[0] = STLINK_DEBUG_COMMAND;
515 h->txbuf[1] = STLINK_DEBUG_WRITEREG;
516 h->txbuf[2] = num;
517 h_u32_to_le(h->txbuf + 3, val);
518
519 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
520
521 if (res != ERROR_OK)
522 return res;
523
524 return ERROR_OK;
525 }
526
527 /** */
528 int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len,
529 uint8_t *buffer)
530 {
531 int res;
532 uint16_t read_len = len;
533 struct stlink_usb_handle_s *h;
534
535 assert(handle != NULL);
536
537 h = (struct stlink_usb_handle_s *)handle;
538
539 stlink_usb_init_buffer(handle);
540
541 h->txbuf[0] = STLINK_DEBUG_COMMAND;
542 h->txbuf[1] = STLINK_DEBUG_READMEM_8BIT;
543 h_u32_to_le(h->txbuf + 2, addr);
544 h_u16_to_le(h->txbuf + 2 + 4, len);
545
546 /* we need to fix read length for single bytes */
547 if (read_len == 1)
548 read_len++;
549
550 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, read_len);
551
552 if (res != ERROR_OK)
553 return res;
554
555 memcpy(buffer, h->rxbuf, len);
556
557 return ERROR_OK;
558 }
559
560 /** */
561 int stlink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len,
562 const uint8_t *buffer)
563 {
564 int res;
565 struct stlink_usb_handle_s *h;
566
567 assert(handle != NULL);
568
569 h = (struct stlink_usb_handle_s *)handle;
570
571 stlink_usb_init_buffer(handle);
572
573 h->txbuf[0] = STLINK_DEBUG_COMMAND;
574 h->txbuf[1] = STLINK_DEBUG_WRITEMEM_8BIT;
575 h_u32_to_le(h->txbuf + 2, addr);
576 h_u16_to_le(h->txbuf + 2 + 4, len);
577
578 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, 0, 0);
579
580 if (res != ERROR_OK)
581 return res;
582
583 res = stlink_usb_recv(handle, (uint8_t *) buffer, len, 0, 0);
584
585 if (res != ERROR_OK)
586 return res;
587
588 return ERROR_OK;
589 }
590
591 /** */
592 int stlink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len,
593 uint32_t *buffer)
594 {
595 int res;
596 struct stlink_usb_handle_s *h;
597
598 assert(handle != NULL);
599
600 h = (struct stlink_usb_handle_s *)handle;
601
602 stlink_usb_init_buffer(handle);
603
604 len *= 4;
605
606 h->txbuf[0] = STLINK_DEBUG_COMMAND;
607 h->txbuf[1] = STLINK_DEBUG_READMEM_32BIT;
608 h_u32_to_le(h->txbuf + 2, addr);
609 h_u16_to_le(h->txbuf + 2 + 4, len);
610
611 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, len);
612
613 if (res != ERROR_OK)
614 return res;
615
616 memcpy(buffer, h->rxbuf, len);
617
618 return ERROR_OK;
619 }
620
621 /** */
622 int stlink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len,
623 const uint32_t *buffer)
624 {
625 int res;
626 struct stlink_usb_handle_s *h;
627
628 assert(handle != NULL);
629
630 h = (struct stlink_usb_handle_s *)handle;
631
632 stlink_usb_init_buffer(handle);
633
634 len *= 4;
635
636 h->txbuf[0] = STLINK_DEBUG_COMMAND;
637 h->txbuf[1] = STLINK_DEBUG_WRITEMEM_32BIT;
638 h_u32_to_le(h->txbuf + 2, addr);
639 h_u16_to_le(h->txbuf + 2 + 4, len);
640
641 res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, 0, 0);
642
643 if (res != ERROR_OK)
644 return res;
645
646 res = stlink_usb_recv(handle, (uint8_t *) buffer, len, 0, 0);
647
648 if (res != ERROR_OK)
649 return res;
650
651 return ERROR_OK;
652 }
653
654 /** */
655 int stlink_usb_open(struct stlink_interface_param_s *param, void **fd)
656 {
657 struct stlink_usb_handle_s *h;
658
659 LOG_DEBUG("stlink_usb_open");
660
661 h = malloc(sizeof(struct stlink_usb_handle_s));
662
663 if (h == 0) {
664 LOG_DEBUG("stlink_open_usb: malloc failed");
665 return ERROR_FAIL;
666 }
667
668 const uint16_t vids[] = { param->vid, 0 };
669 const uint16_t pids[] = { param->pid, 0 };
670
671 LOG_DEBUG("stlink_open_usb: vid: %04x pid: %04x", param->vid,
672 param->pid);
673
674 if (jtag_libusb_open(vids, pids, &h->fd) != ERROR_OK) {
675 LOG_ERROR("stlink_open_usb: open failed");
676 return ERROR_FAIL;
677 }
678
679 jtag_libusb_set_configuration(h->fd, 0);
680
681 if (jtag_libusb_claim_interface(h->fd, 0) != ERROR_OK) {
682 LOG_DEBUG("stlink_open_usb: claim failed");
683 return ERROR_FAIL;
684 }
685
686 stlink_usb_init_mode(h);
687
688 stlink_usb_version(h);
689
690 *fd = h;
691
692 return ERROR_OK;
693 }
694
695 /** */
696 struct stlink_layout_api_s stlink_layout_api = {
697 /** */
698 .open = stlink_usb_open,
699 /** */
700 .idcode = stlink_usb_idcode,
701 /** */
702 .state = stlink_usb_state,
703 /** */
704 .reset = stlink_usb_reset,
705 /** */
706 .run = stlink_usb_run,
707 /** */
708 .halt = stlink_usb_halt,
709 /** */
710 .step = stlink_usb_step,
711 /** */
712 .read_regs = stlink_usb_read_regs,
713 /** */
714 .read_reg = stlink_usb_read_reg,
715 /** */
716 .write_reg = stlink_usb_write_reg,
717 /** */
718 .read_mem8 = stlink_usb_read_mem8,
719 /** */
720 .write_mem8 = stlink_usb_write_mem8,
721 /** */
722 .read_mem32 = stlink_usb_read_mem32,
723 /** */
724 .write_mem32 = stlink_usb_write_mem32,
725 };

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)