2 * Serial Wire Debug Open Library.
5 * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (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>, 2010-2013;
35 /** \file libswd_log.c */
39 /*******************************************************************************
40 * \defgroup libswd_log Miscelanous logging functionalities.
42 ******************************************************************************/
44 /** Logging functionality can be external or internal, by default external
45 * function can be defined to use target program logging mechanism.
46 * To use internal logging mechanism simply wrap libswd_log_internal() around
47 * this function in application specific driver bridge file,
48 * see liblibswd_externs.c for examples. When you want to use variable argument
49 * (printf style) invocation you can use libswd_log_internal_va() as vprintf().
51 extern int libswd_log(libswd_ctx_t
*libswdctx
, libswd_loglevel_t loglevel
, char *msg
, ...);
53 /** Put a message into swd context log at specified verbosity level.
54 * If specified message's log level is lower than actual context configuration,
55 * message will be omitted. Verbosity level increases from 0 (silent) to 6 (bitstream).
56 * This function does not put '\n' at the end of line so you need to put them by hand.
57 * \param *libswdctx swd context.
58 * \param loglevel at which to put selected message.
59 * \param *msg message body with variable arguments as in "printf".
60 * \return number of characters written or error code on failure.
62 int libswd_log_internal(libswd_ctx_t
*libswdctx
, libswd_loglevel_t loglevel
, char *msg
, ...){
63 if (loglevel
<LIBSWD_LOGLEVEL_MIN
|| loglevel
>LIBSWD_LOGLEVEL_MAX
)
64 return LIBSWD_ERROR_LOGLEVEL
;
65 if (loglevel
> libswdctx
->config
.loglevel
) return LIBSWD_OK
;
74 /** Put a fmt+va_list message into swd context log at specified verbosity level.
75 * It works just as libswd_log_internal() but is intended for use instead
76 * vprintf() between va_start() and va_end()...
77 * \param *libswdctx swd context.
78 * \param loglevel at which to put selected message.
79 * \param *msg message body with variable arguments as in "printf".
80 * \return number of characters written or error code on failure.
82 int libswd_log_internal_va(libswd_ctx_t
*libswdctx
, libswd_loglevel_t loglevel
, char *fmt
, va_list ap
){
83 if (loglevel
<LIBSWD_LOGLEVEL_MIN
|| loglevel
>LIBSWD_LOGLEVEL_MAX
)
84 return LIBSWD_ERROR_LOGLEVEL
;
85 if (loglevel
> libswdctx
->config
.loglevel
) return LIBSWD_OK
;
91 /** Change log level to increase or decrease verbosity level.
92 * \param *libswdctx swd context.
93 * \param loglevel is the target verbosity level to be set.
94 * \return LIBSWD_OK on success or error code.
96 int libswd_log_level_set(libswd_ctx_t
*libswdctx
, libswd_loglevel_t loglevel
){
97 if (libswdctx
==NULL
) return LIBSWD_ERROR_NULLCONTEXT
;
98 if (loglevel
<LIBSWD_LOGLEVEL_MIN
|| loglevel
>LIBSWD_LOGLEVEL_MAX
)
99 return LIBSWD_ERROR_LOGLEVEL
;
101 libswdctx
->config
.loglevel
=loglevel
;
102 libswd_log(libswdctx
, LIBSWD_LOGLEVEL_DEBUG
, "LIBSWD_D: libswd_log_level_set(libswdctx=0x%p, loglevel[%d..%d]=%d/%s)\n", (void*)libswdctx
, LIBSWD_LOGLEVEL_MIN
, LIBSWD_LOGLEVEL_MAX
, loglevel
, libswd_log_level_string(loglevel
));
106 /** Return integer log level value.
107 * \param *libswdctx swd context.
108 * \return integer log level value or LIBSWD_ERROR code on failure.
110 int libswd_log_level_get(libswd_ctx_t
*libswdctx
){
111 if (libswdctx
==NULL
) return LIBSWD_ERROR_NULLCONTEXT
;
112 return libswdctx
->config
.loglevel
;
115 /** Helper function that returns loglevel name string for logging purposes.
116 * \param loglevel is the libswd_loglevel_t code to produce a string.
117 * \return char* loglevel name sring array.
119 const char *libswd_log_level_string(libswd_loglevel_t loglevel
){
121 case LIBSWD_LOGLEVEL_SILENT
: return "LIBSWD_LOGLEVEL_SILENT";
122 case LIBSWD_LOGLEVEL_ERROR
: return "LIBSWD_LOGLEVEL_ERROR";
123 case LIBSWD_LOGLEVEL_WARNING
: return "LIBSWD_LOGLEVEL_WARNING";
124 case LIBSWD_LOGLEVEL_NORMAL
: return "LIBSWD_LOGLEVEL_NORMAL";
125 case LIBSWD_LOGLEVEL_INFO
: return "LIBSWD_LOGLEVEL_INFO";
126 case LIBSWD_LOGLEVEL_DEBUG
: return "LIBSWD_LOGLEVEL_DEBUG";
127 case LIBSWD_LOGLEVEL_PAYLOAD
: return "LIBSWD_LOGLEVEL_PAYLOAD";
129 return "UNKNOWN_LOGLEVEL";
132 /** Helper function to produce operation name string for logging purposes.
133 * \param operation is the libswd_operation_t code to return as string.
134 * \return char* array with operation name string.
136 const char *libswd_operation_string(libswd_operation_t operation
){
138 case LIBSWD_OPERATION_ENQUEUE
: return "LIBSWD_OPERATION_ENQUEUE";
139 case LIBSWD_OPERATION_EXECUTE
: return "LIBSWD_OPERATION_EXECUTE";
140 case LIBSWD_OPERATION_TRANSMIT_HEAD
: return "LIBSWD_OPERATION_TRANSMIT_HEAD";
141 case LIBSWD_OPERATION_TRANSMIT_TAIL
: return "LIBSWD_OPERATION_TRANSMIT_TAIL";
142 case LIBSWD_OPERATION_TRANSMIT_ALL
: return "LIBSWD_OPERATION_TRANSMIT_ALL";
143 case LIBSWD_OPERATION_TRANSMIT_ONE
: return "LIBSWD_OPERATION_TRANSMIT_ONE";
144 case LIBSWD_OPERATION_TRANSMIT_LAST
: return "LIBSWD_OPERATION_TRANSMIT_LAST";
146 return "UNKNOWN_LIBSWD_OPERATION";
149 /** Helper function that can print name of the request fields.
150 * DP SELECT APBANKSEL fields are also taken into account here for APACC.
151 * \param libswdctx points to the swd context and its necessary to know
152 DP SELECT register value as it determines CTRL/STAT or WCR access.
153 * \param RnW is the read/write bit of the request packet.
154 * \param addr is the address of the register.
155 * \return char* array with the register name string.
157 const char *libswd_request_string(libswd_ctx_t
*libswdctx
, char request
){
158 static char string
[100], tmp
[8]; string
[0]=0;
159 int apndp
=request
&LIBSWD_REQUEST_APnDP
;
161 addr
|=((request
&LIBSWD_REQUEST_A3
)?1<<3:0);
162 addr
|=((request
&LIBSWD_REQUEST_A2
)?1<<2:0);
163 if (apndp
) addr
|=(libswdctx
->log
.dp
.select
&LIBSWD_DP_SELECT_APBANKSEL
);
164 int rnw
=request
&LIBSWD_REQUEST_RnW
;
165 int parity
=request
&LIBSWD_REQUEST_PARITY
;
167 strcat(string
, apndp
?"AccessPort ":"DebugPort ");
168 strcat(string
, rnw
?"Read ":"Write ");
169 strcat(string
, "Addr="); sprintf(tmp
, "0x%02X", addr
); strcat(string
, tmp
);
172 // APnDP=1 so we print out the AHB-AP registers
173 addr
|=libswdctx
->log
.dp
.select
&LIBSWD_DP_SELECT_APBANKSEL
;
175 case 0x00: strcat(string
, "(R/W: Control/Status Word, CSW (reset value: 0x43800042)) "); break;
176 case 0x04: strcat(string
, "(R/W: Transfer Address, TAR (reset value: 0x00000000)) "); break;
177 case 0x08: strcat(string
, "(Reserved SBZ) "); break;
178 case 0x0c: strcat(string
, "(R/W, Data Read/Write, DRW) "); break;
179 case 0x10: strcat(string
, "(R/W, Banked Data 0, BD0) "); break;
180 case 0x14: strcat(string
, "(R/W, Banked Data 1, BD1) "); break;
181 case 0x18: strcat(string
, "(R/W, Banked Data 2, BD2 )"); break;
182 case 0x1c: strcat(string
, "(R/W, Banked Data 3, BD3) "); break;
183 case 0xf8: strcat(string
, "(RO, Debug ROM table (reset value: 0xE00FF000)) "); break;
184 case 0xfc: strcat(string
, "(RO, Identification Register, IDR (reset value: 0x24770001)) "); break;
185 default: strcat(string
, "(UNKNOWN) ");
188 // APnDP=0 so we print out the SW-DP registers
191 case LIBSWD_DP_IDCODE_ADDR
: strcat(string
, "(IDCODE)"); break;
192 case LIBSWD_DP_CTRLSTAT_ADDR
: strcat(string
, (libswdctx
->log
.dp
.select
&1<<LIBSWD_DP_SELECT_CTRLSEL_BITNUM
)?"(CTRL/STAT or [WCR])":"([CTRL/STAT] or WCR)"); break;
193 case LIBSWD_DP_RESEND_ADDR
: strcat(string
,"(RESEND) "); break;
194 case LIBSWD_DP_RDBUFF_ADDR
: strcat(string
, "(RDBUFF) "); break;
195 default: strcat(string
, "(UNKNOWN) ");
199 case LIBSWD_DP_ABORT_ADDR
: strcat(string
, "(ABORT) "); break;
200 case LIBSWD_DP_CTRLSTAT_ADDR
: strcat(string
, (libswdctx
->log
.dp
.select
&1<<LIBSWD_DP_SELECT_CTRLSEL_BITNUM
)?"(CTRL/STAT or [WCR]) ":"([CTRL/STAT] or WCR) "); break;
201 case LIBSWD_DP_SELECT_ADDR
: strcat(string
, "(SELECT) "); break;
202 case LIBSWD_DP_ROUTESEL_ADDR
: strcat(string
, "(ROUTESEL)"); break;
203 default: strcat(string
, "(UNKNOWN) ");
207 strcat(string
, "Parity="); strcat(string
, parity
?"1":"0");