2 * OpenOCD's SWD Transport Drivers for LibSWD, body file.
4 * Copyright (C) 2011-2012 Tomasz Boleslaw CEDRO
5 * cederom@tlen.pl, http://www.tomek.cedro.info
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.*
31 * Written by Tomasz Boleslaw CEDRO <cederom@tlen.pl>, 2011-2012;
36 * \file transport_swd_libswd.c OpenOCD's SWD Transport Drivers for LibSWD,
39 * This file implements SWD transport in OpenOCD using external LibSWD library.
40 * LibSWD makes it possible to generate and anlyze SWD bistream, which can be
41 * transported by any generic interface that provides "transfer" and "bitbang"
42 * functions (see ft2232 as example).
50 #include <interface/interface.h>
51 #include <transport/transport.h>
52 #include <transport/swd.h>
53 #include <transport/swd_libswd.h>
54 #include <target/arm.h>
55 #include <target/arm_adi_v5.h>
56 #include <helper/log.h>
58 /** OpenOCD as for now use global pointer to driver structure. */
59 extern struct jtag_interface
*jtag_interface
;
61 /******************************************************************************
62 * @{ oocd_transport_swd_libswd_arm_adi_v5
63 * SWD Transport definitions that use LibSWD for underlying bus operations.
66 int oocd_transport_swd_libswd_queue_idcode_read(struct adiv5_dap
*dap
, uint8_t *ack
, uint32_t *data
)
69 retval
= libswd_dp_read_idcode(dap
->ctx
, LIBSWD_OPERATION_EXECUTE
, &pdata
);
71 LOG_ERROR("oocd_transport_swd_libswd_queue_idcode_read(*dap=@%p, ack=@%p, data=@%p) error (%s)", (void *)dap
,
72 (void *)ack
, (void *)data
, libswd_error_string(retval
));
76 *data
= (uint32_t)*pdata
;
80 int oocd_transport_swd_libswd_queue_dp_read(struct adiv5_dap
*dap
, unsigned reg
, uint32_t *data
)
83 retval
= libswd_dp_read((libswd_ctx_t
*)dap
->ctx
, LIBSWD_OPERATION_EXECUTE
, (char)reg
, &pdata
);
85 LOG_ERROR("oocd_transport_swd_libswd_queue_dp_read(dap=@%p, reg=0x%X, data=@%p) error (%s) ", (void *)dap
, reg
,
86 (void *)data
, libswd_error_string(retval
));
90 *data
= (uint32_t)*pdata
;
94 int oocd_transport_swd_libswd_queue_dp_write(struct adiv5_dap
*dap
, unsigned reg
, uint32_t data
)
97 retval
= libswd_dp_write((libswd_ctx_t
*)dap
->ctx
, LIBSWD_OPERATION_EXECUTE
, (char)reg
, (int *)&data
);
99 LOG_ERROR("oocd_transport_swd_libswd_queue_dp_write(dap=@%p, reg=0x%X, data=0x%X) error (%s)", (void *)dap
, reg
,
100 data
, libswd_error_string(retval
));
106 int oocd_transport_swd_libswd_queue_ap_read(struct adiv5_dap
*dap
, unsigned reg
, uint32_t *data
)
109 retval
= libswd_ap_read((libswd_ctx_t
*)dap
->ctx
, LIBSWD_OPERATION_EXECUTE
, (char)reg
, &pdata
);
111 LOG_ERROR("oocd_transport_swd_libswd_queue_ap_read(dap=@%p, reg=0x%X, data=@%p) error (%s)", (void *)dap
, reg
,
112 (void *)data
, libswd_error_string(retval
));
116 *data
= (uint32_t)*pdata
;
120 int oocd_transport_swd_libswd_queue_ap_write(struct adiv5_dap
*dap
, unsigned reg
, uint32_t data
)
123 retval
= libswd_ap_write((libswd_ctx_t
*)dap
->ctx
, LIBSWD_OPERATION_EXECUTE
, (char) reg
, (int *) &data
);
125 LOG_ERROR("oocd_transport_swd_libswd_queue_ap_write(dap=@%p, reg=0x%X, data=0x%X) error (%s)", (void *)dap
, reg
,
126 data
, libswd_error_string(retval
));
132 int oocd_transport_swd_libswd_queue_ap_abort(struct adiv5_dap
*dap
, uint8_t *ack
)
135 int abort_flags
= LIBSWD_DP_ABORT_ORUNERRCLR
| LIBSWD_DP_ABORT_WDERRCLR
| LIBSWD_DP_ABORT_STKERRCLR \
136 | LIBSWD_DP_ABORT_STKCMPCLR
| LIBSWD_DP_ABORT_DAPABORT
;
137 retval
= libswd_dp_write((libswd_ctx_t
*)dap
->ctx
, LIBSWD_OPERATION_ENQUEUE
, LIBSWD_DP_ABORT_ADDR
, &abort_flags
);
139 LOG_ERROR("oocd_transport_swd_libswd_queue_ap_abort(dap=@%p, ack=@%p) error (%s)", (void *)dap
, (void *)ack
,
140 libswd_error_string(retval
));
146 /** This function flushes all enqueued operations into a hardware interface.
147 * libswd_cmdq_flush() is called, then libswd_drv_transmit() which is using
148 * application specific drivers that are linked into target application binary.
149 * Because in SWD each operation is confirmed by Target with ACK answer
150 * we need to react on errors here. OpenOCD was constructed for use with JTAG
151 * and most functions use series of enqueue functions that are later flushed
152 * into a hardware interface with high level dap_run() / transport_run(), so
153 * this is the only sensible place to place error handling (otherwise code
154 * would need to be changed in lots of places). Caller function simply want
155 * to know if transfer succeeded, so we can perform handling such as retry
156 * on ACK=WAIT unless transfer fail with ACK={FAIL, UNKNOWN}.
159 int oocd_transport_swd_libswd_run(struct adiv5_dap
*dap
)
162 libswd_ctx_t
*libswdctx
= (libswd_ctx_t
*)dap
->ctx
;
163 retval
= libswd_cmdq_flush(libswdctx
, &libswdctx
->cmdq
, LIBSWD_OPERATION_EXECUTE
);
165 LOG_ERROR("oocd_transport_swd_libswd_run(dap=@%p) error (%s)", (void *) dap
, libswd_error_string(retval
));
173 * Select SWD transport on interface pointed by global *jtag_interface structure.
174 * Select is assumed to be called before transport init. It prepares everything,
175 * including context memory and command set for higher layers, but not hardware
176 * and does not interrogate target device (with IDCODE read that is done by
177 * transport init call). This function does not touch the hardware because
178 * hardware use signals that are not yet read from config file at this point!
180 int oocd_transport_swd_libswd_select(struct command_context
*ctx
)
184 retval
= oocd_transport_swd_libswd_register_commands(ctx
);
185 if (retval
!= ERROR_OK
) {
186 LOG_ERROR("Unable to register LibSWD commands for SWD Transport!");
193 * Transport initialization routine is responsible for target initialization
194 * using previously selected transport.
195 * It talks to the hardware using functions selected by transport_select().
197 * \param *ctx is the openocd command_context.
198 * \return ERROR_OK on success, ERROR_FAIL otherwise.
200 int oocd_transport_swd_libswd_init(struct command_context
*ctx
)
202 LOG_DEBUG("entering function...");
205 struct target
*target
= get_current_target(ctx
);
206 struct arm
*arm
= target_to_arm(target
);
207 struct adiv5_dap
*dap
= arm
->dap
;
209 dap
->ops
= &oocd_dap_ops_swd_libswd
;
211 /* Create LIBSWD_CTX if nesessary */
213 /** Transport was not yet initialized. */
214 dap
->ctx
= libswd_init();
215 if (dap
->ctx
== NULL
) {
216 LOG_ERROR("Cannot initialize SWD context!");
219 LOG_INFO("New SWD context initialized at 0x%p", (void *)dap
->ctx
);
220 /* Now inherit the log level from OpenOCD settings. */
221 retval
= libswd_log_level_inherit((libswd_ctx_t
*)dap
->ctx
, debug_level
);
223 LOG_ERROR("Unable to set log level: %s", libswd_error_string(retval
));
227 LOG_INFO("Working on existing transport context at 0x%p...", (void *)dap
->ctx
);
229 /** We enable automatic error handling on error */
230 libswd_ctx_t
*libswdctx
= (libswd_ctx_t
*)dap
->ctx
;
231 libswdctx
->config
.autofixerrors
= 0;
234 * Initialize driver and detect target working with selected transport.
235 * Because we can work on existing context there is no need to destroy it,
236 * as it can be used on next try.
238 retval
= libswd_dap_detect((libswd_ctx_t
*)dap
->ctx
, LIBSWD_OPERATION_EXECUTE
, &idcode
);
240 LOG_ERROR("libswd_dap_detect() error %d (%s)", retval
, libswd_error_string(retval
));
244 LOG_INFO("SWD transport initialization complete. Found IDCODE=0x%08X.", *idcode
);
249 * SWD Tranport based DAP Operations using LibSWD for underlying operations.
251 const struct dap_ops oocd_dap_ops_swd_libswd
= {
253 .select
= oocd_transport_swd_libswd_select
,
254 .init
= oocd_transport_swd_libswd_init
,
255 .queue_idcode_read
= oocd_transport_swd_libswd_queue_idcode_read
,
256 .queue_dp_read
= oocd_transport_swd_libswd_queue_dp_read
,
257 .queue_dp_write
= oocd_transport_swd_libswd_queue_dp_write
,
258 .queue_ap_read
= oocd_transport_swd_libswd_queue_ap_read
,
259 .queue_ap_write
= oocd_transport_swd_libswd_queue_ap_write
,
260 .queue_ap_abort
= oocd_transport_swd_libswd_queue_ap_abort
,
261 .run
= oocd_transport_swd_libswd_run
,
265 * Interface features adds SWD support using LibSWD as middleware.
267 oocd_feature_t oocd_transport_swd_libswd_arm_dap_feature
= {
268 .name
= OOCD_FEATURE_ARM_DAP
,
269 .description
= "ARM DAP SWD transport features based on LibSWD.",
270 .body
= (void *)&oocd_dap_ops_swd_libswd
,
276 /******************************************************************************
277 * @{ oocd_transport_swd_libswd_drv
278 * Driver bridge between OpenOCD and LibSWD.
282 * Driver code to write 8-bit data (char type).
283 * MOSI (Master Output Slave Input) is a SWD Write Operation.
285 * \param *libswdctx swd context to work on.
286 * \param *cmd point to the actual command being sent.
287 * \param *data points to the char data.
288 * \bits tells how many bits to send (at most 8).
289 * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first.
290 * \return data count transferred, or negative LIBSWD_ERROR code on failure.
292 int libswd_drv_mosi_8(libswd_ctx_t
*libswdctx
, libswd_cmd_t
*cmd
, char *data
, int bits
, int nLSBfirst
)
294 LOG_DEBUG("OpenOCD's libswd_drv_mosi_8(libswdctx=@%p, cmd=@%p, data=0x%02X, bits=%d, nLSBfirst=0x%02X)",
295 (void *)libswdctx
, (void *)cmd
, *data
, bits
, nLSBfirst
);
297 return LIBSWD_ERROR_NULLPOINTER
;
298 if (bits
< 0 && bits
> 8)
299 return LIBSWD_ERROR_PARAM
;
300 if (nLSBfirst
!= 0 && nLSBfirst
!= 1)
301 return LIBSWD_ERROR_PARAM
;
303 static unsigned int i
;
304 static signed int res
;
305 static char misodata
[8], mosidata
[8];
307 /* Split output data into char array. */
308 for (i
= 0; i
< 8; i
++)
309 mosidata
[(nLSBfirst
== LIBSWD_DIR_LSBFIRST
) ? i
: (bits
- 1 - i
)] = ((1 << i
) & (*data
)) ? 1 : 0;
310 /* Then send that array into interface hardware. */
311 res
= jtag_interface
->transfer(NULL
, bits
, mosidata
, misodata
, 0);
313 return LIBSWD_ERROR_DRIVER
;
319 * Driver code to write 32-bit data (int type).
320 * MOSI (Master Output Slave Input) is a SWD Write Operation.
322 * \param *libswdctx swd context to work on.
323 * \param *cmd point to the actual command being sent.
324 * \param *data points to the char buffer array.
325 * \bits tells how many bits to send (at most 32).
326 * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first.
327 * \return data count transferred, or negative LIBSWD_ERROR code on failure.
329 int libswd_drv_mosi_32(libswd_ctx_t
*libswdctx
, libswd_cmd_t
*cmd
, int *data
, int bits
, int nLSBfirst
)
331 LOG_DEBUG("OpenOCD's libswd_drv_mosi_32(libswdctx=@%p, cmd=@%p, data=0x%08X, bits=%d, nLSBfirst=0x%02X)",
332 (void *)libswdctx
, (void *)cmd
, *data
, bits
, nLSBfirst
);
334 return LIBSWD_ERROR_NULLPOINTER
;
335 if (bits
< 0 && bits
> 8)
336 return LIBSWD_ERROR_PARAM
;
337 if (nLSBfirst
!= 0 && nLSBfirst
!= 1)
338 return LIBSWD_ERROR_PARAM
;
340 static unsigned int i
;
341 static signed int res
;
342 static char misodata
[32], mosidata
[32];
344 /* UrJTAG drivers shift data LSB-First. */
345 for (i
= 0; i
< 32; i
++)
346 mosidata
[(nLSBfirst
== LIBSWD_DIR_LSBFIRST
) ? i
: (bits
- 1 - i
)] = ((1 << i
) & (*data
)) ? 1 : 0;
347 res
= jtag_interface
->transfer(NULL
, bits
, mosidata
, misodata
, 0);
349 return LIBSWD_ERROR_DRIVER
;
354 * Use UrJTAG's driver to read 8-bit data (char type).
355 * MISO (Master Input Slave Output) is a SWD Read Operation.
357 * \param *libswdctx swd context to work on.
358 * \param *cmd point to the actual command being sent.
359 * \param *data points to the char buffer array.
360 * \bits tells how many bits to send (at most 8).
361 * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first.
362 * \return data count transferred, or negative LIBSWD_ERROR code on failure.
364 int libswd_drv_miso_8(libswd_ctx_t
*libswdctx
, libswd_cmd_t
*cmd
, char *data
, int bits
, int nLSBfirst
)
367 return LIBSWD_ERROR_NULLPOINTER
;
368 if (bits
< 0 && bits
> 8)
369 return LIBSWD_ERROR_PARAM
;
370 if (nLSBfirst
!= 0 && nLSBfirst
!= 1)
371 return LIBSWD_ERROR_PARAM
;
374 static signed int res
;
375 static char misodata
[8], mosidata
[8];
377 res
= jtag_interface
->transfer(NULL
, bits
, mosidata
, misodata
, LIBSWD_DIR_LSBFIRST
);
379 return LIBSWD_ERROR_DRIVER
;
380 /* Now we need to reconstruct the data byte from shifted in LSBfirst byte array. */
382 for (i
= 0; i
< bits
; i
++)
383 *data
|= misodata
[(nLSBfirst
== LIBSWD_DIR_LSBFIRST
) ? i
: (bits
- 1 - i
)] ? (1 << i
) : 0;
384 LOG_DEBUG("OpenOCD's libswd_drv_miso_8(libswdctx=@%p, cmd=@%p, data=@%p, bits=%d, nLSBfirst=0x%02X) reads: 0x%02X",
385 (void *)libswdctx
, (void *)cmd
, (void *)data
, bits
, nLSBfirst
, *data
);
390 * Driver code to read 32-bit data (int type).
391 * MISO (Master Input Slave Output) is a SWD Read Operation.
393 * \param *libswdctx swd context to work on.
394 * \param *cmd point to the actual command being sent.
395 * \param *data points to the char buffer array.
396 * \bits tells how many bits to send (at most 32).
397 * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first.
398 * \return data count transferred, or negative LIBSWD_ERROR code on failure.
400 int libswd_drv_miso_32(libswd_ctx_t
*libswdctx
, libswd_cmd_t
*cmd
, int *data
, int bits
, int nLSBfirst
)
403 return LIBSWD_ERROR_NULLPOINTER
;
404 if (bits
< 0 && bits
> 8)
405 return LIBSWD_ERROR_PARAM
;
406 if (nLSBfirst
!= 0 && nLSBfirst
!= 1)
407 return LIBSWD_ERROR_PARAM
;
410 static signed int res
;
411 static char misodata
[32], mosidata
[32];
413 res
= jtag_interface
->transfer(NULL
, bits
, mosidata
, misodata
, LIBSWD_DIR_LSBFIRST
);
415 return LIBSWD_ERROR_DRIVER
;
416 /* Now we need to reconstruct the data byte from shifted in LSBfirst byte array. */
418 for (i
= 0; i
< bits
; i
++)
419 *data
|= (misodata
[(nLSBfirst
== LIBSWD_DIR_LSBFIRST
) ? i
: (bits
- 1 - i
)] ? (1 << i
) : 0);
420 LOG_DEBUG("OpenOCD's libswd_drv_miso_32(libswdctx=@%p, cmd=@%p, data=@%p, bits=%d, nLSBfirst=0x%02X) reads: 0x%08X",
421 (void *)libswdctx
, (void *)cmd
, (void *)data
, bits
, nLSBfirst
, *data
);
422 LOG_DEBUG("OpenOCD's libswd_drv_miso_32() reads: 0x%08X\n", *data
);
427 * This function sets interface buffers to MOSI direction.
428 * MOSI (Master Output Slave Input) is a SWD Write operation.
429 * OpenOCD use global "struct jtag_interface" pointer as interface driver.
430 * OpenOCD driver must support "RnW" signal to drive output buffers for TRN.
432 * \param *libswdctx is the swd context to work on.
433 * \param bits specify how many clock cycles must be used for TRN.
434 * \return number of bits transmitted or negative LIBSWD_ERROR code on failure.
436 int libswd_drv_mosi_trn(libswd_ctx_t
*libswdctx
, int bits
)
438 LOG_DEBUG("OpenOCD's libswd_drv_mosi_trn(libswdctx=@%p, bits=%d)\n", (void *)libswdctx
, bits
);
439 if (bits
< LIBSWD_TURNROUND_MIN_VAL
&& bits
> LIBSWD_TURNROUND_MAX_VAL
)
440 return LIBSWD_ERROR_TURNAROUND
;
443 static char buf
[LIBSWD_TURNROUND_MAX_VAL
];
444 /* Use driver method to set low (write) signal named RnW. */
445 res
= jtag_interface
->bitbang(NULL
, "RnW", 0, &val
);
447 return LIBSWD_ERROR_DRIVER
;
449 /* Clock specified number of bits for proper TRN transaction. */
450 res
= jtag_interface
->transfer(NULL
, bits
, buf
, buf
, 0);
452 return LIBSWD_ERROR_DRIVER
;
458 * This function sets interface buffers to MISO direction.
459 * MISO (Master Input Slave Output) is a SWD Read operation.
460 * OpenOCD use global "struct jtag_interface" pointer as interface driver.
461 * OpenOCD driver must support "RnW" signal to drive output buffers for TRN.
463 * \param *libswdctx is the swd context to work on.
464 * \param bits specify how many clock cycles must be used for TRN.
465 * \return number of bits transmitted or negative LIBSWD_ERROR code on failure.
467 int libswd_drv_miso_trn(libswd_ctx_t
*libswdctx
, int bits
)
469 LOG_DEBUG("OpenOCD's libswd_drv_miso_trn(libswdctx=@%p, bits=%d)\n", (void *)libswdctx
, bits
);
470 if (bits
< LIBSWD_TURNROUND_MIN_VAL
&& bits
> LIBSWD_TURNROUND_MAX_VAL
)
471 return LIBSWD_ERROR_TURNAROUND
;
473 static int res
, val
= 1;
474 static char buf
[LIBSWD_TURNROUND_MAX_VAL
];
476 /* Use driver method to set high (read) signal named RnW. */
477 res
= jtag_interface
->bitbang(NULL
, "RnW", 0xFFFFFFFF, &val
);
479 return LIBSWD_ERROR_DRIVER
;
481 /* Clock specified number of bits for proper TRN transaction. */
482 res
= jtag_interface
->transfer(NULL
, bits
, buf
, buf
, 0);
484 return LIBSWD_ERROR_DRIVER
;
490 * Set SWD debug level according to OpenOCD settings.
492 * \param *libswdctx is the context to work on.
493 * \param loglevel is the OpenOCD numerical value of actual loglevel to force
494 * on LibSWD, or -1 to inherit from actual global settings of OpenOCD.
495 * \return LIBSWD_OK on success, negative LIBSWD_ERROR code on failure.
497 int libswd_log_level_inherit(libswd_ctx_t
*libswdctx
, int loglevel
)
499 LOG_DEBUG("OpenOCD's libswd_log_level_inherit(libswdctx=@%p, loglevel=%d)\n", (void *)libswdctx
, loglevel
);
500 if (libswdctx
== NULL
) {
501 LOG_WARNING("libswd_log_level_inherit(): SWD Context not (yet) initialized...\n");
505 libswd_loglevel_t new_swdlevel
;
506 switch ((loglevel
== -1) ? debug_level
: loglevel
) {
508 new_swdlevel
= LIBSWD_LOGLEVEL_PAYLOAD
;
511 new_swdlevel
= LIBSWD_LOGLEVEL_INFO
;
513 case LOG_LVL_WARNING
:
514 new_swdlevel
= LIBSWD_LOGLEVEL_WARNING
;
517 new_swdlevel
= LIBSWD_LOGLEVEL_ERROR
;
521 new_swdlevel
= LIBSWD_LOGLEVEL_NORMAL
;
524 new_swdlevel
= LIBSWD_LOGLEVEL_SILENT
;
527 new_swdlevel
= LIBSWD_LOGLEVEL_NORMAL
;
530 int res
= libswd_log_level_set(libswdctx
, new_swdlevel
);
532 LOG_ERROR("libswd_log_level_set() failed (%s)\n", libswd_error_string(res
));
538 /** We will use OpenOCD's logging mechanisms to show LibSWD messages.
539 * SWD can have different loglevel set than the OpenOCD itself, so we need to
540 * log all messages at OpenOCD level that will not block swd messages.
541 * It is also possible to 'inherit' loglevel to swd from openocd.
543 * \param *libswdctx is the pointer to the libswd context to work with.
544 * \param loglevel is the desired log level to show message at.
545 * \param *msg, ... is the printf like message to be logged.
546 * \return LIBSWD_OK on success, or error code otherwise.
548 int libswd_log(libswd_ctx_t
*libswdctx
, libswd_loglevel_t loglevel
, char *msg
, ...)
550 if (libswdctx
== NULL
)
551 return LIBSWD_ERROR_NULLCONTEXT
;
552 if (loglevel
> LIBSWD_LOGLEVEL_MAX
)
553 return LIBSWD_ERROR_PARAM
;
555 if (loglevel
> libswdctx
->config
.loglevel
)
559 /* Calling OpenOCD log functions here will cause program crash (va recurrent). */
565 /******************************************************************************
566 * @{ oocd_transport_swd_libswd_tcl
567 * TCL interface for LibSWD based SWD Transport in OpenOCD.
570 COMMAND_HANDLER(handle_oocd_transport_swd_libswd_loglevel
)
573 struct target
*target
= get_current_target(CMD_CTX
);
574 struct arm
*arm
= target_to_arm(target
);
575 libswd_ctx_t
*swdctx
= (libswd_ctx_t
*)arm
->dap
->ctx
;
579 LOG_USER("Current SWD LogLevel[%d..%d] is: %d (%s)", LIBSWD_LOGLEVEL_MIN
, LIBSWD_LOGLEVEL_MAX
,
580 swdctx
->config
.loglevel
, libswd_log_level_string(swdctx
->config
.loglevel
));
583 /* We want to allow inherit current OpenOCD's debuglevel. */
584 if (strncasecmp(CMD_ARGV
[0], "inherit", 7) == 0) {
585 loglevel
= libswd_log_level_inherit(swdctx
, debug_level
);
587 LOG_ERROR("LogLevel inherit failed!");
590 LOG_USER("Using OpenOCD settings, SWD LogLevel[%d..%d] set to: %d (%s)", LIBSWD_LOGLEVEL_MIN
,
591 LIBSWD_LOGLEVEL_MAX
, loglevel
, libswd_log_level_string(loglevel
));
595 /* Or we want to set log level for SWD transport by hand. */
596 loglevel
= atoi(CMD_ARGV
[0]);
597 if (loglevel
< LIBSWD_LOGLEVEL_MIN
|| loglevel
> LIBSWD_LOGLEVEL_MAX
) {
598 LOG_ERROR("Bad SWD LogLevel value!");
601 LOG_USER("Setting SWD LogLevel[%d..%d] to: %d (%s)", LIBSWD_LOGLEVEL_MIN
, LIBSWD_LOGLEVEL_MAX
, loglevel
,
602 libswd_log_level_string(loglevel
));
603 if (libswd_log_level_set(swdctx
, loglevel
) < 0)
608 LOG_INFO("Available values:");
609 for (int i
= 0; i
<= LIBSWD_LOGLEVEL_MAX
; i
++)
610 LOG_INFO(" %d (%s)", i
, libswd_log_level_string(i
));
615 struct command_registration oocd_transport_swd_libswd_subcommand_handlers
[] = {
618 .handler
= handle_oocd_transport_swd_libswd_loglevel
,
620 .help
= "set/inherit/get loglevel for LibSWD-based SWD transport.",
623 COMMAND_REGISTRATION_DONE
627 struct command_registration oocd_transport_swd_libswd_command_handlers
[] = {
631 .help
= "LibSWD-based SWD transport command group",
632 .chain
= oocd_transport_swd_libswd_subcommand_handlers
,
634 COMMAND_REGISTRATION_DONE
637 int oocd_transport_swd_libswd_register_commands(struct command_context
*cmd_ctx
)
639 return register_commands(cmd_ctx
, NULL
, oocd_transport_swd_libswd_command_handlers
);