├── .drone.yml ├── .gitignore ├── .travis.yml ├── COPYING ├── ChangeLog ├── Doxyfile ├── Makefile.am ├── NEWS ├── README.md ├── TODO ├── acinclude.m4 ├── aminclude.am ├── autogen.sh ├── configure.ac └── src ├── Makefile.am ├── examples ├── libswd_drv_openocd.c ├── libswd_drv_openocd.h ├── libswd_drv_urjtag.c └── libswd_test.c ├── libswd.h ├── libswd_app.c ├── libswd_app.h ├── libswd_bin.c ├── libswd_bitgen.c ├── libswd_bus.c ├── libswd_cli.c ├── libswd_cmd.c ├── libswd_cmdq.c ├── libswd_core.c ├── libswd_dap.c ├── libswd_debug.c ├── libswd_drv.c ├── libswd_error.c ├── libswd_externs.c ├── libswd_log.c └── libswd_memap.c /.drone.yml: -------------------------------------------------------------------------------- 1 | build: 2 | image: teaci/msys$$arch 3 | shell: mingw$$arch 4 | pull: true 5 | commands: 6 | - if [ $$arch = 32 ]; then target=i686; fi 7 | - if [ $$arch = 64 ]; then target=x86_64; fi 8 | - pacman -Sy --noconfirm mingw-w64-${target}-libftdi mingw-w64-${target}-glib2 9 | - ./autogen.sh && ./configure $$config_opts && make 10 | matrix: 11 | arch: 12 | - 64 13 | - 32 14 | config_opts: 15 | - 16 | - --enable-application 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # C gitignore 2 | # Prerequisites 3 | *.d 4 | 5 | # Object files 6 | *.o 7 | *.ko 8 | *.obj 9 | *.elf 10 | 11 | # Linker output 12 | *.ilk 13 | *.map 14 | *.exp 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | 26 | # Shared objects (inc. Windows DLLs) 27 | *.dll 28 | *.so 29 | *.so.* 30 | *.dylib 31 | 32 | # Executables 33 | *.exe 34 | *.out 35 | *.app 36 | *.i*86 37 | *.x86_64 38 | *.hex 39 | 40 | # Debug files 41 | *.dSYM/ 42 | *.su 43 | *.idb 44 | *.pdb 45 | 46 | # Kernel Module Compile Results 47 | *.mod* 48 | *.cmd 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Autotools gitignore 55 | # http://www.gnu.org/software/automake 56 | 57 | Makefile.in 58 | /ar-lib 59 | /mdate-sh 60 | /py-compile 61 | /test-driver 62 | /ylwrap 63 | 64 | # http://www.gnu.org/software/autoconf 65 | 66 | /autom4te.cache 67 | /autoscan.log 68 | /autoscan-*.log 69 | /aclocal.m4 70 | /compile 71 | /config.guess 72 | /config.h.in 73 | /config.sub 74 | /configure 75 | /configure.scan 76 | /depcomp 77 | /install-sh 78 | /missing 79 | /stamp-h1 80 | 81 | # https://www.gnu.org/software/libtool/ 82 | 83 | /ltmain.sh 84 | 85 | # http://www.gnu.org/software/texinfo 86 | 87 | /texinfo.tex 88 | 89 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | os: 3 | - linux 4 | - osx 5 | addons: 6 | apt: 7 | packages: 8 | - libftdi-dev 9 | compiler: 10 | - gcc 11 | - clang 12 | env: 13 | - 14 | - CONFIG_OPTS=--enable-application 15 | install: if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install libftdi; fi 16 | script: ./autogen.sh && ./configure $CONFIG_OPTS && make 17 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Serial Wire Debug Open Library is distributed under 3-clause BSD license. 2 | 3 | Copyright (C) 2010-2017, CeDeROM Tomasz CEDRO (http://www.tomek.cedro.info) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 14 | contributors may be used to endorse or promote products derived from this 15 | software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 21 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 22 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 27 | OF THE POSSIBILITY OF SUCH DAMAGE.* 28 | 29 | Written by CeDeROM Tomasz Boleslaw CEDRO , 2010-2017; 30 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | LibSWD-0.7 (2017-02-15): 2 | * ARM Cortex-M0 and Cortex-M4 support. 3 | * AP read fix (ABORT after READ). 4 | * MEMAP support for 16-bit non-packed writes. 5 | * LibSWD Application CLI and CPUID improvements. 6 | * Fixed byte-laning and memory alignment issues. 7 | * Source code cleanup. 8 | * Special thanks to Andrew Parlane of [Carallon Ltd.](http://www.carallon.com/)! :-) 9 | 10 | LibSWD-0.6 (2013-10-20): 11 | * Introducing CLI (Command Line Interface) parser framework. Updated error defines. 12 | * Major fixes in LOG functions. Introducing vprintf() like libswd_log_internal_va(). 13 | * Added DEFAULT defines for LogLevel and AutoFixErrors libswdctx->config values. 14 | * Introducing MEM-AP routines. 15 | * Introducing Standalone LibSWD Aplication. 16 | * Introducing initial support for Debug and Flash access. 17 | 18 | LibSWD-0.5 (2012-12-06): 19 | * All functions and defines were renamed to use prefix libswd_ and LIBSWD_. 20 | * This is a first and official candidate for release with OpenOCD master. 21 | 22 | LibSWD-0.4 (2012-10-14): 23 | * Implemented necessary data phase on ACK={WAIT,FAULT} reply from Target. 24 | * Unknown ACK response and Protocol Error Sequence detection. 25 | * swd_cmd_t was added *errors to hold queue for error handling in ACK element. 26 | * automatic error handling on queue was not included in this release yet. 27 | * fixed swd_cmdq_free_tail() 28 | * swd_cmdq_flush() updates swdctx->cmdq upon execution. 29 | * swd_drv_transmit() updates swdctx->log values only on successful transmit. 30 | * DP and AP operations including MEM-AP now works. 31 | * OpenOCD integration is almost done, flashing works (1938B/18.6s with FT2232). 32 | 33 | LibSWD-0.3 (2011-11-11): 34 | * Fixed critical issue with ACK/DATA bitswap due erratic ARM documentation. 35 | * Fixes and improvements in libswd.h. 36 | * Debug hint function in Request packet decoposition (libswd_drv). 37 | * Fixed OpenOCD drivers. 38 | * Introduced SWD_LOGLEVEL_PAYLOAD even more verbose than debug. 39 | * All transfers are now LSB-First. 40 | * Major bugfixes. 41 | 42 | LibSWD-0.2 (2011-10-31): 43 | * Source code reorganization (split into different files). 44 | * Build system fixes and documentation updates. 45 | * Integration with OpenOCD. 46 | * Bugfixes and improvements. 47 | * Error detection in swd_drv_transmit() - cmdq is truncated on error. 48 | * Created dedicated functions to work on DAP registers. 49 | 50 | LibSWD-0.1 (2011-04-02): 51 | Initial release of LibSWD: 52 | * Basic functionality of transport, queue and drivers for ADIv5.0. 53 | * Automated SW-DP activation/reset and IDCODE read. 54 | * Tested and verified functionality on UrJTAG. 55 | * Source code documented using Doxygen. 56 | * Autotools integration for standarized build. 57 | 58 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src 2 | ACLOCAL_AMFLAGS = -I m4 3 | 4 | include $(top_srcdir)/aminclude.am 5 | EXTRA_DIST = Doxyfile 6 | MOSTLYCLEANFILES = DX_CLEANFILES 7 | 8 | dist_pkgdata_DATA = \ 9 | README.md \ 10 | COPYING \ 11 | ChangeLog \ 12 | NEWS 13 | 14 | uninstall-hook: 15 | rm -rf $(DESTDIR)$(pkgdatadir) 16 | 17 | distclean-local: 18 | rm -rf doxygen-doc/html doxygen-doc/latex doxygen-doc/libswd.pdf 19 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | For news and updates please visit project website at https://github.com/CeDeROM/LibSWD :-) 2 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Feel free to suggest fixes/changes/features at project website: 2 | https://github.com/CeDeROM/LibSWD/ 3 | -------------------------------------------------------------------------------- /acinclude.m4: -------------------------------------------------------------------------------- 1 | # This file is part of Autoconf. -*- Autoconf -*- 2 | 3 | # Copyright (C) 2004 Oren Ben-Kiki 4 | # This file is distributed under the same terms as the Autoconf macro files. 5 | 6 | ########## CHANGELOG ################## 7 | # 2009-01-14 Martin Mann 8 | # * DX_ARG_ABLE : new variable 'DX_FLAG_DX_CURRENT_FEATURE' 9 | # * DX_CLEAR_DEPEND : use of explicit variable 'DX_FLAG_DX_CURRENT_FEATURE' 10 | # in AC_SUBST instead of 'DX_FLAG[]DX_CURRENT_FEATURE' which is rejected by 11 | # newer autotools 12 | 13 | # Generate automatic documentation using Doxygen. Works in concert with the 14 | # aminclude.m4 file and a compatible doxygen configuration file. Defines the 15 | # following public macros: 16 | # 17 | # DX_???_FEATURE(ON|OFF) - control the default setting fo a Doxygen feature. 18 | # Supported features are 'DOXYGEN' itself, 'DOT' for generating graphics, 19 | # 'HTML' for plain HTML, 'CHM' for compressed HTML help (for MS users), 'CHI' 20 | # for generating a seperate .chi file by the .chm file, and 'MAN', 'RTF', 21 | # 'XML', 'PDF' and 'PS' for the appropriate output formats. The environment 22 | # variable DOXYGEN_PAPER_SIZE may be specified to override the default 'a4wide' 23 | # paper size. 24 | # 25 | # By default, HTML, PDF and PS documentation is generated as this seems to be 26 | # the most popular and portable combination. MAN pages created by Doxygen are 27 | # usually problematic, though by picking an appropriate subset and doing some 28 | # massaging they might be better than nothing. CHM and RTF are specific for MS 29 | # (note that you can't generate both HTML and CHM at the same time). The XML is 30 | # rather useless unless you apply specialized post-processing to it. 31 | # 32 | # The macro mainly controls the default state of the feature. The use can 33 | # override the default by specifying --enable or --disable. The macros ensure 34 | # that contradictory flags are not given (e.g., --enable-doxygen-html and 35 | # --enable-doxygen-chm, --enable-doxygen-anything with --disable-doxygen, etc.) 36 | # Finally, each feature will be automatically disabled (with a warning) if the 37 | # required programs are missing. 38 | # 39 | # Once all the feature defaults have been specified, call DX_INIT_DOXYGEN with 40 | # the following parameters: a one-word name for the project for use as a 41 | # filename base etc., an optional configuration file name (the default is 42 | # 'Doxyfile', the same as Doxygen's default), and an optional output directory 43 | # name (the default is 'doxygen-doc'). 44 | 45 | ## ----------## 46 | ## Defaults. ## 47 | ## ----------## 48 | 49 | DX_ENV="" 50 | AC_DEFUN([DX_FEATURE_doc], ON) 51 | AC_DEFUN([DX_FEATURE_dot], ON) 52 | AC_DEFUN([DX_FEATURE_man], OFF) 53 | AC_DEFUN([DX_FEATURE_html], ON) 54 | AC_DEFUN([DX_FEATURE_chm], OFF) 55 | AC_DEFUN([DX_FEATURE_chi], OFF) 56 | AC_DEFUN([DX_FEATURE_rtf], OFF) 57 | AC_DEFUN([DX_FEATURE_xml], OFF) 58 | AC_DEFUN([DX_FEATURE_pdf], ON) 59 | AC_DEFUN([DX_FEATURE_ps], ON) 60 | 61 | ## --------------- ## 62 | ## Private macros. ## 63 | ## --------------- ## 64 | 65 | # DX_ENV_APPEND(VARIABLE, VALUE) 66 | # ------------------------------ 67 | # Append VARIABLE="VALUE" to DX_ENV for invoking doxygen. 68 | AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])]) 69 | 70 | # DX_DIRNAME_EXPR 71 | # --------------- 72 | # Expand into a shell expression prints the directory part of a path. 73 | AC_DEFUN([DX_DIRNAME_EXPR], 74 | [[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']]) 75 | 76 | # DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF) 77 | # ------------------------------------- 78 | # Expands according to the M4 (static) status of the feature. 79 | AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])]) 80 | 81 | # DX_REQUIRE_PROG(VARIABLE, PROGRAM) 82 | # ---------------------------------- 83 | # Require the specified program to be found for the DX_CURRENT_FEATURE to work. 84 | AC_DEFUN([DX_REQUIRE_PROG], [ 85 | AC_PATH_TOOL([$1], [$2]) 86 | if test "$DX_FLAG_DX_CURRENT_FEATURE$$1" = 1; then 87 | AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION]) 88 | AC_SUBST([DX_FLAG_DX_CURRENT_FEATURE], 0) 89 | fi 90 | ]) 91 | 92 | # DX_TEST_FEATURE(FEATURE) 93 | # ------------------------ 94 | # Expand to a shell expression testing whether the feature is active. 95 | AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1]) 96 | 97 | # DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE) 98 | # ------------------------------------------------- 99 | # Verify that a required features has the right state before trying to turn on 100 | # the DX_CURRENT_FEATURE. 101 | AC_DEFUN([DX_CHECK_DEPEND], [ 102 | test "$DX_FLAG_$1" = "$2" \ 103 | || AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1, 104 | requires, contradicts) doxygen-DX_CURRENT_FEATURE]) 105 | ]) 106 | 107 | # DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE) 108 | # ---------------------------------------------------------- 109 | # Turn off the DX_CURRENT_FEATURE if the required feature is off. 110 | AC_DEFUN([DX_CLEAR_DEPEND], [ 111 | test "$DX_FLAG_$1" = "$2" || AC_SUBST([DX_FLAG_DX_CURRENT_FEATURE], 0) 112 | ]) 113 | 114 | 115 | # DX_FEATURE_ARG(FEATURE, DESCRIPTION, 116 | # CHECK_DEPEND, CLEAR_DEPEND, 117 | # REQUIRE, DO-IF-ON, DO-IF-OFF) 118 | # -------------------------------------------- 119 | # Parse the command-line option controlling a feature. CHECK_DEPEND is called 120 | # if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND), 121 | # otherwise CLEAR_DEPEND is called to turn off the default state if a required 122 | # feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional 123 | # requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and 124 | # DO-IF-ON or DO-IF-OFF are called according to the final state of the feature. 125 | AC_DEFUN([DX_ARG_ABLE], [ 126 | AC_DEFUN([DX_CURRENT_FEATURE], [$1]) 127 | AC_DEFUN([DX_FLAG_DX_CURRENT_FEATURE], [DX_FLAG_$1]) 128 | AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2]) 129 | AC_ARG_ENABLE(doxygen-$1, 130 | [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1], 131 | [--enable-doxygen-$1]), 132 | DX_IF_FEATURE([$1], [don't $2], [$2]))], 133 | [ 134 | case "$enableval" in 135 | #( 136 | y|Y|yes|Yes|YES) 137 | AC_SUBST([DX_FLAG_$1], 1) 138 | $3 139 | ;; #( 140 | n|N|no|No|NO) 141 | AC_SUBST([DX_FLAG_$1], 0) 142 | ;; #( 143 | *) 144 | AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1]) 145 | ;; 146 | esac 147 | ], [ 148 | AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)]) 149 | $4 150 | ]) 151 | if DX_TEST_FEATURE([$1]); then 152 | $5 153 | : 154 | fi 155 | if DX_TEST_FEATURE([$1]); then 156 | AM_CONDITIONAL(DX_COND_$1, :) 157 | $6 158 | : 159 | else 160 | AM_CONDITIONAL(DX_COND_$1, false) 161 | $7 162 | : 163 | fi 164 | ]) 165 | 166 | ## -------------- ## 167 | ## Public macros. ## 168 | ## -------------- ## 169 | 170 | # DX_XXX_FEATURE(DEFAULT_STATE) 171 | # ----------------------------- 172 | AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])]) 173 | AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])]) 174 | AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])]) 175 | AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])]) 176 | AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])]) 177 | AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])]) 178 | AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])]) 179 | AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])]) 180 | AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])]) 181 | AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])]) 182 | 183 | # DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR]) 184 | # --------------------------------------------------------- 185 | # PROJECT also serves as the base name for the documentation files. 186 | # The default CONFIG-FILE is "Doxyfile" and OUTPUT-DOC-DIR is "doxygen-doc". 187 | AC_DEFUN([DX_INIT_DOXYGEN], [ 188 | 189 | # Files: 190 | AC_SUBST([DX_PROJECT], [$1]) 191 | AC_SUBST([DX_CONFIG], [ifelse([$2], [], Doxyfile, [$2])]) 192 | AC_SUBST([DX_DOCDIR], [ifelse([$3], [], doxygen-doc, [$3])]) 193 | 194 | # Environment variables used inside doxygen.cfg: 195 | DX_ENV_APPEND(SRCDIR, $srcdir) 196 | DX_ENV_APPEND(PROJECT, $DX_PROJECT) 197 | DX_ENV_APPEND(DOCDIR, $DX_DOCDIR) 198 | DX_ENV_APPEND(VERSION, $PACKAGE_VERSION) 199 | 200 | # Doxygen itself: 201 | DX_ARG_ABLE(doc, [generate any doxygen documentation], 202 | [], 203 | [], 204 | [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen) 205 | DX_REQUIRE_PROG([DX_PERL], perl)], 206 | [DX_ENV_APPEND(PERL_PATH, $DX_PERL)]) 207 | 208 | # Dot for graphics: 209 | DX_ARG_ABLE(dot, [generate graphics for doxygen documentation], 210 | [DX_CHECK_DEPEND(doc, 1)], 211 | [DX_CLEAR_DEPEND(doc, 1)], 212 | [DX_REQUIRE_PROG([DX_DOT], dot)], 213 | [DX_ENV_APPEND(HAVE_DOT, YES) 214 | DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])], 215 | [DX_ENV_APPEND(HAVE_DOT, NO)]) 216 | 217 | # Man pages generation: 218 | DX_ARG_ABLE(man, [generate doxygen manual pages], 219 | [DX_CHECK_DEPEND(doc, 1)], 220 | [DX_CLEAR_DEPEND(doc, 1)], 221 | [], 222 | [DX_ENV_APPEND(GENERATE_MAN, YES)], 223 | [DX_ENV_APPEND(GENERATE_MAN, NO)]) 224 | 225 | # RTF file generation: 226 | DX_ARG_ABLE(rtf, [generate doxygen RTF documentation], 227 | [DX_CHECK_DEPEND(doc, 1)], 228 | [DX_CLEAR_DEPEND(doc, 1)], 229 | [], 230 | [DX_ENV_APPEND(GENERATE_RTF, YES)], 231 | [DX_ENV_APPEND(GENERATE_RTF, NO)]) 232 | 233 | # XML file generation: 234 | DX_ARG_ABLE(xml, [generate doxygen XML documentation], 235 | [DX_CHECK_DEPEND(doc, 1)], 236 | [DX_CLEAR_DEPEND(doc, 1)], 237 | [], 238 | [DX_ENV_APPEND(GENERATE_XML, YES)], 239 | [DX_ENV_APPEND(GENERATE_XML, NO)]) 240 | 241 | # (Compressed) HTML help generation: 242 | DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation], 243 | [DX_CHECK_DEPEND(doc, 1)], 244 | [DX_CLEAR_DEPEND(doc, 1)], 245 | [DX_REQUIRE_PROG([DX_HHC], hhc)], 246 | [DX_ENV_APPEND(HHC_PATH, $DX_HHC) 247 | DX_ENV_APPEND(GENERATE_HTML, YES) 248 | DX_ENV_APPEND(GENERATE_HTMLHELP, YES)], 249 | [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)]) 250 | 251 | # Seperate CHI file generation. 252 | DX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file], 253 | [DX_CHECK_DEPEND(chm, 1)], 254 | [DX_CLEAR_DEPEND(chm, 1)], 255 | [], 256 | [DX_ENV_APPEND(GENERATE_CHI, YES)], 257 | [DX_ENV_APPEND(GENERATE_CHI, NO)]) 258 | 259 | # Plain HTML pages generation: 260 | DX_ARG_ABLE(html, [generate doxygen plain HTML documentation], 261 | [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)], 262 | [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)], 263 | [], 264 | [DX_ENV_APPEND(GENERATE_HTML, YES)], 265 | [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)]) 266 | 267 | # PostScript file generation: 268 | DX_ARG_ABLE(ps, [generate doxygen PostScript documentation], 269 | [DX_CHECK_DEPEND(doc, 1)], 270 | [DX_CLEAR_DEPEND(doc, 1)], 271 | [DX_REQUIRE_PROG([DX_LATEX], latex) 272 | DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) 273 | DX_REQUIRE_PROG([DX_DVIPS], dvips) 274 | DX_REQUIRE_PROG([DX_EGREP], egrep)]) 275 | 276 | # PDF file generation: 277 | DX_ARG_ABLE(pdf, [generate doxygen PDF documentation], 278 | [DX_CHECK_DEPEND(doc, 1)], 279 | [DX_CLEAR_DEPEND(doc, 1)], 280 | [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex) 281 | DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) 282 | DX_REQUIRE_PROG([DX_EGREP], egrep)]) 283 | 284 | # LaTeX generation for PS and/or PDF: 285 | if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then 286 | AM_CONDITIONAL(DX_COND_latex, :) 287 | DX_ENV_APPEND(GENERATE_LATEX, YES) 288 | else 289 | AM_CONDITIONAL(DX_COND_latex, false) 290 | DX_ENV_APPEND(GENERATE_LATEX, NO) 291 | fi 292 | 293 | # Paper size for PS and/or PDF: 294 | AC_ARG_VAR(DOXYGEN_PAPER_SIZE, 295 | [a4wide (default), a4, letter, legal or executive]) 296 | case "$DOXYGEN_PAPER_SIZE" in 297 | #( 298 | "") 299 | AC_SUBST(DOXYGEN_PAPER_SIZE, "") 300 | ;; #( 301 | a4wide|a4|letter|legal|executive) 302 | DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE) 303 | ;; #( 304 | *) 305 | AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE']) 306 | ;; 307 | esac 308 | 309 | #For debugging: 310 | #echo DX_FLAG_doc=$DX_FLAG_doc 311 | #echo DX_FLAG_dot=$DX_FLAG_dot 312 | #echo DX_FLAG_man=$DX_FLAG_man 313 | #echo DX_FLAG_html=$DX_FLAG_html 314 | #echo DX_FLAG_chm=$DX_FLAG_chm 315 | #echo DX_FLAG_chi=$DX_FLAG_chi 316 | #echo DX_FLAG_rtf=$DX_FLAG_rtf 317 | #echo DX_FLAG_xml=$DX_FLAG_xml 318 | #echo DX_FLAG_pdf=$DX_FLAG_pdf 319 | #echo DX_FLAG_ps=$DX_FLAG_ps 320 | #echo DX_ENV=$DX_ENV 321 | ]) 322 | -------------------------------------------------------------------------------- /aminclude.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004 Oren Ben-Kiki 2 | # This file is distributed under the same terms as the Automake macro files. 3 | 4 | # Generate automatic documentation using Doxygen. Goals and variables values 5 | # are controlled by the various DX_COND_??? conditionals set by autoconf. 6 | # 7 | # The provided goals are: 8 | # doxygen-doc: Generate all doxygen documentation. 9 | # doxygen-run: Run doxygen, which will generate some of the documentation 10 | # (HTML, CHM, CHI, MAN, RTF, XML) but will not do the post 11 | # processing required for the rest of it (PS, PDF, and some MAN). 12 | # doxygen-man: Rename some doxygen generated man pages. 13 | # doxygen-ps: Generate doxygen PostScript documentation. 14 | # doxygen-pdf: Generate doxygen PDF documentation. 15 | # 16 | # Note that by default these are not integrated into the automake goals. If 17 | # doxygen is used to generate man pages, you can achieve this integration by 18 | # setting man3_MANS to the list of man pages generated and then adding the 19 | # dependency: 20 | # 21 | # $(man3_MANS): doxygen-doc 22 | # 23 | # This will cause make to run doxygen and generate all the documentation. 24 | # 25 | # The following variable is intended for use in Makefile.am: 26 | # 27 | # DX_CLEANFILES = everything to clean. 28 | # 29 | # This is usually added to MOSTLYCLEANFILES. 30 | 31 | ## --------------------------------- ## 32 | ## Format-independent Doxygen rules. ## 33 | ## --------------------------------- ## 34 | 35 | if DX_COND_doc 36 | 37 | ## ------------------------------- ## 38 | ## Rules specific for HTML output. ## 39 | ## ------------------------------- ## 40 | 41 | if DX_COND_html 42 | 43 | DX_CLEAN_HTML = @DX_DOCDIR@/html 44 | 45 | endif DX_COND_html 46 | 47 | ## ------------------------------ ## 48 | ## Rules specific for CHM output. ## 49 | ## ------------------------------ ## 50 | 51 | if DX_COND_chm 52 | 53 | DX_CLEAN_CHM = @DX_DOCDIR@/chm 54 | 55 | if DX_COND_chi 56 | 57 | DX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi 58 | 59 | endif DX_COND_chi 60 | 61 | endif DX_COND_chm 62 | 63 | ## ------------------------------ ## 64 | ## Rules specific for MAN output. ## 65 | ## ------------------------------ ## 66 | 67 | if DX_COND_man 68 | 69 | DX_CLEAN_MAN = @DX_DOCDIR@/man 70 | 71 | endif DX_COND_man 72 | 73 | ## ------------------------------ ## 74 | ## Rules specific for RTF output. ## 75 | ## ------------------------------ ## 76 | 77 | if DX_COND_rtf 78 | 79 | DX_CLEAN_RTF = @DX_DOCDIR@/rtf 80 | 81 | endif DX_COND_rtf 82 | 83 | ## ------------------------------ ## 84 | ## Rules specific for XML output. ## 85 | ## ------------------------------ ## 86 | 87 | if DX_COND_xml 88 | 89 | DX_CLEAN_XML = @DX_DOCDIR@/xml 90 | 91 | endif DX_COND_xml 92 | 93 | ## ----------------------------- ## 94 | ## Rules specific for PS output. ## 95 | ## ----------------------------- ## 96 | 97 | if DX_COND_ps 98 | 99 | DX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps 100 | 101 | DX_PS_GOAL = doxygen-ps 102 | 103 | doxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps 104 | 105 | @DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag 106 | cd @DX_DOCDIR@/latex; \ 107 | rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \ 108 | $(DX_LATEX) refman.tex; \ 109 | $(MAKEINDEX_PATH) refman.idx; \ 110 | $(DX_LATEX) refman.tex; \ 111 | countdown=5; \ 112 | while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \ 113 | refman.log > /dev/null 2>&1 \ 114 | && test $$countdown -gt 0; do \ 115 | $(DX_LATEX) refman.tex; \ 116 | countdown=`expr $$countdown - 1`; \ 117 | done; \ 118 | $(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi 119 | 120 | endif DX_COND_ps 121 | 122 | ## ------------------------------ ## 123 | ## Rules specific for PDF output. ## 124 | ## ------------------------------ ## 125 | 126 | if DX_COND_pdf 127 | 128 | DX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf 129 | 130 | DX_PDF_GOAL = doxygen-pdf 131 | 132 | doxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf 133 | 134 | @DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag 135 | cd @DX_DOCDIR@/latex; \ 136 | rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \ 137 | $(DX_PDFLATEX) refman.tex; \ 138 | $(DX_MAKEINDEX) refman.idx; \ 139 | $(DX_PDFLATEX) refman.tex; \ 140 | countdown=5; \ 141 | while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \ 142 | refman.log > /dev/null 2>&1 \ 143 | && test $$countdown -gt 0; do \ 144 | $(DX_PDFLATEX) refman.tex; \ 145 | countdown=`expr $$countdown - 1`; \ 146 | done; \ 147 | mv refman.pdf ../@PACKAGE@.pdf 148 | 149 | endif DX_COND_pdf 150 | 151 | ## ------------------------------------------------- ## 152 | ## Rules specific for LaTeX (shared for PS and PDF). ## 153 | ## ------------------------------------------------- ## 154 | 155 | if DX_COND_latex 156 | 157 | DX_CLEAN_LATEX = @DX_DOCDIR@/latex 158 | 159 | endif DX_COND_latex 160 | 161 | .PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL) 162 | 163 | .INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL) 164 | 165 | doxygen-run: @DX_DOCDIR@/@PACKAGE@.tag 166 | 167 | doxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL) 168 | 169 | @DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS) 170 | # rm -rf @DX_DOCDIR@ 171 | $(DX_ENV) $(DX_DOXYGEN) $(srcdir)/$(DX_CONFIG) 172 | 173 | DX_CLEANFILES = \ 174 | @DX_DOCDIR@/@PACKAGE@.tag \ 175 | -r \ 176 | $(DX_CLEAN_HTML) \ 177 | $(DX_CLEAN_CHM) \ 178 | $(DX_CLEAN_CHI) \ 179 | $(DX_CLEAN_MAN) \ 180 | $(DX_CLEAN_RTF) \ 181 | $(DX_CLEAN_XML) \ 182 | $(DX_CLEAN_PS) \ 183 | $(DX_CLEAN_PDF) \ 184 | $(DX_CLEAN_LATEX) 185 | 186 | endif DX_COND_doc 187 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mkdir m4 3 | if autoreconf -i -v -f ; then 4 | echo 5 | echo "autoreconf done." 6 | echo 7 | else 8 | echo 9 | echo "autoreconf failed." 10 | echo 11 | exit 1 12 | fi 13 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([libswd], [GIT-][m4_esyscmd_s([git rev-parse --short HEAD])], [tomek@cedro.info]) 2 | AC_CONFIG_AUX_DIR([build-aux]) 3 | AC_CONFIG_MACRO_DIR([m4]) 4 | 5 | AC_ARG_ENABLE([application], 6 | AS_HELP_STRING([--enable-application], 7 | [build the LibSWD Application (default: no)]), 8 | [case "${enableval}" in 9 | yes) enable_application=true ;; 10 | no) enable_application=false ;; 11 | *) AC_MSG_ERROR([bad value ${enableval} for --enable-application]) ;; 12 | esac], 13 | [enable_application=false] 14 | ) 15 | AM_CONDITIONAL([APPLICATION], [test x"$enable_application" = x"true"]) 16 | LIBREADLINE= 17 | AS_IF([test x"$enable_application" == x"true"], 18 | [ 19 | AC_CHECK_LIB([readline], [readline], 20 | [AC_SUBST([LIBREADLINE], ["-lreadline"]) 21 | AC_DEFINE([HAVE_READLINE], [1], [Define if you have libreadline])], 22 | [AC_MSG_FAILURE([Readline not found, required by LibSWD Application!])] 23 | ) 24 | ] 25 | ) 26 | LIBFTDI= 27 | AS_IF([test x"$enable_application" == x"true"], 28 | [ 29 | AC_CHECK_LIB([ftdi], [ftdi_new], 30 | [AC_SUBST([LIBFTDI], ["-lftdi"]) 31 | AC_DEFINE([HAVE_FTDI], [1], [Define if you have libftdi])], 32 | ) 33 | ] 34 | ) 35 | LIBFTDI1= 36 | AS_IF([test x"$enable_application" == x"true"], 37 | [ 38 | AC_CHECK_LIB([ftdi1], [ftdi_new], 39 | [AC_SUBST([LIBFTDI], ["-lftdi1"]) 40 | AC_DEFINE([HAVE_FTDI1], [1], [Define if you have libftdi1])], 41 | ) 42 | ] 43 | ) 44 | LIBUSB= 45 | AS_IF([test x"$enable_application" == x"true"], 46 | [ 47 | AS_IF( 48 | [test `uname` == "FreeBSD"], 49 | [ 50 | AC_CHECK_LIB([usb], [libusb_init], 51 | [AC_SUBST([LIBUSB], ["-lusb"]) 52 | AC_DEFINE([HAVE_USB1], [1], [Define if you have libusb-1])] 53 | ,[AC_MSG_WARN([LibUSB-1 not found, no async USB I/O available...])] 54 | ) 55 | ], 56 | [ 57 | AC_CHECK_LIB([usb-1.0], [libusb_init], 58 | [AC_SUBST([LIBUSB], ["-lusb-1.0"]) 59 | AC_DEFINE([HAVE_USB1], [1], [Define if you have libusb-1])] 60 | ,[AC_MSG_WARN([LibUSB-1 not found, no async USB I/O available...])] 61 | ) 62 | ] 63 | ) 64 | ] 65 | ) 66 | #Check if we have LibFTDI. If using LibFTDI1 also verify LibUSB1 presence. 67 | AS_IF([test x"$enable_application" == x"true"], 68 | [ 69 | AC_CHECK_DECL(HAVE_FTDI1, 70 | [ 71 | AC_CHECK_DECL(HAVE_USB1, 72 | [AC_MSG_NOTICE([LibFTDI1+LibUSB1 found, async USB I/O available!])], 73 | [AC_MSG_FAILURE([LibFTDI1 requires LibUSB1, but it was not found!])] 74 | ) 75 | ], 76 | [ 77 | AC_CHECK_DECL(HAVE_FTDI, 78 | [AC_MSG_NOTICE([Old LibFTDI found, no async USB I/O available!])], 79 | [AC_MSG_FAILURE([Neither LibFTDI nor LibFTDI1 was found, but required by LibSWD Application!])] 80 | ) 81 | ] 82 | ) 83 | ] 84 | ) 85 | 86 | AC_ARG_ENABLE(debug, 87 | AS_HELP_STRING([--enable-debug], [build with Debug Symbols (default: no)]), 88 | [case "${enableval}" in 89 | yes) debug=true ;; 90 | no) debug=false ;; 91 | *) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;; 92 | esac], 93 | [debug=false] 94 | ) 95 | AM_CONDITIONAL(DEBUG, test x"$debug" = x"true") 96 | 97 | AM_INIT_AUTOMAKE([foreign -Wall -Werror]) 98 | DX_PDF_FEATURE(ON) 99 | DX_HTML_FEATURE(ON) 100 | DX_PS_FEATURE(OFF) 101 | DX_MAN_FEATURE(OFF) 102 | DX_INIT_DOXYGEN($PACKAGE_STRING) 103 | m4_pattern_allow([AM_PROG_AR]) 104 | AM_PROG_AR 105 | AC_PROG_CC 106 | LT_INIT 107 | AC_CONFIG_HEADERS([config.h]) 108 | AC_CONFIG_FILES([Makefile src/Makefile]) 109 | AC_OUTPUT 110 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES = libswd.la 2 | libswd_la_LDFLAGS = -version-info 0:6:0 3 | include_HEADERS = libswd.h 4 | LDADD = $(LIBOBJS) $(ALLOCA) 5 | EXTRA_DIST = \ 6 | examples/libswd_drv_urjtag.c \ 7 | examples/libswd_drv_openocd.h \ 8 | examples/libswd_drv_openocd.c \ 9 | libswd_externs.c 10 | if DEBUG 11 | AM_CFLAGS = -g3 12 | endif 13 | 14 | libswd_la_SOURCES = \ 15 | libswd.h \ 16 | libswd_bin.c \ 17 | libswd_bitgen.c \ 18 | libswd_bus.c \ 19 | libswd_cli.c \ 20 | libswd_cmd.c \ 21 | libswd_cmdq.c \ 22 | libswd_core.c \ 23 | libswd_dap.c \ 24 | libswd_debug.c \ 25 | libswd_drv.c \ 26 | libswd_error.c \ 27 | libswd_log.c \ 28 | libswd_memap.c 29 | 30 | if APPLICATION 31 | bin_PROGRAMS = libswd 32 | libswd_SOURCES = \ 33 | libswd_app.h \ 34 | libswd_app.c 35 | libswd_LDADD = -lswd $(LIBREADLINE) $(LIBFTDI) $(LIBUSB) 36 | endif 37 | -------------------------------------------------------------------------------- /src/examples/libswd_drv_openocd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * 4 | * Driver Bridge between LibSWD and OpenOCD. 5 | * 6 | * Copyright (C) 2010-2011 Tomasz Boleslaw CEDRO 7 | * cederom@tlen.pl, http://www.tomek.cedro.info 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * 1. Redistributions of source code must retain the above copyright notice, 13 | * this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright notice, 15 | * this list of conditions and the following disclaimer in the documentation 16 | * and/or other materials provided with the distribution. 17 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 18 | * contributors may be used to endorse or promote products derived from this 19 | * software without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 26 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 29 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 32 | * 33 | * Written by Tomasz Boleslaw CEDRO , 2010-2011; 34 | * 35 | */ 36 | 37 | /** \file liblibswd_drv_openocd.c Driver Bridge between LibSWD and OpenOCD. */ 38 | 39 | #include 40 | 41 | /** OpenOCD as for now use global pointer to driver structure. */ 42 | extern struct jtag_interface *jtag_interface; 43 | 44 | /** 45 | * Use UrJTAG's driver to write 8-bit data (char type). 46 | * MOSI (Master Output Slave Input) is a SWD Write Operation. 47 | * \param *libswdctx swd context to work on. 48 | * \param *cmd point to the actual command being sent. 49 | * \param *data points to the char data. 50 | * \bits tells how many bits to send (at most 8). 51 | * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first. 52 | * \return data count transferred, or negative LIBSWD_ERROR code on failure. 53 | ar)*/ 54 | int libswd_drv_mosi_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst){ 55 | LOG_DEBUG("OpenOCD's libswd_drv_mosi_8(libswdctx=@%p, cmd=@%p, data=0x%02X, bits=%d, nLSBfirst=0x%02X)", (void*)libswdctx, (void*)cmd, *data, bits, nLSBfirst); 56 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 57 | if (bits<0 && bits>8) return LIBSWD_ERROR_PARAM; 58 | if (nLSBfirst!=0 && nLSBfirst!=1) return LIBSWD_ERROR_PARAM; 59 | 60 | static unsigned int i; 61 | static signed int res; 62 | static char misodata[8], mosidata[8]; 63 | 64 | /* Split output data into char array. */ 65 | for (i=0;i<8;i++) mosidata[(nLSBfirst==LIBSWD_DIR_LSBFIRST)?(i):(bits-1-i)]=((1<transfer(NULL, bits, mosidata, misodata, 0); 68 | if (res<0) return LIBSWD_ERROR_DRIVER; 69 | 70 | return i; 71 | } 72 | 73 | /** 74 | * Use UrJTAG's driver to write 32-bit data (int type). 75 | * MOSI (Master Output Slave Input) is a SWD Write Operation. 76 | * \param *libswdctx swd context to work on. 77 | * \param *cmd point to the actual command being sent. 78 | * \param *data points to the char buffer array. 79 | * \bits tells how many bits to send (at most 32). 80 | * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first. 81 | * \return data count transferred, or negative LIBSWD_ERROR code on failure. 82 | */ 83 | int libswd_drv_mosi_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst){ 84 | LOG_DEBUG("OpenOCD's libswd_drv_mosi_32(libswdctx=@%p, cmd=@%p, data=0x%08X, bits=%d, nLSBfirst=0x%02X)", (void*)libswdctx, (void*)cmd, *data, bits, nLSBfirst); 85 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 86 | if (bits<0 && bits>8) return LIBSWD_ERROR_PARAM; 87 | if (nLSBfirst!=0 && nLSBfirst!=1) return LIBSWD_ERROR_PARAM; 88 | 89 | static unsigned int i; 90 | static signed int res; 91 | static char misodata[32], mosidata[32]; 92 | 93 | //UrJTAG drivers shift data LSB-First. 94 | for (i=0;i<32;i++) mosidata[(nLSBfirst==LIBSWD_DIR_LSBFIRST)?(i):(bits-1-i)]=((1<transfer(NULL, bits, mosidata, misodata, 0); 96 | if (res<0) return LIBSWD_ERROR_DRIVER; 97 | return i; 98 | } 99 | 100 | /** 101 | * Use UrJTAG's driver to read 8-bit data (char type). 102 | * MISO (Master Input Slave Output) is a SWD Read Operation. 103 | * \param *libswdctx swd context to work on. 104 | * \param *cmd point to the actual command being sent. 105 | * \param *data points to the char buffer array. 106 | * \bits tells how many bits to send (at most 8). 107 | * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first. 108 | * \return data count transferred, or negative LIBSWD_ERROR code on failure. 109 | */ 110 | int libswd_drv_miso_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst){ 111 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 112 | if (bits<0 && bits>8) return LIBSWD_ERROR_PARAM; 113 | if (nLSBfirst!=0 && nLSBfirst!=1) return LIBSWD_ERROR_PARAM; 114 | 115 | static int i; 116 | static signed int res; 117 | static char misodata[8], mosidata[8]; 118 | 119 | res=jtag_interface->transfer(NULL, bits, mosidata, misodata, LIBSWD_DIR_LSBFIRST); 120 | if (res<0) return LIBSWD_ERROR_DRIVER; 121 | /* Now we need to reconstruct the data byte from shifted in LSBfirst byte array. */ 122 | *data=0; 123 | for (i=0;i8) return LIBSWD_ERROR_PARAM; 141 | if (nLSBfirst!=0 && nLSBfirst!=1) return LIBSWD_ERROR_PARAM; 142 | 143 | static int i; 144 | static signed int res; 145 | static char misodata[32], mosidata[32]; 146 | 147 | res=jtag_interface->transfer(NULL, bits, mosidata, misodata, LIBSWD_DIR_LSBFIRST); 148 | if (res<0) return LIBSWD_ERROR_DRIVER; 149 | /* Now we need to reconstruct the data byte from shifted in LSBfirst byte array. */ 150 | *data=0; 151 | for (i=0;iLIBSWD_TURNROUND_MAX_VAL) 169 | return LIBSWD_ERROR_TURNAROUND; 170 | 171 | int res, val=0; 172 | static char buf[LIBSWD_TURNROUND_MAX_VAL]; 173 | /* Use driver method to set low (write) signal named RnW. */ 174 | res=jtag_interface->bitbang(NULL, "RnW", 0, &val); 175 | if (res<0) return LIBSWD_ERROR_DRIVER; 176 | 177 | /* Clock specified number of bits for proper TRN transaction. */ 178 | res=jtag_interface->transfer(NULL, bits, buf, buf, 0); 179 | if (res<0) return LIBSWD_ERROR_DRIVER; 180 | 181 | return bits; 182 | } 183 | 184 | /** 185 | * This function sets interface buffers to MISO direction. 186 | * MISO (Master Input Slave Output) is a SWD Read operation. 187 | * OpenOCD use global "struct jtag_interface" pointer as interface driver. 188 | * OpenOCD driver must support "RnW" signal to drive output buffers for TRN. 189 | * \param *libswdctx is the swd context to work on. 190 | * \param bits specify how many clock cycles must be used for TRN. 191 | * \return number of bits transmitted or negative LIBSWD_ERROR code on failure. 192 | */ 193 | int libswd_drv_miso_trn(libswd_ctx_t *libswdctx, int bits){ 194 | LOG_DEBUG("OpenOCD's libswd_drv_miso_trn(libswdctx=@%p, bits=%d)\n", (void*)libswdctx, bits); 195 | if (bitsLIBSWD_TURNROUND_MAX_VAL) 196 | return LIBSWD_ERROR_TURNAROUND; 197 | 198 | static int res, val=1; 199 | static char buf[LIBSWD_TURNROUND_MAX_VAL]; 200 | 201 | /* Use driver method to set high (read) signal named RnW. */ 202 | res=jtag_interface->bitbang(NULL, "RnW", 0xFFFFFFFF, &val); 203 | if (res<0) return LIBSWD_ERROR_DRIVER; 204 | 205 | /* Clock specified number of bits for proper TRN transaction. */ 206 | res=jtag_interface->transfer(NULL, bits, buf, buf, 0); 207 | if (res<0) return LIBSWD_ERROR_DRIVER; 208 | 209 | return bits; 210 | } 211 | 212 | 213 | /** 214 | * Set SWD debug level according to OpenOCD settings. 215 | * \param *libswdctx is the context to work on. 216 | * \param loglevel is the OpenOCD numerical value of actual loglevel to force 217 | * on LibSWD, or -1 to inherit from actual global settings of OpenOCD. 218 | * \return LIBSWD_OK on success, negative LIBSWD_ERROR code on failure. 219 | */ 220 | int libswd_log_level_inherit(libswd_ctx_t *libswdctx, int loglevel){ 221 | LOG_DEBUG("OpenOCD's libswd_log_level_inherit(libswdctx=@%p, loglevel=%d)\n", (void*)libswdctx, loglevel); 222 | if (libswdctx==NULL){ 223 | LOG_WARNING("libswd_log_level_inherit(): SWD Context not (yet) initialized...\n"); 224 | return LIBSWD_OK; 225 | } 226 | 227 | libswd_loglevel_t new_swdlevel; 228 | switch ((loglevel==-1)?debug_level:loglevel){ 229 | case LOG_LVL_DEBUG: 230 | new_swdlevel=LIBSWD_LOGLEVEL_PAYLOAD; 231 | break; 232 | case LOG_LVL_INFO: 233 | new_swdlevel=LIBSWD_LOGLEVEL_INFO; 234 | break; 235 | case LOG_LVL_WARNING: 236 | new_swdlevel=LIBSWD_LOGLEVEL_WARNING; 237 | break; 238 | case LOG_LVL_ERROR: 239 | new_swdlevel=LIBSWD_LOGLEVEL_ERROR; 240 | break; 241 | case LOG_LVL_USER: 242 | case LOG_LVL_OUTPUT: 243 | new_swdlevel=LIBSWD_LOGLEVEL_NORMAL; 244 | break; 245 | case LOG_LVL_SILENT: 246 | new_swdlevel=LIBSWD_LOGLEVEL_SILENT; 247 | break; 248 | default: 249 | new_swdlevel=LIBSWD_LOGLEVEL_NORMAL; 250 | } 251 | 252 | int res=libswd_log_level_set(libswdctx, new_swdlevel); 253 | if (res<0) { 254 | LOG_ERROR("libswd_log_level_set() failed (%s)\n", libswd_error_string(res)); 255 | return ERROR_FAIL; 256 | } return new_swdlevel; 257 | } 258 | 259 | /** We will use OpenOCD's logging mechanisms to show LibSWD messages. 260 | * SWD can have different loglevel set than the OpenOCD itself, so we need to 261 | * log all messages at openocd level that will not block swd messages. 262 | * It is also possible to 'inherit' loglevel to swd from openocd. 263 | */ 264 | int libswd_log(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel, char *msg, ...){ 265 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 266 | if (loglevel > LIBSWD_LOGLEVEL_MAX) return LIBSWD_ERROR_PARAM; 267 | 268 | if (loglevel > libswdctx->config.loglevel) return LIBSWD_OK; 269 | va_list ap; 270 | va_start(ap, msg); 271 | // Calling OpenOCD log functions here will cause program crash (va recurrent). 272 | vprintf(msg, ap); 273 | va_end(ap); 274 | return LIBSWD_OK; 275 | } 276 | 277 | -------------------------------------------------------------------------------- /src/examples/libswd_drv_openocd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * 4 | * Driver Bridge between LibSWD and OpenOCD header file. 5 | * 6 | * Copyright (C) 2010-2011 Tomasz Boleslaw CEDRO 7 | * cederom@tlen.pl, http://www.tomek.cedro.info 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * 1. Redistributions of source code must retain the above copyright notice, 13 | * this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright notice, 15 | * this list of conditions and the following disclaimer in the documentation 16 | * and/or other materials provided with the distribution. 17 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 18 | * contributors may be used to endorse or promote products derived from this 19 | * software without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 26 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 29 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 32 | * 33 | * Written by Tomasz Boleslaw CEDRO , 2010-2011; 34 | * 35 | */ 36 | 37 | /** \file liblibswd_drv_openocd.h Driver Bridge between LibSWD and OpenOCD header file. */ 38 | 39 | #include 40 | 41 | int libswd_drv_mosi_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst); 42 | int libswd_drv_mosi_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst); 43 | int libswd_drv_miso_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst); 44 | int libswd_drv_miso_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst); 45 | int libswd_drv_mosi_trn(libswd_ctx_t *libswdctx, int bits); 46 | int libswd_drv_miso_trn(libswd_ctx_t *libswdctx, int bits); 47 | int libswd_log_level_inherit(libswd_ctx_t *libswdctx, int loglevel); 48 | int libswd_log(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel, char *msg, ...); 49 | 50 | -------------------------------------------------------------------------------- /src/examples/libswd_drv_urjtag.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * 4 | * Driver Bridge between LibSWD and UrJTAG. 5 | * 6 | * Copyright (C) 2010-2011, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 1. Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 17 | * contributors may be used to endorse or promote products derived from this 18 | * software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 25 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 28 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 30 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 31 | * 32 | * Written by Tomasz Boleslaw CEDRO , 2010-2011; 33 | * 34 | */ 35 | 36 | /** \file liblibswd_drv_urjtag.c Driver Bridge between LibSWD and UrJTAG. */ 37 | 38 | #include 39 | #include 40 | 41 | /** 42 | * Use UrJTAG's driver to write 8-bit data (char type). 43 | * MOSI (Master Output Slave Input) is a SWD Write Operation. 44 | * \param *libswdctx swd context to work on. 45 | * \param *cmd point to the actual command being sent. 46 | * \param *data points to the char data. 47 | * \bits tells how many bits to send (at most 8). 48 | * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first. 49 | * \return data count transferred, or negative LIBSWD_ERROR code on failure. 50 | */ 51 | int libswd_drv_mosi_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst){ 52 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 53 | if (bits<0 && bits>8) return LIBSWD_ERROR_PARAM; 54 | if (nLSBfirst!=0 && nLSBfirst!=1) return LIBSWD_ERROR_PARAM; 55 | 56 | static unsigned int i; 57 | static signed int res; 58 | static char misodata[8], mosidata[8]; 59 | 60 | //UrJTAG drivers shift data LSB-First. 61 | for (i=0;i<8;i++) mosidata[(nLSBfirst==LIBSWD_DIR_LSBFIRST)?(i):(7-i)]=((1<driver->device, bits, mosidata, misodata); 63 | if (res<0) return LIBSWD_ERROR_DRIVER; 64 | urj_tap_cable_flush((urj_cable_t *)libswdctx->driver->device, URJ_TAP_CABLE_COMPLETELY); 65 | return i; 66 | } 67 | 68 | /** 69 | * Use UrJTAG's driver to write 32-bit data (int type). 70 | * MOSI (Master Output Slave Input) is a SWD Write Operation. 71 | * \param *libswdctx swd context to work on. 72 | * \param *cmd point to the actual command being sent. 73 | * \param *data points to the char buffer array. 74 | * \bits tells how many bits to send (at most 32). 75 | * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first. 76 | * \return data count transferred, or negative LIBSWD_ERROR code on failure. 77 | */ 78 | int libswd_drv_mosi_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst){ 79 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 80 | if (bits<0 && bits>8) return LIBSWD_ERROR_PARAM; 81 | if (nLSBfirst!=0 && nLSBfirst!=1) return LIBSWD_ERROR_PARAM; 82 | 83 | static unsigned int i; 84 | static signed int res; 85 | static char misodata[32], mosidata[32]; 86 | 87 | //UrJTAG drivers shift data LSB-First. 88 | for (i=0;i<32;i++) mosidata[(nLSBfirst==LIBSWD_DIR_LSBFIRST)?(i):(31-i)]=((1<driver->device, bits, mosidata, misodata); 90 | if (res<0) return LIBSWD_ERROR_DRIVER; 91 | urj_tap_cable_flush((urj_cable_t *)libswdctx->driver->device, URJ_TAP_CABLE_COMPLETELY); 92 | return i; 93 | } 94 | 95 | /** 96 | * Use UrJTAG's driver to read 8-bit data (char type). 97 | * MISO (Master Input Slave Output) is a SWD Read Operation. 98 | * \param *libswdctx swd context to work on. 99 | * \param *cmd point to the actual command being sent. 100 | * \param *data points to the char buffer array. 101 | * \bits tells how many bits to send (at most 8). 102 | * \bits nLSBfirst tells the shift direction: 0 = LSB first, other MSB first. 103 | * \return data count transferred, or negative LIBSWD_ERROR code on failure. 104 | */ 105 | int libswd_drv_miso_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst){ 106 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 107 | if (bits<0 && bits>8) return LIBSWD_ERROR_PARAM; 108 | if (nLSBfirst!=0 && nLSBfirst!=1) return LIBSWD_ERROR_PARAM; 109 | 110 | static unsigned int i; 111 | static signed int res; 112 | static char misodata[8], mosidata[8]; 113 | 114 | res=urj_tap_cable_transfer((urj_cable_t *)libswdctx->driver->device, bits, mosidata, misodata); 115 | if (res<0) return LIBSWD_ERROR_DRIVER; 116 | urj_tap_cable_flush((urj_cable_t *)libswdctx->driver->device, URJ_TAP_CABLE_COMPLETELY); 117 | //Now we need to reconstruct the data byte from shifted in LSBfirst byte array. 118 | *data=0; 119 | for (i=0;i8) return LIBSWD_ERROR_PARAM; 136 | if (nLSBfirst!=0 && nLSBfirst!=1) return LIBSWD_ERROR_PARAM; 137 | 138 | static unsigned int i; 139 | static signed int res; 140 | static char misodata[32], mosidata[32]; 141 | 142 | res=urj_tap_cable_transfer((urj_cable_t *)libswdctx->driver->device, bits, mosidata, misodata); 143 | if (res<0) return LIBSWD_ERROR_DRIVER; 144 | urj_tap_cable_flush((urj_cable_t *)libswdctx->driver->device, URJ_TAP_CABLE_COMPLETELY); 145 | //Now we need to reconstruct the data byte from shifted in LSBfirst byte array. 146 | *data=0; 147 | for (i=0;iLIBSWD_TURNROUND_MAX_VAL) 160 | return LIBSWD_ERROR_TURNAROUND; 161 | 162 | int res; 163 | res=urj_tap_cable_set_signal((urj_cable_t *)libswdctx->driver->device, URJ_POD_CS_RnW, 0); 164 | if (res<0) return LIBSWD_ERROR_DRIVER; 165 | /* void urj_tap_cable_clock (urj_cable_t *cable, int tms, int tdi, int n); */ 166 | urj_tap_cable_clock((urj_cable_t *)libswdctx->driver->device, 1, 1, bits); 167 | 168 | return bits; 169 | } 170 | 171 | /** 172 | * This function sets interface buffers to MISO direction. 173 | * MISO (Master Input Slave Output) is a SWD Read operation. 174 | * \param *libswdctx is the swd context to work on. 175 | * \param bits specify how many clock cycles must be used for TRN. 176 | * \return number of bits transmitted or negative LIBSWD_ERROR code on failure. 177 | */ 178 | int libswd_drv_miso_trn(libswd_ctx_t *libswdctx, int bits){ 179 | if (bitsLIBSWD_TURNROUND_MAX_VAL) 180 | return LIBSWD_ERROR_TURNAROUND; 181 | 182 | static int res; 183 | 184 | res=urj_tap_cable_set_signal((urj_cable_t *)libswdctx->driver->device, URJ_POD_CS_RnW, URJ_POD_CS_RnW); 185 | if (res<0) return LIBSWD_ERROR_DRIVER; 186 | 187 | /* void urj_tap_cable_clock (urj_cable_t *cable, int tms, int tdi, int n); */ 188 | urj_tap_cable_clock((urj_cable_t *)libswdctx->driver->device, 1, 1, bits); 189 | 190 | return bits; 191 | } 192 | 193 | 194 | /** 195 | * Set debug level according to UrJTAG settings. 196 | * \param *libswdctx is the context to work on. 197 | * \param loglevel is the UrJTAG's lovleve to be transformed into LibSWD one. 198 | * \return LIBSWD_OK on success, negative LIBSWD_ERROR code on failure. 199 | */ 200 | int libswd_log_level_inherit(libswd_ctx_t *libswdctx, int loglevel){ 201 | if (libswdctx==NULL){ 202 | urj_log(URJ_LOG_LEVEL_DEBUG, "libswd_log_level_inherit(): SWD Context not (yet) initialized...\n"); 203 | return LIBSWD_OK; 204 | } 205 | 206 | libswd_loglevel_t new_swdlevel; 207 | switch (loglevel){ 208 | case URJ_LOG_LEVEL_ALL: 209 | case URJ_LOG_LEVEL_COMM: 210 | case URJ_LOG_LEVEL_DEBUG: 211 | new_swdlevel=LIBSWD_LOGLEVEL_DEBUG; 212 | break; 213 | case URJ_LOG_LEVEL_DETAIL: 214 | new_swdlevel=LIBSWD_LOGLEVEL_INFO; 215 | break; 216 | case URJ_LOG_LEVEL_NORMAL: 217 | new_swdlevel=LIBSWD_LOGLEVEL_NORMAL; 218 | break; 219 | case URJ_LOG_LEVEL_WARNING: 220 | new_swdlevel=LIBSWD_LOGLEVEL_WARNING; 221 | break; 222 | case URJ_LOG_LEVEL_ERROR: 223 | new_swdlevel=LIBSWD_LOGLEVEL_ERROR; 224 | break; 225 | case URJ_LOG_LEVEL_SILENT: 226 | new_swdlevel=LIBSWD_LOGLEVEL_SILENT; 227 | break; 228 | default: 229 | new_swdlevel=LIBSWD_LOGLEVEL_NORMAL; 230 | } 231 | 232 | int res=libswd_log_level_set(libswdctx, new_swdlevel); 233 | if (res<0) { 234 | urj_log(URJ_LOG_LEVEL_ERROR, "libswd_log_level_set() failed (%s)\n", libswd_error_string(res)); 235 | return URJ_ERROR_SYNTAX; 236 | } else return LIBSWD_OK; 237 | } 238 | 239 | 240 | -------------------------------------------------------------------------------- /src/examples/libswd_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id$ 3 | * 4 | * Serial Wire Debug Open API. 5 | * Simple Test Program. 6 | * 7 | * Copyright (C) 2010, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * 1. Redistributions of source code must retain the above copyright notice, 13 | * this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright notice, 15 | * this list of conditions and the following disclaimer in the documentation 16 | * and/or other materials provided with the distribution. 17 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 18 | * contributors may be used to endorse or promote products derived from this 19 | * software without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 26 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 29 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | * OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | * Written by Tomasz Boleslaw CEDRO , 2010; 34 | * 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | int main(int argc, char argv[]){ 42 | printf("Hello to SWD world, a simple SWD API and general test program.\n"); 43 | 44 | int i, x, res; 45 | unsigned char c, uc, uc2; 46 | char sc, sc2, par8, par32; 47 | 48 | printf("\n=> Bitswap test:\n"); 49 | i=0x01a0cede; 50 | c=0x6f; 51 | printf("C size %d bits, I size %d bits.\n", sizeof(c)*LIBSWD_DATA_BYTESIZE, sizeof(i)*LIBSWD_DATA_BYTESIZE); 52 | printf("Before bitswap: C=%s, I=%s\n", libswd_bin8_string(&c), libswd_bin32_string(&i)); 53 | libswd_bin8_bitswap(&c, LIBSWD_DATA_BYTESIZE); 54 | libswd_bin32_bitswap(&i, sizeof(i)*LIBSWD_DATA_BYTESIZE); 55 | printf("After bitswap : C=%s, I=%s\n", libswd_bin8_string(&c), libswd_bin32_string(&i)); 56 | 57 | printf("\n=> Parity test:\n"); 58 | for (x=0;x<=0xff;x++){ 59 | i=x*x*x*x; 60 | c=x; 61 | res=libswd_bin8_parity_even(&c, &par8); 62 | if (res<0) return res; 63 | res=libswd_bin32_parity_even(&c, &par32); 64 | if (res<0) return res; 65 | printf("C=%s P=%d | I=%s P=%d\n", libswd_bin8_string(&c), par8, libswd_bin32_string(&i), par32); 66 | } 67 | 68 | printf("\n=> Casting test:\n"); 69 | uc=10; 70 | sc=-10; 71 | printf("Signed char: %d, Unsigned char: %d\n", sc, uc); 72 | printf(" (char)unsigned : %d\n", (char)uc); 73 | printf(" (unsigned char)char: %d\n", (unsigned char)sc); 74 | printf(" unsigned = signed : %d\n", uc2=sc); 75 | printf(" signed = unsigned : %d\n", sc2=uc); 76 | printf(" (signed)(uns=sign) : %d\n", (signed char)(uc2=sc)); 77 | printf(" (unsigned)(sig=uns): %d\n", (unsigned char)(sc2=uc)); 78 | 79 | int *ip=NULL; 80 | char *cp=NULL; 81 | printf("\n=> Memory Allocation test:\n"); 82 | printf(" Before: IP=%8X, CP=%8X\n", ip, cp); 83 | ip=(int *)calloc(1,sizeof(ip)); 84 | cp=(char *)calloc(1,sizeof(cp)); 85 | printf(" After ip=(int *)calloc(1,sizeof(ip)) : %8X\n", ip); 86 | printf(" After cp=(char *)callow(1,sizeof(cp)): %8X\n", cp); 87 | free(ip); free(cp); 88 | ip=calloc(1,sizeof(ip)); 89 | cp=calloc(1,sizeof(cp)); 90 | printf(" After ip=calloc(1,sizeof(ip)): %8X\n", ip); 91 | printf(" After cp=calloc(1,sizeof(cp)): %8X\n", cp); 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /src/libswd_app.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Application Header File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 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. 18 | * 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.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_app.h */ 36 | 37 | #ifndef __LIBSWDAPP_H__ 38 | #define __LIBSWDAPP_H__ 39 | 40 | #include 41 | #if defined(__MINGW32__) || (defined(__APPLE__) && defined(__MACH__)) 42 | #include 43 | #else 44 | #include 45 | #endif 46 | 47 | #define LIBSWDAPP_INTERFACE_SIGNAL_NAME_MINLEN 1 48 | #define LIBSWDAPP_INTERFACE_SIGNAL_NAME_MAXLEN 32 49 | #define LIBSWDAPP_INTERFACE_NAME_MAXLEN 32 50 | #define LIBSWDAPP_INTERFACE_CONFIG_NAME_MAXLEN 32 51 | #define LIBSWDAPP_INTERFACE_VID_DEFAULT 0x0403 52 | #define LIBSWDAPP_INTERFACE_PID_DEFAULT 0xbbe2 53 | #define LIBSWDAPP_INTERFACE_NAME_DEFAULT "ktlink" 54 | 55 | #define LIBSWDAPP_CLI_HISTORY_FILENAME "/.libswd/libswdapp_cli_history" 56 | #define LIBSWDAPP_CLI_HISTORY_MAXLEN 1024 57 | 58 | typedef struct libswdapp_interface_signal { 59 | char *name; /// Signal name string. 60 | unsigned int mask; /// Mask value for selected signal. 61 | int value; /// Cached signal value. 62 | struct libswdapp_interface_signal *next; /// Next signal on the list. 63 | } libswdapp_interface_signal_t; 64 | 65 | typedef struct libswdapp_context { 66 | libswd_ctx_t *libswdctx; 67 | struct libswdapp_interface *interface; 68 | int loglevel; 69 | int retval; 70 | } libswdapp_context_t; 71 | 72 | typedef struct libswdapp_interface { 73 | char name[LIBSWDAPP_INTERFACE_NAME_MAXLEN]; 74 | char description[LIBSWDAPP_INTERFACE_NAME_MAXLEN]; 75 | void *ctx; 76 | void *handle; 77 | int vid, pid, vid_forced, pid_forced; 78 | libswdapp_interface_signal_t *signal; 79 | int (*init)(libswdapp_context_t *libswdappctx); 80 | int (*deinit)(libswdapp_context_t *libswdappctx); 81 | int (*set_freq)(libswdapp_context_t *libswdappctx, int freq); 82 | int (*bitbang)(libswdapp_context_t *libswdappctx, unsigned int bitmask, int GETnSET, unsigned int *value); 83 | int (*transfer_bits)(libswdapp_context_t *libswdappctx, int bits, char *mosidata, char *misodata, int nLSBfirst); 84 | int (*transfer_bytes)(libswdapp_context_t *libswdappctx, int bytes, char *mosidata, char *misodata, int nLSBfirst); 85 | char *sigsetupstr; 86 | // Below are CACHED values changed only by the interface functions. 87 | 88 | unsigned char latency; 89 | enum ftdi_interface ftdi_channel; 90 | int maxfrequency; /// Set by init. Used for frequency calculation. 91 | int frequency; /// This value shall only be changed by set_freq() routine. 92 | unsigned int chunksize; 93 | char initialized; 94 | unsigned int gpioval, gpiodir; 95 | } libswdapp_interface_t; 96 | 97 | typedef struct libswdapp_interface_config { 98 | char name[LIBSWDAPP_INTERFACE_NAME_MAXLEN]; 99 | char *description; 100 | char *sigsetupstr; 101 | int (*init)(libswdapp_context_t *libswdappctx); 102 | int (*deinit)(libswdapp_context_t *libswdappctx); 103 | int (*set_freq)(libswdapp_context_t *libswdappctx, int freq); 104 | int (*bitbang)(libswdapp_context_t *libswdappctx, unsigned int bitmask, int GETnSET, unsigned int *value); 105 | int (*transfer_bits)(libswdapp_context_t *libswdappctx, int bits, char *mosidata, char *misodata, int nLSBfirst); 106 | int (*transfer_bytes)(libswdapp_context_t *libswdappctx, int bytes, char *mosidata, char *misodata, int nLSBfirst); 107 | int vid, pid; 108 | unsigned char latency; 109 | int frequency, maxfrequency; 110 | unsigned int gpioval, gpiodir; //Shouldnt we use array? 111 | unsigned int chunksize; 112 | } libswdapp_interface_config_t; 113 | 114 | typedef enum libswdapp_interface_operation { 115 | OOCD_INTERFACE_SIGNAL_OPERATION_UNDEFINED = 0, 116 | OOCD_INTERFACE_SIGNAL_OPERATION_READ, 117 | OOCD_INTERFACE_SIGNAL_OPERATION_WRITE, 118 | OOCD_INTERFACE_SIGNAL_OPERATION_SET, 119 | OOCD_INTERFACE_SIGNAL_OPERATION_CLEAR 120 | } libswdapp_interface_operation_t; 121 | 122 | 123 | 124 | void libswdapp_shutdown(int sig); 125 | int libswdapp_interface_signal_add(libswdapp_context_t *libswdappctx, char *name, unsigned int mask); 126 | int libswdapp_interface_signal_del(libswdapp_context_t *libswdappctx, char *name); 127 | libswdapp_interface_signal_t *libswdapp_interface_signal_find(libswdapp_context_t *libswdappctx, char *name); 128 | int libswdapp_print_banner(void); 129 | int libswdapp_print_usage(void); 130 | int libswdapp_handle_command_signal_usage(void); 131 | int libswdapp_handle_command_signal(libswdapp_context_t *libswdappctx, char *cmd); 132 | int libswdapp_handle_command_interface_init(libswdapp_context_t *libswdappctx, char *cmd); 133 | int libswdapp_handle_command_flash_usage(void); 134 | int libswdapp_handle_command_flash(libswdapp_context_t *libswdappctx, char *command); 135 | 136 | int libswd_drv_mosi_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst); 137 | int libswd_drv_mosi_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst); 138 | int libswd_drv_miso_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst); 139 | int libswd_drv_miso_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst); 140 | int libswd_drv_mosi_trn(libswd_ctx_t *libswdctx, int clks); 141 | int libswd_drv_miso_trn(libswd_ctx_t *libswdctx, int clks); 142 | 143 | static int libswdapp_interface_ftdi_init(libswdapp_context_t *libswdappctx); 144 | static int libswdapp_interface_ftdi_deinit(libswdapp_context_t *libswdappctx); 145 | static int libswdapp_interface_ftdi_init_ktlink(libswdapp_context_t *libswdappctx); 146 | static int libswdapp_interface_ftdi_set_freq(libswdapp_context_t *libswdappctx, int freq); 147 | static int libswdapp_interface_ftdi_bitbang(libswdapp_context_t *libswdappctx, unsigned int bitmask, int GETnSET, unsigned int *value); 148 | static int libswdapp_interface_ftdi_transfer_bits(libswdapp_context_t *libswdappctx, int bits, char *mosidata, char *misodata, int nLSBfirst); 149 | static int libswdapp_interface_ftdi_transfer_bytes(libswdapp_context_t *libswdappctx, int bytes, char *mosidata, char *misodata, int nLSBfirst); 150 | 151 | static int libswdapp_interface_aftdi_init(libswdapp_context_t *libswdappctx); 152 | static int libswdapp_interface_aftdi_deinit(libswdapp_context_t *libswdappctx); 153 | static int libswdapp_interface_aftdi_init_ktlink(libswdapp_context_t *libswdappctx); 154 | static int libswdapp_interface_aftdi_set_freq(libswdapp_context_t *libswdappctx, int freq); 155 | static int libswdapp_interface_aftdi_bitbang(libswdapp_context_t *libswdappctx, unsigned int bitmask, int GETnSET, unsigned int *value); 156 | static int libswdapp_interface_aftdi_transfer_bits(libswdapp_context_t *libswdappctx, int bits, char *mosidata, char *misodata, int nLSBfirst); 157 | static int libswdapp_interface_aftdi_transfer_bytes(libswdapp_context_t *libswdappctx, int bytes, char *mosidata, char *misodata, int nLSBfirst); 158 | 159 | int libswd_log(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel, char *msg, ...); 160 | 161 | static const libswdapp_interface_config_t libswdapp_interface_configs[] = { 162 | { 163 | .name = "ktlink", 164 | .description = "KT-LINK FT2232H based device (using LibFTDI)", 165 | .init = libswdapp_interface_ftdi_init_ktlink, 166 | .deinit = libswdapp_interface_ftdi_deinit, 167 | .set_freq = libswdapp_interface_ftdi_set_freq, 168 | .bitbang = libswdapp_interface_ftdi_bitbang, 169 | .transfer_bits = libswdapp_interface_ftdi_transfer_bits, 170 | .transfer_bytes = libswdapp_interface_ftdi_transfer_bytes, 171 | .vid = 0x0403, 172 | .pid = 0xbbe2, 173 | .latency = 1, 174 | .maxfrequency = 30000000, 175 | .frequency = 1000000, 176 | .chunksize = 32768, 177 | .sigsetupstr = "signal add:CLK=0x0001 add:MOSI=0x0002 add:MISO=0x0004 add:TMS=0x0008 add:nSWDsel=0x0020 add:SRSTin=0x0040 add:RTCK=0x0080 add:TRST=0x0100 add:SRST=0x0200 add:nTRSTen=0x0400 add:nSRSTen=0x0800 add:RnW=0x1000 add:nMOSIen=0x2000 add:nCLKen=0x4000 add:LED=0x8000 CLK=lo MOSI=lo SRST=hi nCLKen=lo nSWDsel=lo RnW=lo nSRSTen=lo LED=lo MISO SRSTin RTCK", 178 | }, 179 | { 180 | .name = "ktlink-async", 181 | .description = "KT-LINK FT2232H based device (using async LibUSB)", 182 | .init = libswdapp_interface_aftdi_init_ktlink, 183 | .deinit = libswdapp_interface_aftdi_deinit, 184 | .set_freq = libswdapp_interface_aftdi_set_freq, 185 | .bitbang = libswdapp_interface_aftdi_bitbang, 186 | .transfer_bits = libswdapp_interface_aftdi_transfer_bits, 187 | .transfer_bytes = libswdapp_interface_aftdi_transfer_bytes, 188 | .vid = 0x0403, 189 | .pid = 0xbbe2, 190 | .latency = 1, 191 | .maxfrequency = 30000000, 192 | .frequency = 1000000, 193 | .chunksize = 32768, 194 | .sigsetupstr = "signal add:CLK=0x0001 add:MOSI=0x0002 add:MISO=0x0004 add:TMS=0x0008 add:nSWDsel=0x0020 add:SRSTin=0x0040 add:RTCK=0x0080 add:TRST=0x0100 add:SRST=0x0200 add:nTRSTen=0x0400 add:nSRSTen=0x0800 add:RnW=0x1000 add:nMOSIen=0x2000 add:nCLKen=0x4000 add:LED=0x8000 CLK=lo MOSI=lo SRST=hi nCLKen=lo nSWDsel=lo RnW=lo nSRSTen=lo LED=lo MISO SRSTin RTCK", 195 | }, 196 | 197 | { 198 | .name = '\0', 199 | } 200 | }; 201 | 202 | typedef struct libswdapp_flash_stm32f1_memmap 203 | { 204 | int page_start; 205 | int page_size; 206 | int page_end; 207 | int system_memory_start; 208 | int system_memory_size; 209 | int option_bytes_start; 210 | int option_bytes_size; 211 | int FLASH_ACR_ADDR; 212 | int FLASH_KEYR_ADDR; 213 | int FLASH_OPTKEYR_ADDR; 214 | int FLASH_SR_ADDR; 215 | int FLASH_CR_ADDR; 216 | int FLASH_AR_ADDR; 217 | int FLASH_OBR_ADDR; 218 | int FLASH_WRPR_ADDR; 219 | int idcode[]; 220 | } libswdapp_flash_stm32f1_memmap_t; 221 | 222 | static const libswdapp_flash_stm32f1_memmap_t libswdapp_flash_stm321f_lowdensity = { 223 | .page_start = 0x08000000, 224 | .page_size = 0x000003FF, 225 | .page_end = 0x08007FFF, 226 | .system_memory_start = 0x1FFFF000, 227 | .system_memory_size = 0x000007FF, 228 | .option_bytes_start = 0x1FFFF800, 229 | .option_bytes_size = 0x0000000F, 230 | .FLASH_ACR_ADDR = 0x40022000, 231 | .FLASH_KEYR_ADDR = 0x40022004, 232 | .FLASH_OPTKEYR_ADDR = 0x40022008, 233 | .FLASH_SR_ADDR = 0x4002200C, 234 | .FLASH_CR_ADDR = 0x40022010, 235 | .FLASH_AR_ADDR = 0x40022014, 236 | .FLASH_OBR_ADDR = 0x4002201C, 237 | .FLASH_WRPR_ADDR = 0x40022020, 238 | .idcode = {0} 239 | }; 240 | 241 | static const libswdapp_flash_stm32f1_memmap_t libswdapp_flash_stm321f_mediumdensity = { 242 | .page_start = 0x08000000, 243 | .page_size = 0x000003FF, 244 | .page_end = 0x0801FFFF, 245 | .system_memory_start = 0x1FFFF000, 246 | .system_memory_size = 0x000007FF, 247 | .option_bytes_start = 0x1FFFF800, 248 | .option_bytes_size = 0x0000000F, 249 | .FLASH_ACR_ADDR = 0x40022000, 250 | .FLASH_KEYR_ADDR = 0x40022004, 251 | .FLASH_OPTKEYR_ADDR = 0x40022008, 252 | .FLASH_SR_ADDR = 0x4002200C, 253 | .FLASH_CR_ADDR = 0x40022010, 254 | .FLASH_AR_ADDR = 0x40022014, 255 | .FLASH_OBR_ADDR = 0x4002201C, 256 | .FLASH_WRPR_ADDR = 0x40022020, 257 | .idcode = {0} 258 | }; 259 | 260 | static const libswdapp_flash_stm32f1_memmap_t libswdapp_flash_stm321f_highdensity = { 261 | .page_start = 0x08000000, 262 | .page_size = 0x000007FF, 263 | .page_end = 0x0807FFFF, 264 | .system_memory_start = 0x1FFFF000, 265 | .system_memory_size = 0x000007FF, 266 | .option_bytes_start = 0x1FFFF800, 267 | .option_bytes_size = 0x0000000F, 268 | .FLASH_ACR_ADDR = 0x40022000, 269 | .FLASH_KEYR_ADDR = 0x40022004, 270 | .FLASH_OPTKEYR_ADDR = 0x40022008, 271 | .FLASH_SR_ADDR = 0x4002200C, 272 | .FLASH_CR_ADDR = 0x40022010, 273 | .FLASH_AR_ADDR = 0x40022014, 274 | .FLASH_OBR_ADDR = 0x4002201C, 275 | .FLASH_WRPR_ADDR = 0x40022020, 276 | .idcode = {0x1BA01477,0} 277 | }; 278 | 279 | static const libswdapp_flash_stm32f1_memmap_t libswdapp_flash_stm321f_connectivityline = { 280 | .page_start = 0x08000000, 281 | .page_size = 0x000007FF, 282 | .page_end = 0x0803FFFF, 283 | .system_memory_start = 0x1FFFB000, 284 | .system_memory_size = 0x000047FF, 285 | .option_bytes_start = 0x1FFFF800, 286 | .option_bytes_size = 0x0000000F, 287 | .FLASH_ACR_ADDR = 0x40022000, 288 | .FLASH_KEYR_ADDR = 0x40022004, 289 | .FLASH_OPTKEYR_ADDR = 0x40022008, 290 | .FLASH_SR_ADDR = 0x4002200C, 291 | .FLASH_CR_ADDR = 0x40022010, 292 | .FLASH_AR_ADDR = 0x40022014, 293 | .FLASH_OBR_ADDR = 0x4002201C, 294 | .FLASH_WRPR_ADDR = 0x40022020, 295 | .idcode = {0} 296 | }; 297 | 298 | static const libswdapp_flash_stm32f1_memmap_t *libswdapp_flash_stm32f1_devices[] = { 299 | &libswdapp_flash_stm321f_lowdensity, 300 | &libswdapp_flash_stm321f_mediumdensity, 301 | &libswdapp_flash_stm321f_highdensity, 302 | &libswdapp_flash_stm321f_connectivityline, 303 | NULL 304 | }; 305 | 306 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_OBR_RDPRT_VAL 0x000000A5 307 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_KEYR_KEY1_VAL 0x45670123 308 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_KEYR_KEY2_VAL 0xCDEF89AB 309 | 310 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_ACR_PRFTBS (1<<5) 311 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_ACR_PRFTBE (1<<4) 312 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_ACR_HLFCYA (1<<3) 313 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_ACR_LATENCY (7<<2) 314 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_SR_EOP (1<<5) 315 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_SR_WRPRTERR (1<<4) 316 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_SR_PGERR (1<<2) 317 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_SR_BSY (1<<0) 318 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_CR_EOPIE (1<<12) 319 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_CR_ERRIE (1<<10) 320 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_CR_OPTWRE (1<<9) 321 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_CR_LOCK (1<<7) 322 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_CR_STRT (1<<6) 323 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_CR_OPTER (1<<5) 324 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_CR_OPTPG (1<<4) 325 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_CR_MER (1<<2) 326 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_CR_PER (1<<1) 327 | #define LIBSWDAPP_FLASH_STM32F1_FLASH_CR_PG (1<<0) 328 | 329 | #endif 330 | -------------------------------------------------------------------------------- /src/libswd_bin.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 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. 18 | * 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.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_bin.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_bin Binary operations helper functions. 41 | * @{ 42 | ******************************************************************************/ 43 | 44 | /** 45 | * Data parity calculator, calculates even parity on char type. 46 | * \param *data source data pointer. 47 | * \param *parity resulting data pointer. 48 | * \return negative value on error, 0 or 1 as parity result. 49 | */ 50 | int libswd_bin8_parity_even(char *data, char *parity){ 51 | char i; 52 | unsigned char test=*data; 53 | *parity=0; 54 | for (i=0;i<=8;i++) *parity ^= ((test>>i)&1); 55 | if (*parity<0 || *parity>1) return LIBSWD_ERROR_PARITY; 56 | return (int)*parity; 57 | } 58 | 59 | /** 60 | * Data parity calculator, calculates even parity on integer type. 61 | * \param *data source data pointer. 62 | * \param *parity resulting data pointer. 63 | * \return negative value on error, 0 or 1 as parity result. 64 | */ 65 | int libswd_bin32_parity_even(int *data, char *parity){ 66 | int i; 67 | unsigned int test=*data; 68 | *parity=0; 69 | for (i=0;i<32;i++) *parity ^= ((test>>i)&1); 70 | if (*parity<0 || *parity>1) return LIBSWD_ERROR_PARITY; 71 | return (int)*parity; 72 | } 73 | 74 | /** 75 | * Prints binary data of a char value on the screen. 76 | * \param *data source data pointer. 77 | * \return number of characters printed. 78 | */ 79 | int libswd_bin8_print(char *data){ 80 | unsigned char i, bits=*data; 81 | for (i=0;i<8;i++) putchar(((bits<8) return LIBSWD_ERROR_PARAM; 131 | unsigned char bit, result=0; //res must be unsigned for proper shifting result 132 | #ifdef __SWDDEBUG__ 133 | printf("|LIBSWD_DEBUG: libswd_bin8_bitswap(%02X, %d);\n", *buffer, bitcount); 134 | #endif 135 | for (bit=0;bit>bit)&1)?1:0); 137 | #ifdef __SWDDEBUG__ 138 | printf("|LIBSWD_DEBUG: libswd_bin8_bitswap: in=%02X out=%02X bit=%d\n", *buffer, result, bit); 139 | #endif 140 | } 141 | *buffer=result; 142 | return bit; 143 | } 144 | 145 | /** 146 | * Bit swap helper function that reverse bit order in int *buffer. 147 | * Most Significant Bit becomes Least Significant Bit. 148 | * It is possible to swap only n-bits from int (32-bit) *buffer. 149 | * \param *buffer unsigned char (32-bit) data pointer. 150 | * \param bitcount how many bits to swap. 151 | * \return swapped bit count (positive) or error code (negative). 152 | */ 153 | int libswd_bin32_bitswap(unsigned int *buffer, unsigned int bitcount){ 154 | if (buffer==NULL) return LIBSWD_ERROR_NULLPOINTER; 155 | if (bitcount>32) return LIBSWD_ERROR_PARAM; 156 | unsigned int bit, result=0; //res must be unsigned for proper shifting result 157 | #ifdef __SWDDEBUG__ 158 | printf("|LIBSWD_DEBUG: libswd_bin32_bitswap(%08X, %d);\n", *buffer, bitcount); 159 | #endif 160 | for (bit=0;bit>bit)&1)?1:0); 162 | #ifdef __SWDDEBUG__ 163 | printf("|LIBSWD_DEBUG: libswd_bin32_bitswap: in=%08X out=%08X bit=%d\n", *buffer, result, bit); 164 | #endif 165 | } 166 | *buffer=result; 167 | return bit; 168 | } 169 | 170 | /** @} */ 171 | -------------------------------------------------------------------------------- /src/libswd_bitgen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 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. 18 | * 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.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_bitgen.c */ 36 | 37 | #include 38 | 39 | 40 | /******************************************************************************* 41 | * \defgroup libswd_bitgen SWD Bitstream / Packet Payload generation routines. 42 | * @{ 43 | ******************************************************************************/ 44 | 45 | /** Generate 8-bit SWD-REQUEST packet contents with provided parameters. 46 | * Note that parity bit value is calculated automatically. 47 | * Note that Request is also sent LSB-First so diagrams are wrapped! 48 | * \param *libswdctx swd context pointer. 49 | * \param *APnDP AccessPort (high) or DebugPort (low) access type pointer. 50 | * \param *RnW Read (high) or Write (low) operation type pointer. 51 | * \param *addr target register address value pointer. 52 | * \param *request pointer where to store resulting packet. 53 | * \return number of generated packets (1), or LIBSWD_ERROR_CODE on failure. 54 | */ 55 | int libswd_bitgen8_request(libswd_ctx_t *libswdctx, char *APnDP, char *RnW, char *addr, char *request){ 56 | /* Verify function parameters.*/ 57 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 58 | if (*APnDP!=0 && *APnDP!=1) return LIBSWD_ERROR_APnDP; 59 | if (*RnW!=0 && *RnW!=1) return LIBSWD_ERROR_RnW; 60 | if (*addrLIBSWD_ADDR_MAXVAL) return LIBSWD_ERROR_ADDR; 61 | 62 | /* Build request header content. */ 63 | unsigned char reqhdr=0; 64 | char parity, req; 65 | int res; 66 | reqhdr|=(((*addr&(1<<2))?1:0)<1) return LIBSWD_ERROR_PARITY; 74 | reqhdr|=(res<, 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_bus.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_bus SWD Bus Primitives: Request, ACK, Data+Parity, Direction. 41 | * These functions generate payloads and queue up all elements/commands 42 | * necessary to perform requested operations on the SWD bus. Depending 43 | * on "operation" type, elements can be only enqueued on the queue (operation == 44 | * LIBSWD_OPERATION_ENQUEUE) or queued and then flushed into hardware driver 45 | * (operation == LIBSWD_OPERATION_EXECUTE) for immediate effect on the target. 46 | * Other operations are not allowed for these functions and will produce error. 47 | * This group of functions is intelligent, so they will react on errors, when 48 | * operation is LIBSWD_OPERATION_EXECUTE, otherwise simply queue up transaction. 49 | * These functions are primitives to use by high level functions operating 50 | * on the Debug Port (DP) or the Access Port (AP). 51 | * @{ 52 | ******************************************************************************/ 53 | 54 | /** Append command queue with TRN WRITE/MOSI, if previous command was READ/MISO. 55 | * \param *libswdctx swd context pointer. 56 | * \return number of elements appended, or LIBSWD_ERROR_CODE on failure. 57 | */ 58 | int libswd_bus_setdir_mosi(libswd_ctx_t *libswdctx){ 59 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 60 | int res, cmdcnt=0; 61 | libswd_cmd_t *cmdqtail=libswd_cmdq_find_tail(libswdctx->cmdq); 62 | if (cmdqtail==NULL) return LIBSWD_ERROR_QUEUE; 63 | if ( cmdqtail->prev==NULL || (cmdqtail->cmdtype*LIBSWD_CMDTYPE_MOSI<0) ) { 64 | res=libswd_cmd_enqueue_mosi_trn(libswdctx); 65 | if (res<1) return res; 66 | cmdcnt=+res; 67 | } 68 | return cmdcnt; 69 | } 70 | 71 | /** Append command queue with TRN READ/MISO, if previous command was WRITE/MOSI. 72 | * \param *libswdctx swd context pointer. 73 | * \return number of elements appended, or LIBSWD_ERROR_CODE on failure. 74 | */ 75 | int libswd_bus_setdir_miso(libswd_ctx_t *libswdctx){ 76 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 77 | int res, cmdcnt=0; 78 | libswd_cmd_t *cmdqtail=libswd_cmdq_find_tail(libswdctx->cmdq); 79 | if (cmdqtail==NULL) return LIBSWD_ERROR_QUEUE; 80 | if (cmdqtail->prev==NULL || (cmdqtail->cmdtype*LIBSWD_CMDTYPE_MISO<0) ) { 81 | res=libswd_cmd_enqueue_miso_trn(libswdctx); 82 | if (res<0) return res; 83 | cmdcnt=+res; 84 | } 85 | return cmdcnt; 86 | } 87 | 88 | /** Perform Request (write provided raw byte). 89 | * \param *libswdctx swd context pointer. 90 | * \param operation type of action to perform with generated request. 91 | * \param *request request packet raw data 92 | * \return number of commands processed, or LIBSWD_ERROR_CODE on failure. 93 | */ 94 | int libswd_bus_write_request_raw 95 | (libswd_ctx_t *libswdctx, libswd_operation_t operation, char *request){ 96 | /* Verify function parameters.*/ 97 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 98 | if (request==NULL) return LIBSWD_ERROR_NULLPOINTER; 99 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 100 | return LIBSWD_ERROR_BADOPCODE; 101 | 102 | int res, qcmdcnt=0, tcmdcnt=0; 103 | 104 | /* Bus direction must be MOSI. */ 105 | res=libswd_bus_setdir_mosi(libswdctx); 106 | if (res<0) return res; 107 | qcmdcnt=+res; 108 | 109 | /* Append request command to the queue. */ 110 | res=libswd_cmd_enqueue_mosi_request(libswdctx, request); 111 | if (res<0) return res; 112 | qcmdcnt+=res; 113 | 114 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 115 | return qcmdcnt; 116 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 117 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 118 | if (res<0) return res; 119 | tcmdcnt=+res; 120 | return qcmdcnt+tcmdcnt; 121 | } else return LIBSWD_ERROR_BADOPCODE; 122 | } 123 | 124 | /** Perform Request. 125 | * \param *libswdctx swd context pointer. 126 | * \param operation type of action to perform with generated request. 127 | * \param *APnDP AccessPort (high) or DebugPort (low) access value pointer. 128 | * \param *RnW Read (high) or Write (low) access value pointer. 129 | * \param *addr target register address value pointer. 130 | * \return number of commands processed, or LIBSWD_ERROR_CODE on failure. 131 | */ 132 | int libswd_bus_write_request 133 | (libswd_ctx_t *libswdctx, libswd_operation_t operation, char *APnDP, char *RnW, char *addr){ 134 | /* Verify function parameters.*/ 135 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 136 | if (*APnDP!=0 && *APnDP!=1) return LIBSWD_ERROR_APnDP; 137 | if (*RnW!=0 && *RnW!=1) return LIBSWD_ERROR_RnW; 138 | if (*addrLIBSWD_ADDR_MAXVAL) return LIBSWD_ERROR_ADDR; 139 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 140 | return LIBSWD_ERROR_BADOPCODE; 141 | 142 | int res, qcmdcnt=0, tcmdcnt=0; 143 | char request; 144 | 145 | /* Generate request bitstream. */ 146 | res=libswd_bitgen8_request(libswdctx, APnDP, RnW, addr, &request); 147 | if (res<0) return res; 148 | 149 | /* Bus direction must be MOSI. */ 150 | res=libswd_bus_setdir_mosi(libswdctx); 151 | if (res<0) return res; 152 | qcmdcnt=+res; 153 | 154 | /* Append request command to the queue. */ 155 | res=libswd_cmd_enqueue_mosi_request(libswdctx, &request); 156 | if (res<0) return res; 157 | qcmdcnt+=res; 158 | 159 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 160 | return qcmdcnt; 161 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 162 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 163 | if (res<0) return res; 164 | tcmdcnt=+res; 165 | return qcmdcnt+tcmdcnt; 166 | } else return LIBSWD_ERROR_BADOPCODE; 167 | } 168 | 169 | /** Perform ACK read into *ack and verify received data. 170 | * \param *libswdctx swd context pointer. 171 | * \param operation type of action to perform with generated request. 172 | * \param *ack pointer to the result location. 173 | * \return number of commands processed, or LIBSWD_ERROR_CODE on failure. 174 | */ 175 | int libswd_bus_read_ack(libswd_ctx_t *libswdctx, libswd_operation_t operation, char **ack){ 176 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 177 | if (ack==NULL) return LIBSWD_ERROR_NULLPOINTER; 178 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 179 | return LIBSWD_ERROR_BADOPCODE; 180 | 181 | int res, qcmdcnt=0, tcmdcnt=0; 182 | libswd_cmd_t *tmpcmdq, *cmdqtail; 183 | 184 | /* ACK can only show after REQ_MOSI,TRN_MISO sequence. */ 185 | cmdqtail=libswd_cmdq_find_tail(libswdctx->cmdq); 186 | if (cmdqtail==NULL) return LIBSWD_ERROR_QUEUE; 187 | if (cmdqtail->prev==NULL) return LIBSWD_ERROR_ACKORDER; 188 | /* Check if there is REQ->TRN sequence at the command queue tail. */ 189 | if (cmdqtail->prev->cmdtype!=LIBSWD_CMDTYPE_MOSI_REQUEST 190 | && cmdqtail->cmdtype!=LIBSWD_CMDTYPE_MISO_TRN){ 191 | /* If not, there should be at least REQ. */ 192 | if (cmdqtail->cmdtype!=LIBSWD_CMDTYPE_MOSI_REQUEST){ 193 | return LIBSWD_ERROR_ACKORDER; 194 | } else { 195 | /* TRN was found at queue tail, so we need to append TRN_MISO command. */ 196 | res=libswd_bus_setdir_miso(libswdctx); 197 | if (res<0) return res; 198 | qcmdcnt=+res; 199 | } 200 | } 201 | 202 | res=libswd_cmd_enqueue_miso_ack(libswdctx, ack); 203 | if (res<0) return res; 204 | qcmdcnt=+res; 205 | 206 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 207 | return qcmdcnt; 208 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 209 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 210 | if (res<0) return res; 211 | tcmdcnt+=res; 212 | } else return LIBSWD_ERROR_BADOPCODE; 213 | 214 | /* Now verify the read result and return/pass error code if necessary. */ 215 | 216 | /* Use temporary queue pointer for context queue operations.*/ 217 | tmpcmdq=libswdctx->cmdq; 218 | /* Search backward for ACK command on the queue (ack we have just appended). */ 219 | while (tmpcmdq->cmdtype!=LIBSWD_CMDTYPE_MISO_ACK){ 220 | if (tmpcmdq->prev==NULL) return LIBSWD_ERROR_ACKMISSING; 221 | tmpcmdq=tmpcmdq->prev; 222 | } 223 | /* If command was found and executed, read received ACK code, or error code. */ 224 | if (tmpcmdq->cmdtype==LIBSWD_CMDTYPE_MISO_ACK && tmpcmdq->done){ 225 | /* Verify data address found on the queue, with pointer selected before run.*/ 226 | if (&tmpcmdq->ack!=*ack) return LIBSWD_ERROR_ACKMISMATCH; 227 | return qcmdcnt+tcmdcnt; 228 | } else return LIBSWD_ERROR_ACKNOTDONE; 229 | } 230 | 231 | /** Perform (MOSI) data write with provided parity value. 232 | * \param *libswdctx swd context pointer. 233 | * \param operation type of action to perform on generated command. 234 | * \param *data payload value pointer. 235 | * \param *parity payload parity value pointer. 236 | * \return number of elements processed, or LIBSWD_ERROR_CODE on failure. 237 | */ 238 | int libswd_bus_write_data_p 239 | (libswd_ctx_t *libswdctx, libswd_operation_t operation, int *data, char *parity){ 240 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 241 | if (data==NULL || parity==NULL) return LIBSWD_ERROR_NULLPOINTER; 242 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 243 | return LIBSWD_ERROR_BADOPCODE; 244 | 245 | int res, qcmdcnt=0, tcmdcnt=0; 246 | 247 | res=libswd_bus_setdir_mosi(libswdctx); 248 | if (res<0) return res; 249 | qcmdcnt=+res; 250 | 251 | res=libswd_cmd_enqueue_mosi_data_p(libswdctx, data, parity); 252 | if (res<0) return res; 253 | qcmdcnt=+res; 254 | 255 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 256 | return qcmdcnt; 257 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 258 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 259 | if (res<0) return res; 260 | tcmdcnt=+res; 261 | return qcmdcnt+tcmdcnt; 262 | } else return LIBSWD_ERROR_BADOPCODE; 263 | } 264 | 265 | 266 | /** Perform (MOSI) data write with automatic parity calculation. 267 | * \param *libswdctx swd context pointer. 268 | * \param operation type of action to perform on generated command. 269 | * \param *data payload value pointer. 270 | * \return number of elements processed, or LIBSWD_ERROR_CODE on failure. 271 | */ 272 | int libswd_bus_write_data_ap(libswd_ctx_t *libswdctx, libswd_operation_t operation, int *data){ 273 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 274 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 275 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 276 | return LIBSWD_ERROR_BADOPCODE; 277 | 278 | int res, qcmdcnt=0, tcmdcnt=0; 279 | 280 | res=libswd_bus_setdir_mosi(libswdctx); 281 | if (res<0) return res; 282 | qcmdcnt=+res; 283 | 284 | res=libswd_cmd_enqueue_mosi_data_ap(libswdctx, data); 285 | if (res<0) return res; 286 | qcmdcnt=+res; 287 | 288 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 289 | return qcmdcnt; 290 | } else if (operation==LIBSWD_OPERATION_EXECUTE) { 291 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 292 | if (res<0) return res; 293 | tcmdcnt=+res; 294 | return qcmdcnt+tcmdcnt; 295 | } else return LIBSWD_ERROR_BADOPCODE; 296 | } 297 | 298 | /** Perform (MISO) data read. 299 | * \param *libswdctx swd context pointer. 300 | * \param operation type of action to perform on generated command. 301 | * \param *data payload value pointer. 302 | * \param *parity payload parity value pointer. 303 | * \return number of elements processed, or LIBSWD_ERROR_CODE on failure. 304 | */ 305 | int libswd_bus_read_data_p(libswd_ctx_t *libswdctx, libswd_operation_t operation, int **data, char **parity){ 306 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 307 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 308 | return LIBSWD_ERROR_BADOPCODE; 309 | 310 | int res, qcmdcnt=0, tcmdcnt=0; 311 | libswd_cmd_t *tmpcmdq; 312 | 313 | res=libswd_bus_setdir_miso(libswdctx); 314 | if (res<0) return res; 315 | qcmdcnt=+res; 316 | 317 | res=libswd_cmd_enqueue_miso_data_p(libswdctx, data, parity); 318 | if (res<0) return res; 319 | qcmdcnt=+res; 320 | 321 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 322 | return qcmdcnt; 323 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 324 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 325 | if (res<2) return res; 326 | tcmdcnt+=res; 327 | } else return LIBSWD_ERROR_BADOPCODE; 328 | 329 | /* Now verify the read result and return error if necessary. 330 | * Maybe iterative approach should be applied, not only last elemnt found..? */ 331 | 332 | /* Use temporary queue pointer for context queue operations.*/ 333 | tmpcmdq=libswdctx->cmdq; 334 | /* Search backward for our MISO_DATA command on the queue. */ 335 | while (tmpcmdq->cmdtype!=LIBSWD_CMDTYPE_MISO_DATA){ 336 | if (tmpcmdq->prev==NULL) return LIBSWD_ERROR_NODATACMD; 337 | tmpcmdq=tmpcmdq->prev; 338 | } 339 | /* There should be parity bit (command) just after data (command). */ 340 | if (tmpcmdq->next->cmdtype!=LIBSWD_CMDTYPE_MISO_PARITY) 341 | return LIBSWD_ERROR_NOPARITYCMD; 342 | /* If command found and executed, verify if data points to correct address. */ 343 | if (tmpcmdq->cmdtype==LIBSWD_CMDTYPE_MISO_DATA && tmpcmdq->done){ 344 | if (tmpcmdq->next->cmdtype==LIBSWD_CMDTYPE_MISO_PARITY && tmpcmdq->next->done){ 345 | if (*data!=&tmpcmdq->misodata) return LIBSWD_ERROR_DATAPTR; 346 | if (*parity!=&tmpcmdq->next->parity) return LIBSWD_ERROR_PARITYPTR; 347 | return qcmdcnt+tcmdcnt; 348 | } else return LIBSWD_ERROR_NOTDONE; 349 | } 350 | return LIBSWD_OK; 351 | } 352 | 353 | /** Write CONTROL byte to the Target's DAP. 354 | * \param *libswdctx swd context. 355 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 356 | * \param *ctlmsg byte/char array that contains control payload. 357 | * \param len number of bytes in the *ctlmsg to send. 358 | * \return number of bytes sent or LIBSWD_ERROR_CODE on failure. 359 | */ 360 | int libswd_bus_write_control(libswd_ctx_t *libswdctx, libswd_operation_t operation, char *ctlmsg, int len){ 361 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 362 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 363 | return LIBSWD_ERROR_BADOPCODE; 364 | if (ctlmsg==NULL) return LIBSWD_ERROR_NULLPOINTER; 365 | if (len<1 && len>libswdctx->config.maxcmdqlen) return LIBSWD_ERROR_PARAM; 366 | 367 | int res, qcmdcnt=0, tcmdcnt=0; 368 | 369 | /* Make sure that bus is in MOSI state. */ 370 | res=libswd_bus_setdir_mosi(libswdctx); 371 | if (res<0) return res; 372 | qcmdcnt=+res; 373 | 374 | res=libswd_cmd_enqueue_mosi_control(libswdctx, ctlmsg, len); 375 | if (res<0) return res; 376 | qcmdcnt=+res; 377 | 378 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 379 | return qcmdcnt; 380 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 381 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 382 | if (res<0) return res; 383 | tcmdcnt+=res; 384 | } else return LIBSWD_ERROR_BADOPCODE; 385 | return LIBSWD_OK; 386 | } 387 | 388 | /** @} */ 389 | -------------------------------------------------------------------------------- /src/libswd_cli.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Command Line Interface Body File. 4 | * 5 | * Copyright (C) 2010-2014, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 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. 18 | * 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.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2014; 32 | * 33 | */ 34 | 35 | /** \file libswd_cli.c */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | /******************************************************************************* 44 | * \defgroup libswd_cli Command Line Interface functions. 45 | * @{ 46 | ******************************************************************************/ 47 | 48 | int libswd_cli_print_usage(libswd_ctx_t *libswdctx) 49 | { 50 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLPOINTER; 51 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: Available LibSWD CLI commands:\n"); 52 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [h]elp / [?]\n"); 53 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [i]nit [dap]|memap|debug\n"); 54 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [l]oglevel \n"); 55 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [r]ead [d]ap/[a]p 0xAddress\n"); 56 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [w]rite [d]ap/[a]p 0xAddress 0x32BitData\n"); 57 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [r]ead [m]emap 0xAddress <0xCount>|4 \n"); 58 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [w]rite [m]emap 0xAddress 0xData[]|filename\n"); 59 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "\n"); 60 | return LIBSWD_OK; 61 | } 62 | 63 | /** Command Line Interface parse and execution engine. 64 | * Multiple commands invocation is possible, split by '\n' or ';' characters. 65 | * \param *libswdctx libswd context 66 | * \param *cmd command string pointer 67 | * \return LIBSWD_ERROR_OK on success or negative value error code otherwise. 68 | */ 69 | int libswd_cli(libswd_ctx_t *libswdctx, char *command) 70 | { 71 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 72 | "LIBSWD_D: libswd_cli(libswdctx=@%p, command=@%p/\"%s\"): Entring function...\n", 73 | (void*)libswdctx, (void*)command, command); 74 | 75 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 76 | if (command==NULL) return LIBSWD_ERROR_NULLPOINTER; 77 | 78 | int res, retval, addrstart, addrstop, count, data, *data32, i, j; 79 | char *cmd, *thiscommand, ap, *filename, *endptr; 80 | 81 | while ( (thiscommand=strsep(&command,"\n;")) ) 82 | { 83 | while ( (cmd=strsep(&thiscommand," ")) ) 84 | { 85 | // Strip heading and trailing spaces. 86 | if (cmd && thiscommand) if (!cmd[0] && thiscommand[0]) continue; 87 | if (cmd && thiscommand) if (!cmd[0] && !thiscommand[0]) break; 88 | 89 | // Check for HELP invocation. 90 | if ( strncmp(cmd,"?",1)==0 || strncmp(cmd,"help",4)==0 || strncmp(cmd,"h",1)==0 ) 91 | { 92 | return libswd_cli_print_usage(libswdctx); 93 | } 94 | 95 | // Check for LOGLEVEL invocation. 96 | else if ( strncmp(cmd,"l",1)==0 || strncmp(cmd,"loglevel",8)==0 ) 97 | { 98 | int loglevel_new=LIBSWD_LOGLEVEL_DEFAULT; 99 | cmd=strsep(&thiscommand," "); 100 | if (cmd==NULL) 101 | { 102 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 103 | "LIBSWD_I: libswd_cli(): Current loglevel is: %d (%s)\n", 104 | (int)libswdctx->config.loglevel, 105 | libswd_log_level_string(libswdctx->config.loglevel) ); 106 | } 107 | else 108 | { 109 | errno=LIBSWD_OK; 110 | loglevel_new=atol(cmd); 111 | if (errno==LIBSWD_OK) 112 | { 113 | retval=libswd_log_level_set(libswdctx, (libswd_loglevel_t)loglevel_new ); 114 | if (retval<0) 115 | { 116 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 117 | "LIBSWD_E: libswd_cli(): Cannot set loglevel %d/%s): %s.\n", 118 | loglevel_new, 119 | libswd_log_level_string((libswd_loglevel_t)loglevel_new), 120 | libswd_error_string(retval) ); 121 | } 122 | } 123 | else if (errno!=LIBSWD_OK) 124 | { 125 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 126 | "LIBSWD_I: libswd_cli(): Current loglevel is: %d (%s)\n", 127 | (int)libswdctx->config.loglevel, 128 | libswd_log_level_string(libswdctx->config.loglevel) ); 129 | } 130 | } 131 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LOGLEVEL=%d/%s\n", 132 | (int)libswdctx->config.loglevel, 133 | libswd_log_level_string(libswdctx->config.loglevel)); 134 | continue; 135 | } 136 | 137 | // Initialize Target subsystems. 138 | // This will bring components into known state and remove any pending errors. 139 | else if ( strncmp(cmd,"i",1)==0 || strncmp(cmd,"init",4)==0 ) 140 | { 141 | cmd=strsep(&thiscommand," "); 142 | if (!cmd || strncmp(cmd,"da",2)==0 || strncmp(cmd,"dap",3)==0 ) 143 | { 144 | int *idcode; 145 | retval=libswd_dap_init(libswdctx, LIBSWD_OPERATION_EXECUTE, &idcode); 146 | if (retval<0) 147 | { 148 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 149 | "LIBSWD_E: libswd_cli(): Cannot Initialize DAP! (%s)\n", 150 | libswd_error_string(retval) ); 151 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 152 | "LIBSWD_N: libswd_cli(): DAP INIT ERROR!\n" ); 153 | } else libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 154 | "LIBSWD_N: DAP INIT OK! IDCODE=0x%08X/%s\n", 155 | *idcode, libswd_bin32_string(idcode) ); 156 | } 157 | else if ( strncmp(cmd,"m",1)==0 || strncmp(cmd,"memap",5)==0 ) 158 | { 159 | retval=libswd_memap_init(libswdctx, LIBSWD_OPERATION_EXECUTE); 160 | if (retval<0) 161 | { 162 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 163 | "LIBSWD_E: libswd_cli(): MEM-AP INIT ERROR!\n"); 164 | } else libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 165 | "LIBSWD_N: MEM-AP INIT OK!\n"); 166 | } 167 | else if ( strncmp(cmd,"de",2)==0 || strncmp(cmd,"debug",5)==0 ) 168 | { 169 | retval=libswd_debug_init(libswdctx, LIBSWD_OPERATION_EXECUTE); 170 | if (retval<0) 171 | { 172 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 173 | "LIBSWD_E: libswd_cli(): DEBUG INIT ERROR!\n" ); 174 | } else libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 175 | "LIBSWD_N: DEBUG INIT OK!\n"); 176 | } 177 | continue; 178 | } 179 | // Check for DEBUG invocation. 180 | else if ( strncmp(cmd,"d",1)==0 || strncmp(cmd,"debug",5)==0 ) 181 | { 182 | cmd=strsep(&thiscommand," "); 183 | if (!cmd) goto libswd_cli_syntaxerror; 184 | if ( strncmp(cmd,"h",1)==0 || strncmp(cmd,"halt",4)==0 ) 185 | { 186 | retval=libswd_debug_halt(libswdctx, LIBSWD_OPERATION_EXECUTE); 187 | if (retval<0) 188 | { 189 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 190 | "LIBSWD_E: libswd_cli(): DEBUG HALT ERROR! (%s).\n", 191 | libswd_error_string(retval) ); 192 | } 193 | } 194 | else if ( strncmp(cmd,"r",1)==0 || strncmp(cmd,"run",3)==0 ) 195 | { 196 | retval=libswd_debug_run(libswdctx, LIBSWD_OPERATION_EXECUTE); 197 | if (retval<0) 198 | { 199 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 200 | "LIBSWD_E: libswd_cli(); DEBUG RUN ERROR! (%s)\n", 201 | libswd_error_string(retval) ); 202 | } 203 | } 204 | } 205 | // Check for READ invocation. 206 | else if ( strncmp(cmd,"r",1)==0 || strncmp(cmd,"read",4)==0 ) 207 | { 208 | // Parse access port name parameter. 209 | cmd=strsep(&thiscommand," "); 210 | if (!cmd) goto libswd_cli_syntaxerror; 211 | if ( strncmp(cmd,"d",1)==0 || strncmp(cmd,"dap",3)==0 ) 212 | { 213 | ap='d'; 214 | } 215 | else if ( strncmp(cmd,"a",1)==0 || strncmp(cmd,"ap",2)==0 ) 216 | { 217 | ap='a'; 218 | } 219 | else if ( strncmp(cmd,"m",1)==0 || strncmp(cmd,"memap",5)==0 ) 220 | { 221 | ap='m'; 222 | } else goto libswd_cli_syntaxerror; 223 | // Parse address parameter. 224 | cmd=strsep(&thiscommand," "); 225 | if (!cmd) goto libswd_cli_syntaxerror; 226 | errno=LIBSWD_OK; 227 | addrstart=strtol(cmd, (char**)NULL, 0); 228 | if (errno!=LIBSWD_OK) goto libswd_cli_syntaxerror; 229 | // Perform operations on a given access port. 230 | switch (ap) 231 | { 232 | case 'd': 233 | retval=libswd_dp_read(libswdctx, LIBSWD_OPERATION_EXECUTE, 234 | addrstart, &data32 ); 235 | if (retval<0) goto libswd_cli_error; 236 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 237 | "LIBSWD_N: DP[0x%08X]=0x%08X\n", 238 | addrstart, *data32 ); 239 | break; 240 | case 'a': 241 | retval=libswd_ap_read(libswdctx, LIBSWD_OPERATION_EXECUTE, 242 | addrstart, &data32 ); 243 | if (retval<0) goto libswd_cli_error; 244 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 245 | "LIBSWD_N: AP[0x%08X]=0x%08X\n", 246 | addrstart, *data32 ); 247 | break; 248 | case 'm': 249 | // Parse count parameter for MEM-AP operation. 250 | if (thiscommand) 251 | { 252 | cmd=strsep(&thiscommand," "); 253 | errno=LIBSWD_OK; 254 | count=strtol(cmd, &endptr, 0); 255 | if (errno!=LIBSWD_OK || count<=0) goto libswd_cli_syntaxerror; 256 | } else count=4; 257 | // Make sure count is 32-bit boundary. 258 | if (count%4) count=count-(count%4); 259 | addrstop=addrstart+count; 260 | // Parse filename parameter for MEM-AP operation. 261 | if (thiscommand) 262 | { 263 | cmd=strsep(&thiscommand," "); 264 | if (cmd && cmd!='\0' && !isspace(*cmd)) 265 | { 266 | filename=cmd; 267 | } else filename=NULL; 268 | } else filename=NULL; 269 | // Take care of proper memory (re)allocation. 270 | if (libswdctx->membuf.sizemembuf.data) free(libswdctx->membuf.data); 273 | libswdctx->membuf.size=count*sizeof(char); 274 | libswdctx->membuf.data=(unsigned char*)malloc(libswdctx->membuf.size); 275 | if (!libswdctx->membuf.data) 276 | { 277 | libswdctx->membuf.size=0; 278 | libswd_log(libswdctx, LIBSWD_ERROR_OUTOFMEM, 279 | "LIBSWD_E: libswd_cli(): Cannot (re)allocate memory buffer!\n"); 280 | retval=LIBSWD_ERROR_OUTOFMEM; 281 | goto libswd_cli_error; 282 | } else memset((void*)libswdctx->membuf.data, 0xFF, libswdctx->membuf.size); 283 | } else libswdctx->membuf.size=count*sizeof(char); 284 | // Perform MEM-AP read. 285 | retval=libswd_memap_read_char_32(libswdctx, LIBSWD_OPERATION_EXECUTE, 286 | addrstart, count, 287 | (char*)libswdctx->membuf.data ); 288 | if (retval<0) goto libswd_cli_error; 289 | // Store result to a file if requested. 290 | if (filename) 291 | { 292 | FILE *fp; 293 | fp=fopen(filename,"w"); 294 | if (!fp) 295 | { 296 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 297 | "LIBSWD_W: libswd_cli(): Cannot open '%s' data file!\n", 298 | filename, strerror(errno) ); 299 | break; 300 | } 301 | retval=fwrite(libswdctx->membuf.data, sizeof(char), count, fp); 302 | if (!retval) 303 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 304 | "LIBSWD_W: libswd_cli(): Cannot write to data file '%s' (%s)!\n", 305 | filename, strerror(errno) ); 306 | retval=fclose(fp); 307 | if (retval) 308 | { 309 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 310 | "LIBSWD_W: libswd_cli(): Cannot close data file '%s' (%s)!\n", 311 | filename, strerror(errno) ); 312 | } 313 | } 314 | // Print out the result. 315 | for (i=0; imembuf.size;j++) printf("%02X ", (unsigned char)libswdctx->membuf.data[i+j]); 319 | if (j<16) for(;j<16;j++) printf(" "); 320 | printf(" "); 321 | for (j=0;j<16&&i+jmembuf.size;j++) printf("%c", isprint(libswdctx->membuf.data[i+j])?libswdctx->membuf.data[i+j]:'.'); 322 | if (j<16) for (;j<16;j++) printf("."); 323 | } 324 | printf("\n"); 325 | break; 326 | default: 327 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 328 | "LIBSWD_E: libswd_cli(): Unknown Access Port given!\n"); 329 | goto libswd_cli_syntaxerror; 330 | } 331 | continue; 332 | } 333 | 334 | // Check for WRITE invocation. 335 | else if ( strncmp(cmd,"w",1)==0 || strncmp(cmd,"write",5)==0 ) 336 | { 337 | // Parse access port name parameter. 338 | cmd=strsep(&thiscommand," "); 339 | if (!cmd) goto libswd_cli_syntaxerror; 340 | if ( strncmp(cmd,"d",1)==0 || strncmp(cmd,"dap",3)==0 ) 341 | { 342 | ap='d'; 343 | } 344 | else if ( strncmp(cmd,"a",1)==0 || strncmp(cmd,"ap",2)==0 ) 345 | { 346 | ap='a'; 347 | } 348 | else if ( strncmp(cmd,"m",1)==0 || strncmp(cmd,"memap",5)==0 ) 349 | { 350 | ap='m'; 351 | } else goto libswd_cli_syntaxerror; 352 | // Parse address parameter. 353 | cmd=strsep(&thiscommand," "); 354 | if (!cmd) goto libswd_cli_syntaxerror; 355 | errno=LIBSWD_OK; 356 | addrstart=strtol(cmd, (char**)NULL, 0); 357 | if (errno!=LIBSWD_OK) goto libswd_cli_syntaxerror; 358 | // At this point parse for DP/AP and MEM-AP will vary, so skip it here. 359 | // Perform operations on a given access port. 360 | switch (ap) 361 | { 362 | case 'd': 363 | // Parse data parameter. 364 | if (!thiscommand) goto libswd_cli_syntaxerror; 365 | cmd=strsep(&thiscommand," "); 366 | if (!cmd) goto libswd_cli_syntaxerror; 367 | errno=LIBSWD_OK; 368 | data=strtol(cmd, &endptr, 0); 369 | if (errno!=LIBSWD_OK) goto libswd_cli_syntaxerror; 370 | retval=libswd_dp_write(libswdctx, LIBSWD_OPERATION_EXECUTE, 371 | addrstart, &data ); 372 | if (retval<0) goto libswd_cli_error; 373 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 374 | "LIBSWD_N: DP[0x%08X]=0x%08X\n", 375 | addrstart, data ); 376 | break; 377 | case 'a': 378 | // Parse data parameter. 379 | if (!thiscommand) goto libswd_cli_syntaxerror; 380 | cmd=strsep(&thiscommand," "); 381 | if (!cmd) goto libswd_cli_syntaxerror; 382 | errno=LIBSWD_OK; 383 | data=strtol(cmd, &endptr, 0); 384 | if (errno!=LIBSWD_OK) goto libswd_cli_syntaxerror; 385 | retval=libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, 386 | addrstart, &data ); 387 | if (retval<0) goto libswd_cli_error; 388 | // Read-back the register value as it may differ from original request. 389 | retval=libswd_ap_read(libswdctx, LIBSWD_OPERATION_EXECUTE, addrstart, &data32); 390 | if (retval<0) goto libswd_cli_error; 391 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 392 | "LIBSWD_N: AP[0x%08X]=0x%08X\n", 393 | addrstart, *data32 ); 394 | break; 395 | case 'm': 396 | // First data parameter can be a number or filename. 397 | // If number, it will also deretmine data type (char/int). 398 | // Parse data parameter. 399 | if (!thiscommand) goto libswd_cli_syntaxerror; 400 | errno=LIBSWD_OK; 401 | data=strtol(thiscommand, &endptr, 0); 402 | if (!*endptr || endptr==strstr(thiscommand," ")) 403 | { 404 | // 'thiscommand' variable holds the data list. 405 | // First element length determines data type (char or int). 406 | int elmcnt, elmlen, elmbytes; 407 | for (elmlen=0;thiscommand[elmlen]&&thiscommand[elmlen]!=' ';elmlen++); 408 | // Count the number of elements on the list. 409 | elmcnt=1; for (i=0;thiscommand[i];i++) if (thiscommand[i]==' ') elmcnt++; 410 | if (elmlen<1 || elmlen>10) goto libswd_cli_syntaxerror; 411 | // Calculate and allocate memory buffer. 412 | // Buffer is char based, round up size to match 32-bit align if necessary. 413 | if (libswdctx->membuf.data) free(libswdctx->membuf.data); 414 | libswdctx->membuf.size=0; 415 | elmbytes=elmcnt*((elmlen>4)?(4*sizeof(char)):(sizeof(char))); 416 | if (elmbytes%4) elmbytes+=elmbytes%4; 417 | libswdctx->membuf.size=elmbytes; 418 | libswdctx->membuf.data=(unsigned char*)malloc(libswdctx->membuf.size); 419 | if (!libswdctx->membuf.data) 420 | { 421 | libswdctx->membuf.size=0; 422 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 423 | "LIBSWD_E: libswd_cli(): Cannot allocate memory for data, aborting!\n" ); 424 | retval=LIBSWD_ERROR_OUTOFMEM; 425 | goto libswd_cli_syntaxerror; 426 | } else memset((void*)libswdctx->membuf.data, 0xFF, libswdctx->membuf.size); 427 | // Fill the memory buffer with provided data. 428 | // Load char type data. 429 | if (elmlen<=4) 430 | { 431 | for (i=0;(imembuf.size)&&thiscommand;i++) 432 | { 433 | cmd=strsep(&thiscommand," "); 434 | errno=LIBSWD_OK; 435 | data=strtol(cmd,(char**)NULL, 0); 436 | if (errno!=LIBSWD_OK) goto libswd_cli_syntaxerror; 437 | libswdctx->membuf.data[i]=(unsigned char)data; 438 | } 439 | } 440 | // Load int type data. 441 | else 442 | { 443 | for (i=0;(imembuf.size/4)&&thiscommand;i++) 444 | { 445 | cmd=strsep(&thiscommand," "); 446 | errno=LIBSWD_OK; 447 | data=strtol(cmd,(char**)NULL, 0); 448 | if (errno!=LIBSWD_OK) goto libswd_cli_syntaxerror; 449 | libswdctx->membuf.data[i*4+0]=(unsigned char)data; 450 | libswdctx->membuf.data[i*4+1]=(unsigned char)(data>>8); 451 | libswdctx->membuf.data[i*4+2]=(unsigned char)(data>>16); 452 | libswdctx->membuf.data[i*4+3]=(unsigned char)(data>>24); 453 | } 454 | } 455 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 456 | "LIBSWD_I: libswd_cli(): Parsed %d bytes of data into memory buffer!\n", 457 | libswdctx->membuf.size ); 458 | } 459 | // Given data parameter is a filename. Load file into memory. 460 | else 461 | { 462 | filename=thiscommand; 463 | res=LIBSWD_OK; 464 | FILE *fp; 465 | fp=fopen(filename,"r"); 466 | if (!fp) 467 | { 468 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 469 | "LIBSWD_E: libswd_cli(): Cannot open '%s' data file (%s), aborting!\n", 470 | filename, strerror(errno)); 471 | return LIBSWD_ERROR_FILE; 472 | } 473 | // Take care of (re)allocating memory for membuf based on a file size. 474 | if (libswdctx->membuf.size) free(libswdctx->membuf.data); 475 | fseek(fp, 0, SEEK_END); 476 | libswdctx->membuf.size=ftell(fp); 477 | libswdctx->membuf.data=(unsigned char*)malloc(libswdctx->membuf.size); 478 | fseek(fp, 0, SEEK_SET); 479 | if (!libswdctx->membuf.data) 480 | { 481 | libswdctx->membuf.size=0; 482 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 483 | "LIBSWD_E: libswd_cli(): Cannot allocate memory to load '%s' file, aborting!\n", 484 | filename ); 485 | res=LIBSWD_ERROR_OUTOFMEM; 486 | goto libswd_cli_write_memap_file_load_error; 487 | } else memset((void*)libswdctx->membuf.data, 0xFF, libswdctx->membuf.size); 488 | // Load file content into memory. 489 | retval=fread(libswdctx->membuf.data, sizeof(char), libswdctx->membuf.size, fp); 490 | if (!retval) 491 | { 492 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 493 | "LIBSWD_E: libswd_cli(): Cannot load data from '%s' file (%s), aborting!\n", 494 | filename, strerror(errno) ); 495 | res=LIBSWD_ERROR_FILE; 496 | goto libswd_cli_write_memap_file_load_error; 497 | } 498 | libswd_cli_write_memap_file_load_error: 499 | retval=fclose(fp); 500 | if (retval) 501 | { 502 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 503 | "LIBSWD_E: libswd_cli(): Cannot close data file '%s' (%s), aborting!\n", 504 | filename, strerror(errno) ); 505 | return LIBSWD_ERROR_FILE; 506 | } 507 | if (res!=LIBSWD_OK) return res; 508 | libswd_cli_write_memap_file_load_ok: 509 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 510 | "LIBSWD_I: libswd_cli(): %d bytes of data from '%s' file loaded!\n", 511 | libswdctx->membuf.size, filename ); 512 | } 513 | // At this point data are in membuf, sent them to MEM-AP. 514 | retval=libswd_memap_write_char_32(libswdctx, LIBSWD_OPERATION_EXECUTE, 515 | addrstart, libswdctx->membuf.size, 516 | (char*)libswdctx->membuf.data ); 517 | if (retval<0) goto libswd_cli_error; 518 | // Print out the data. 519 | for (i=0; imembuf.size; i=i+16) 520 | { 521 | printf("\n%08X: ", i+addrstart); 522 | for (j=0;j<16&&i+jmembuf.size;j++) printf("%02X ", (unsigned char)libswdctx->membuf.data[i+j]); 523 | if (j<16) for(;j<16;j++) printf(" "); 524 | printf(" "); 525 | for (j=0;j<16&&i+jmembuf.size;j++) printf("%c", isprint(libswdctx->membuf.data[i+j])?libswdctx->membuf.data[i+j]:'.'); 526 | if (j<16) for (;j<16;j++) printf("."); 527 | } 528 | printf("\n"); 529 | break; 530 | default: 531 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 532 | "LIBSWD_E: libswd_cli(): Unknown Access Port given!\n"); 533 | goto libswd_cli_syntaxerror; 534 | } 535 | break; 536 | } 537 | // No known thiscommand was invoked, show usage message and return message. 538 | else 539 | { 540 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 541 | "LIBSWD_E: libswd_cli(): %s.\n", 542 | libswd_error_string(LIBSWD_ERROR_CLISYNTAX) ); 543 | libswd_cli_print_usage(libswdctx); 544 | return LIBSWD_ERROR_CLISYNTAX; 545 | } 546 | } 547 | } 548 | 549 | return LIBSWD_OK; 550 | 551 | libswd_cli_syntaxerror: 552 | retval=LIBSWD_ERROR_CLISYNTAX; 553 | libswd_cli_error: 554 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 555 | "LIBSWD_E: libswd_cli(): %s.\n", 556 | libswd_error_string(retval) ); 557 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 558 | "LIBSWD_D: libswd_cli(): CMD=%s COMMAND=%s.\n", 559 | cmd, command ); 560 | return retval; 561 | }; 562 | 563 | 564 | /** @} */ 565 | -------------------------------------------------------------------------------- /src/libswd_cmd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 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. 18 | * 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.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_cmd.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_cmd_enqueue SWD Command Genration and Enqueueing routines. 41 | * Command quants are first generated/created in memory, then enqueued into 42 | * command queue for execution by libswd_cmd_flush(). Queue elements are created 43 | * in memory and filled with payload, then appended to the queue. If enqueue 44 | * fails, memory for newly created elements is set free before return. 45 | * All functions here start with "libswd_cmd_queue_append_" prefix. 46 | * Functions here are NOT intelligent, they only create payload in memory, 47 | * so treat them rather as blocks for high-level functions. 48 | * @{ 49 | ******************************************************************************/ 50 | 51 | /** Append selected command to a context's command queue (libswdctx->cmdq). 52 | * This function does not update the libswdctx->cmdq pointer (its updated on flush). 53 | * \param *libswdctx swd context pointer containing the command queue. 54 | * \param *cmd command to be appended to the context's command queue. 55 | * \return number of elements appended or LIBSWD_ERROR_CODE on failure. 56 | */ 57 | int libswd_cmd_enqueue(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd){ 58 | if (libswdctx==NULL || cmd==NULL) return LIBSWD_ERROR_NULLPOINTER; 59 | int res; 60 | res=libswd_cmdq_append(libswdctx->cmdq, cmd); 61 | return res; 62 | } 63 | 64 | /** Appends command queue with SWD Request packet header. 65 | * Note that contents is not validated, so bad request can be sent as well. 66 | * \param *libswdctx swd context pointer. 67 | * \param *request pointer to the 8-bit request payload. 68 | * \return return number elements appended (1), or LIBSWD_ERROR_CODE on failure. 69 | */ 70 | int libswd_cmd_enqueue_mosi_request(libswd_ctx_t *libswdctx, char *request){ 71 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 72 | if (request==NULL) return LIBSWD_ERROR_NULLPOINTER; 73 | int res; 74 | libswd_cmd_t *cmd; 75 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 76 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 77 | cmd->request=*request; 78 | cmd->bits=LIBSWD_REQUEST_BITLEN; 79 | cmd->cmdtype=LIBSWD_CMDTYPE_MOSI_REQUEST; 80 | res=libswd_cmd_enqueue(libswdctx, cmd); 81 | if (res<1) free(cmd); 82 | return res; 83 | } 84 | 85 | /** Append command queue with Turnaround activating MOSI mode. 86 | * \param *libswdctx swd context pointer. 87 | * \return return number elements appended (1), or LIBSWD_ERROR_CODE on failure. 88 | */ 89 | int libswd_cmd_enqueue_mosi_trn(libswd_ctx_t *libswdctx){ 90 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 91 | int res; 92 | libswd_cmd_t *cmd; 93 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 94 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 95 | cmd->TRNnMOSI=0; 96 | cmd->bits=libswdctx->config.trnlen; 97 | cmd->cmdtype=LIBSWD_CMDTYPE_MOSI_TRN; 98 | res=libswd_cmd_enqueue(libswdctx, cmd); 99 | if (res<1) free(cmd); 100 | return res; 101 | } 102 | 103 | /** Append command queue with Turnaround activating MISO mode. 104 | * \param *libswdctx swd context pointer. 105 | * \return return number of elements appended (1), or LIBSWD_ERROR_CODE on failure. 106 | */ 107 | int libswd_cmd_enqueue_miso_trn(libswd_ctx_t *libswdctx){ 108 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 109 | int res; 110 | libswd_cmd_t *cmd; 111 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 112 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 113 | cmd->TRNnMOSI=1; 114 | cmd->bits=libswdctx->config.trnlen; 115 | cmd->cmdtype=LIBSWD_CMDTYPE_MISO_TRN; 116 | res=libswd_cmd_enqueue(libswdctx, cmd); 117 | if (res<1) free(cmd); 118 | return res; 119 | } 120 | 121 | /** Append command queue with bus binary read bit-by-bit operation. 122 | * This function will append command to the queue for each bit, and store 123 | * one bit into single char array element, so read is not constrained to 8 bits. 124 | * On error memory is released and apropriate error code is returned. 125 | * Important: Memory pointed by *data must be allocated prior call! 126 | * \param *libswdctx swd context pointer. 127 | * \param **data allocated data array to write result into. 128 | * \param count number of bits to read (also the **data size). 129 | * \return number of elements processed, or LIBSWD_ERROR_CODE on failure. 130 | */ 131 | int libswd_cmd_enqueue_miso_nbit(libswd_ctx_t *libswdctx, char **data, int count){ 132 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 133 | if (count<=0) return LIBSWD_ERROR_PARAM; 134 | int res, res2; 135 | libswd_cmd_t *cmd, *oldcmdq=libswdctx->cmdq; 136 | int i,cmdcnt=0; 137 | for (i=0;ibits=1; 144 | if (data!=NULL) *data=&cmd->misobit; 145 | cmd->cmdtype=LIBSWD_CMDTYPE_MISO_BITBANG; 146 | res=libswd_cmd_enqueue(libswdctx, cmd); 147 | if (res<1) break; 148 | cmdcnt+=res; 149 | } 150 | //If there was problem enqueueing elements, rollback changes on queue. 151 | if (res<1) { 152 | res2=libswd_cmdq_free_tail(oldcmdq); 153 | if (res2<0) return res2; 154 | return res; 155 | } else return cmdcnt; 156 | } 157 | 158 | /** Append command queue with bus binary write bit-by-bit operation. 159 | * This function will append command to the queue for each bit and store 160 | * one bit into single char array element, so read is not constrained to 8 bits. 161 | * On error memory is released and apropriate error code is returned. 162 | * Important: Memory pointed by *data must be allocated prior call! 163 | * \param *libswdctx swd context pointer. 164 | * \param **data allocated data array to write result into. 165 | * \param count number of bits to read (also the **data size). 166 | * \return number of elements processed, or LIBSWD_ERROR_CODE on failure. 167 | */ 168 | int libswd_cmd_enqueue_mosi_nbit(libswd_ctx_t *libswdctx, char *data, int count){ 169 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 170 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 171 | if (count<=0) return LIBSWD_ERROR_PARAM; 172 | int res, res2, cmdcnt=0; 173 | libswd_cmd_t *cmd, *oldcmdq=libswdctx->cmdq; 174 | int i; 175 | for (i=0;imosibit=data[i]; 182 | cmd->bits=1; 183 | cmd->cmdtype=LIBSWD_CMDTYPE_MOSI_BITBANG; 184 | res=libswd_cmd_enqueue(libswdctx, cmd); 185 | if (res<1) break; 186 | cmdcnt+=res; 187 | } 188 | //If there was problem enqueueing elements, rollback changes on queue. 189 | if (res<1){ 190 | res2=libswd_cmdq_free_tail(oldcmdq); 191 | if (res2<0) return res2; 192 | libswdctx->cmdq=oldcmdq; 193 | return res; 194 | } else return cmdcnt; 195 | } 196 | 197 | /** Append command queue with parity bit write. 198 | * \param *libswdctx swd context pointer. 199 | * \param *parity parity value pointer. 200 | * \return number of elements appended (1), or LIBSWD_ERROR_CODE on failure. 201 | */ 202 | int libswd_cmd_enqueue_mosi_parity(libswd_ctx_t *libswdctx, char *parity){ 203 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 204 | if (*parity!=0 && *parity!=1) return LIBSWD_ERROR_PARAM; 205 | int res; 206 | libswd_cmd_t *cmd; 207 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 208 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 209 | cmd->parity=*parity; 210 | cmd->bits=1; 211 | cmd->cmdtype=LIBSWD_CMDTYPE_MOSI_PARITY; 212 | res=libswd_cmd_enqueue(libswdctx, cmd); 213 | if (res<1) free(cmd); 214 | return res; 215 | } 216 | 217 | /** Append command queue with parity bit read. 218 | * \param *libswdctx swd context pointer. 219 | * \param *parity parity value pointer. 220 | * \return number of elements appended (1), or LIBSWD_ERROR_CODE on failure. 221 | */ 222 | int libswd_cmd_enqueue_miso_parity(libswd_ctx_t *libswdctx, char **parity){ 223 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 224 | int res; 225 | libswd_cmd_t *cmd; 226 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 227 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 228 | if (parity!=NULL) *parity=&cmd->parity; 229 | cmd->bits=1; 230 | cmd->cmdtype=LIBSWD_CMDTYPE_MISO_PARITY; 231 | res=libswd_cmd_enqueue(libswdctx, cmd); 232 | if (res<1) free(cmd); 233 | return res; 234 | } 235 | 236 | /** Append command queue with data read. 237 | * \param *libswdctx swd context pointer. 238 | * \param *data data pointer. 239 | * \return of elements appended (1), or LIBSWD_ERROR_CODE on failure. 240 | */ 241 | int libswd_cmd_enqueue_miso_data(libswd_ctx_t *libswdctx, int **data){ 242 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 243 | int res; 244 | libswd_cmd_t *cmd; 245 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 246 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 247 | if (data!=NULL) *data=&cmd->misodata; 248 | cmd->bits=32; 249 | cmd->cmdtype=LIBSWD_CMDTYPE_MISO_DATA; 250 | res=libswd_cmd_enqueue(libswdctx, cmd); // should be 1 on success 251 | if (res<1) free(cmd); 252 | return res; 253 | } 254 | 255 | /** Append command queue with data and parity read. 256 | * \param *libswdctx swd context pointer. 257 | * \param *data data value pointer. 258 | * \param *parity parity value pointer. 259 | * \return number of elements appended (2), or LIBSWD_ERROR_CODE on failure. 260 | */ 261 | int libswd_cmd_enqueue_miso_data_p(libswd_ctx_t *libswdctx, int **data, char **parity){ 262 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 263 | int res, cmdcnt=0; 264 | res=libswd_cmd_enqueue_miso_data(libswdctx, data); 265 | if (res<1) return res; 266 | cmdcnt+=res; 267 | res=libswd_cmd_enqueue_miso_parity(libswdctx, parity); 268 | if (res<1) return res; 269 | cmdcnt+=res; 270 | return cmdcnt; // should be 2 or 3(+trn) on success 271 | } 272 | 273 | /** Append command queue with series of data and parity read. 274 | * \param *libswdctx swd context pointer. 275 | * \param **data data value array pointer. 276 | * \param **parity parity value array pointer. 277 | * \param count number of (data+parity) elements to read. 278 | * \return number of elements appended (2*count), or LIBSWD_ERROR_CODE on failure. 279 | */ 280 | int libswd_cmd_enqueue_miso_n_data_p(libswd_ctx_t *libswdctx, int **data, char **parity, int count){ 281 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 282 | if (count<=0) return LIBSWD_ERROR_PARAM; 283 | int i,res, cmdcnt=0; 284 | for (i=0;i<=count;i++){ 285 | res=libswd_cmd_enqueue_miso_data_p(libswdctx, &data[i], &parity[i]); 286 | if (res<2) return LIBSWD_ERROR_RESULT; 287 | cmdcnt=+res; 288 | } 289 | return cmdcnt; 290 | } 291 | 292 | /** Append command queue with data and parity write. 293 | * \param *libswdctx swd context pointer. 294 | * \param *data data value pointer. 295 | * \return number of elements appended (1), or LIBSWD_ERROR_CODE on failure. 296 | */ 297 | int libswd_cmd_enqueue_mosi_data(libswd_ctx_t *libswdctx, int *data){ 298 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 299 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 300 | int res; 301 | libswd_cmd_t *cmd; 302 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 303 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 304 | cmd->mosidata=*data; 305 | cmd->bits=32; 306 | cmd->cmdtype=LIBSWD_CMDTYPE_MOSI_DATA; 307 | res=libswd_cmd_enqueue(libswdctx, cmd); // should be 1 or 2 on success 308 | if (res<1) free(cmd); 309 | return res; 310 | } 311 | 312 | /** Append command queue with data and automatic parity write. 313 | * \param *libswdctx swd context pointer. 314 | * \param *data data value pointer. 315 | * \return number of elements appended (2), or LIBSWD_ERROR_CODE on failure. 316 | */ 317 | int libswd_cmd_enqueue_mosi_data_ap(libswd_ctx_t *libswdctx, int *data){ 318 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 319 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 320 | int res, cmdcnt=0; 321 | char parity; 322 | res=libswd_cmd_enqueue_mosi_data(libswdctx, data); 323 | if (res<1) return res; 324 | cmdcnt=+res; 325 | res=libswd_bin32_parity_even(data, &parity); 326 | if (res<0) return res; 327 | res=libswd_cmd_enqueue_mosi_parity(libswdctx, &parity); 328 | if (res<1) return res; 329 | cmdcnt=+res; 330 | return cmdcnt; // should be 2 or 3 on success 331 | } 332 | 333 | /** Append command queue with data and provided parity write. 334 | * \param *libswdctx swd context pointer. 335 | * \param *data data value pointer. 336 | * \param *parity parity value pointer. 337 | * \return number of elements appended (2), or LIBSWD_ERROR_CODE on failure. 338 | */ 339 | int libswd_cmd_enqueue_mosi_data_p(libswd_ctx_t *libswdctx, int *data, char *parity){ 340 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 341 | if (data==NULL || parity==NULL) return LIBSWD_ERROR_NULLPOINTER; 342 | int res, cmdcnt=0; 343 | res=libswd_cmd_enqueue_mosi_data(libswdctx, data); 344 | if (res<1) return res; 345 | cmdcnt=+res; 346 | res=libswd_cmd_enqueue_mosi_parity(libswdctx, parity); 347 | if (res<1) return res; 348 | cmdcnt=+res; 349 | return cmdcnt; // should be 2 or 3 on success 350 | } 351 | 352 | /** Append command queue with series of data and automatic parity writes. 353 | * \param *libswdctx swd context pointer. 354 | * \param **data data value array pointer. 355 | * \param count number of (data+parity) elements to read. 356 | * \return number of elements appended (2*count), or LIBSWD_ERROR_CODE on failure. 357 | */ 358 | int libswd_cmd_enqueue_mosi_n_data_ap(libswd_ctx_t *libswdctx, int **data, int count){ 359 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 360 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 361 | if (count<1) return LIBSWD_ERROR_PARAM; 362 | int i, res, cmdcnt=0; 363 | for (i=0;iack; 403 | cmd->bits=LIBSWD_ACK_BITLEN; 404 | cmd->cmdtype=LIBSWD_CMDTYPE_MISO_ACK; 405 | res=libswd_cmd_enqueue(libswdctx, cmd); //should be 1 on success 406 | if (res<1) free(cmd); 407 | return res; 408 | } 409 | 410 | /** Append command queue with len-octet size control seruence. 411 | * This control sequence can be used for instance to send payload of packets 412 | * switching DAP between JTAG and SWD mode. 413 | * \param *libswdctx swd context pointer. 414 | * \param *ctlmsg control message array pointer. 415 | * \param len number of elements to send from *ctlmsg. 416 | * \return number of elements appended (len), or LIBSWD_ERROR_CODE on failure. 417 | */ 418 | int libswd_cmd_enqueue_mosi_control(libswd_ctx_t *libswdctx, char *ctlmsg, int len){ 419 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 420 | if (ctlmsg==NULL) return LIBSWD_ERROR_NULLPOINTER; 421 | if (len<=0) return LIBSWD_ERROR_PARAM; 422 | int elm, res, res2, cmdcnt=0; 423 | libswd_cmd_t *cmd=NULL, *oldcmdq=libswdctx->cmdq; 424 | for (elm=0;elmcontrol=ctlmsg[elm]; 431 | cmd->cmdtype=LIBSWD_CMDTYPE_MOSI_CONTROL; 432 | cmd->bits=sizeof(ctlmsg[elm])*LIBSWD_DATA_BYTESIZE; 433 | res=libswd_cmd_enqueue(libswdctx, cmd); 434 | if (res<1) break; 435 | cmdcnt=+res; 436 | } 437 | //If there was problem enqueueing elements, rollback changes on queue. 438 | if (res<1){ 439 | res2=libswd_cmdq_free_tail(oldcmdq); 440 | if (res2<0) return res2; 441 | libswdctx->cmdq=oldcmdq; 442 | return res; 443 | } return cmdcnt; 444 | } 445 | 446 | /** Append command queue with SW-DP-RESET sequence. 447 | * \param *libswdctx swd context pointer. 448 | * \return number of elements appended, or LIBSWD_ERROR_CODE on failure. 449 | */ 450 | int libswd_cmd_enqueue_mosi_dap_reset(libswd_ctx_t *libswdctx){ 451 | return libswd_cmd_enqueue_mosi_control(libswdctx, (char *)LIBSWD_CMD_SWDPRESET, sizeof(LIBSWD_CMD_SWDPRESET)); 452 | } 453 | 454 | /** Append command queue with idle sequence. 455 | * \param *libswdctx swd context pointer. 456 | * \return number of elements appended, or LIBSWD_ERROR_CODE on failure. 457 | */ 458 | int libswd_cmd_enqueue_mosi_idle(libswd_ctx_t *libswdctx){ 459 | return libswd_cmd_enqueue_mosi_control(libswdctx, (char *)LIBSWD_CMD_IDLE, sizeof(LIBSWD_CMD_IDLE)); 460 | } 461 | 462 | /** Append command queue with JTAG-TO-SWD DAP-switch sequence. 463 | * \param *libswdctx swd context pointer. 464 | * \return number of elements appended, or LIBSWD_ERROR_CODE on failure. 465 | */ 466 | int libswd_cmd_enqueue_mosi_jtag2swd(libswd_ctx_t *libswdctx){ 467 | return libswd_cmd_enqueue_mosi_control(libswdctx, (char *)LIBSWD_CMD_JTAG2SWD, sizeof(LIBSWD_CMD_JTAG2SWD)); 468 | } 469 | 470 | /** Append command queue with SWD-TO-JTAG DAP-switch sequence. 471 | * \param *libswdctx swd context pointer. 472 | * \return number of elements appended, or LIBSWD_ERROR_CODE on failure. 473 | */ 474 | int libswd_cmd_enqueue_mosi_swd2jtag(libswd_ctx_t *libswdctx){ 475 | return libswd_cmd_enqueue_mosi_control(libswdctx, (char *)LIBSWD_CMD_SWD2JTAG, sizeof(LIBSWD_CMD_SWD2JTAG)); 476 | } 477 | 478 | /** Return human readable command type string of *cmd. 479 | * \param *cmd command the name is to be printed. 480 | * \return string containing human readable command name, or NULL on failure. 481 | */ 482 | char *libswd_cmd_string_cmdtype(libswd_cmd_t *cmd){ 483 | if (cmd==NULL) return NULL; 484 | switch (cmd->cmdtype){ 485 | case LIBSWD_CMDTYPE_MOSI_DATA: return "MOSI_DATA"; 486 | case LIBSWD_CMDTYPE_MOSI_REQUEST: return "MOSI_REQUEST"; 487 | case LIBSWD_CMDTYPE_MOSI_TRN: return "MOSI_TRN"; 488 | case LIBSWD_CMDTYPE_MOSI_PARITY: return "MOSI_PARITY"; 489 | case LIBSWD_CMDTYPE_MOSI_BITBANG: return "MOSI_BITBANG"; 490 | case LIBSWD_CMDTYPE_MOSI_CONTROL: return "MOSI_CONTROL"; 491 | case LIBSWD_CMDTYPE_MOSI: return "MOSI"; 492 | case LIBSWD_CMDTYPE_UNDEFINED: return "UNDEFINED"; 493 | case LIBSWD_CMDTYPE_MISO: return "MISO"; 494 | case LIBSWD_CMDTYPE_MISO_ACK: return "MISO_ACK"; 495 | case LIBSWD_CMDTYPE_MISO_BITBANG: return "MISO_BITBANG"; 496 | case LIBSWD_CMDTYPE_MISO_PARITY: return "MISO_PARITY"; 497 | case LIBSWD_CMDTYPE_MISO_TRN: return "MISO_TRN"; 498 | case LIBSWD_CMDTYPE_MISO_DATA: return "MISO_DATA"; 499 | default: return "Unknown command type!"; 500 | } 501 | } 502 | 503 | 504 | /** @} */ 505 | -------------------------------------------------------------------------------- /src/libswd_cmdq.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 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. 18 | * 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.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_cmdq.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_cmdq Command Queue helper functions 41 | * @{ 42 | ******************************************************************************/ 43 | 44 | /** Initialize new queue element in memory that becomes a queue root. 45 | * \param *cmdq pointer to the command queue element of type libswd_cmd_t 46 | * \return LIBSWD_OK on success, LIBSWD_ERROR_CODE code on failure 47 | */ 48 | int libswd_cmdq_init(libswd_cmd_t *cmdq){ 49 | cmdq=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 50 | if (cmdq==NULL) return LIBSWD_ERROR_OUTOFMEM; 51 | cmdq->prev=NULL; 52 | cmdq->next=NULL; 53 | return LIBSWD_OK; 54 | } 55 | 56 | /** Find queue root (first element). 57 | * \param *cmdq pointer to any queue element 58 | * \return libswd_cmd_t* pointer to the first element (root), NULL on failure 59 | */ 60 | libswd_cmd_t* libswd_cmdq_find_head(libswd_cmd_t *cmdq){ 61 | if (cmdq==NULL) return NULL; 62 | libswd_cmd_t *cmd=cmdq; 63 | while (cmd->prev!=NULL) cmd=cmd->prev; 64 | return cmd; 65 | } 66 | 67 | /** Find queue tail (last element). 68 | * \param *cmdq pointer to any queue element 69 | * \return libswd_cmd_t* pointer to the last element (tail), NULL on failure 70 | */ 71 | libswd_cmd_t* libswd_cmdq_find_tail(libswd_cmd_t *cmdq){ 72 | if (cmdq==NULL) return NULL; 73 | libswd_cmd_t *cmd=cmdq; 74 | while (cmd->next!=NULL) cmd=cmd->next; 75 | return cmd; 76 | } 77 | 78 | /** Find last executed element from the *cmdq. 79 | * Start search at *cmdq head, return element pointer or NULL if not found. 80 | * \param *cmdq queue that contains elements. 81 | * \return libswd_cmd_t* pointer to the last executed element or NULL on error. 82 | */ 83 | libswd_cmd_t* libswd_cmdq_find_exectail(libswd_cmd_t *cmdq){ 84 | if (cmdq==NULL) return NULL; 85 | libswd_cmd_t *cmd=libswd_cmdq_find_head(cmdq); 86 | if (cmd==NULL) return NULL; 87 | for (cmd=libswd_cmdq_find_head(cmdq);cmd;cmd=cmd->next){ 88 | if (cmd->done) { 89 | if (cmd->next){ 90 | if (!cmd->next->done) return cmd; 91 | } else return cmd; 92 | } 93 | } 94 | return NULL; 95 | } 96 | 97 | /** Append element pointed by *cmd at the end of the quque pointed by *cmdq. 98 | * After this operation queue will be pointed by appended element (ie. last 99 | * element added becomes actual quque pointer to show what was added recently). 100 | * \param *cmdq pointer to any element on command queue 101 | * \param *cmd pointer to the command to be appended 102 | * \return number of appended elements (one), LIBSWD_ERROR_CODE on failure 103 | */ 104 | int libswd_cmdq_append(libswd_cmd_t *cmdq, libswd_cmd_t *cmd){ 105 | if (cmdq==NULL) return LIBSWD_ERROR_NULLQUEUE; 106 | if (cmd==NULL) return LIBSWD_ERROR_NULLPOINTER; 107 | if (cmdq->next != NULL){ 108 | libswd_cmd_t *lastcmd; 109 | lastcmd=libswd_cmdq_find_tail(cmdq); 110 | lastcmd->next=cmd; 111 | cmd->prev=lastcmd; 112 | } else { 113 | cmdq->next=cmd; 114 | cmd->prev=cmdq; 115 | } 116 | return 1; 117 | } 118 | 119 | /** Free queue pointed by *cmdq element. 120 | * \param *cmdq pointer to any element on command queue 121 | * \return number of elements destroyed, LIBSWD_ERROR_CODE on failure 122 | */ 123 | int libswd_cmdq_free(libswd_cmd_t *cmdq){ 124 | if (cmdq==NULL) return LIBSWD_ERROR_NULLQUEUE; 125 | int cmdcnt=0; 126 | libswd_cmd_t *cmd, *nextcmd; 127 | cmd=libswd_cmdq_find_head(cmdq); 128 | while (cmd!=NULL) { 129 | nextcmd=cmd->next; 130 | free(cmd); 131 | cmd=nextcmd; 132 | cmdcnt++; 133 | } 134 | return cmdcnt; 135 | } 136 | 137 | /** Free queue head up to *cmdq element. 138 | * \param *cmdq pointer to the element that becomes new queue root. 139 | * \return number of elements destroyed, or LIBSWD_ERROR_CODE on failure. 140 | */ 141 | int libswd_cmdq_free_head(libswd_cmd_t *cmdq){ 142 | if (cmdq==NULL) return LIBSWD_ERROR_NULLQUEUE; 143 | int cmdcnt=0; 144 | libswd_cmd_t *cmdqroot, *nextcmd; 145 | cmdqroot=libswd_cmdq_find_head(cmdq); 146 | while(cmdqroot!=cmdq){ 147 | nextcmd=cmdqroot->next; 148 | free(cmdqroot); 149 | cmdqroot=nextcmd; 150 | cmdcnt++; 151 | } 152 | cmdqroot->prev=NULL; 153 | return cmdcnt; 154 | } 155 | 156 | /** Free queue tail starting after *cmdq element. 157 | * \param *cmdq pointer to the last element on the new queue. 158 | * \return number of elements destroyed, or LIBSWD_ERROR_CODE on failure. 159 | */ 160 | int libswd_cmdq_free_tail(libswd_cmd_t *cmdq){ 161 | if (cmdq==NULL) return LIBSWD_ERROR_NULLQUEUE; 162 | int cmdcnt=0; 163 | libswd_cmd_t *cmdqend; 164 | if (cmdq->next==NULL) return 0; 165 | cmdqend=libswd_cmdq_find_tail(cmdq->next); 166 | if (cmdqend==NULL) return LIBSWD_ERROR_QUEUE; 167 | while(cmdqend!=cmdq){ 168 | cmdqend=cmdqend->prev; 169 | free(cmdqend->next); 170 | cmdcnt++; 171 | } 172 | cmdq->next=NULL; 173 | return cmdcnt; 174 | } 175 | 176 | /** Flush command queue contents into interface driver and update **cmdq. 177 | * Operation is specified by LIBSWD_OPERATION and can be used to select 178 | * how to flush the queue, ie. head-only, tail-only, one, all, etc. 179 | * This function is not only used to flush libswdctx->cmdq but also other 180 | * queues (i.e. error handling) so the parameter is **cmdq not libswdctx itself. 181 | * This is the only place where **cmdq is updated to the last executed element. 182 | * Double pointer is used because we update pointer element not its data. 183 | * \param *cmdq pointer to queue to be flushed. 184 | * \param operation tells how to flush the queue. 185 | * \return number of commands transmitted, or LIBSWD_ERROR_CODE on failure. 186 | * !TODO: HOW WE WANT TO UPDATE CMDQ ELEMENT AFTER PROCESSING WITHOUT DOUBLE POINTER? 187 | */ 188 | int libswd_cmdq_flush(libswd_ctx_t *libswdctx, libswd_cmd_t **cmdq, libswd_operation_t operation){ 189 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 190 | if (*cmdq==NULL||cmdq==NULL) return LIBSWD_ERROR_NULLQUEUE; 191 | if (operationLIBSWD_OPERATION_LAST) 192 | return LIBSWD_ERROR_BADOPCODE; 193 | 194 | int res, cmdcnt=0; 195 | libswd_cmd_t *cmd, *firstcmd, *lastcmd; 196 | 197 | switch (operation){ 198 | case LIBSWD_OPERATION_TRANSMIT_HEAD: 199 | firstcmd=libswd_cmdq_find_head(*cmdq); 200 | lastcmd=*cmdq; 201 | break; 202 | case LIBSWD_OPERATION_TRANSMIT_TAIL: 203 | firstcmd=*cmdq; 204 | lastcmd=libswd_cmdq_find_tail(*cmdq); 205 | break; 206 | case LIBSWD_OPERATION_EXECUTE: 207 | case LIBSWD_OPERATION_TRANSMIT_ALL: 208 | firstcmd=libswd_cmdq_find_head(*cmdq); 209 | lastcmd=libswd_cmdq_find_tail(*cmdq); 210 | break; 211 | case LIBSWD_OPERATION_TRANSMIT_ONE: 212 | firstcmd=*cmdq; 213 | lastcmd=*cmdq; 214 | break; 215 | case LIBSWD_OPERATION_TRANSMIT_LAST: 216 | firstcmd=libswd_cmdq_find_tail(*cmdq); 217 | lastcmd=firstcmd; 218 | break; 219 | default: 220 | return LIBSWD_ERROR_BADOPCODE; 221 | } 222 | 223 | if (firstcmd==NULL) return LIBSWD_ERROR_QUEUEROOT; 224 | if (lastcmd==NULL) return LIBSWD_ERROR_QUEUETAIL; 225 | 226 | if (firstcmd==lastcmd){ 227 | if (!firstcmd->done) { 228 | res=libswd_drv_transmit(libswdctx, firstcmd); 229 | if (res<0) return res; 230 | *cmdq=firstcmd; 231 | } 232 | return 1; 233 | } 234 | 235 | for (cmd=firstcmd;;cmd=cmd->next){ 236 | if (cmd->done){ 237 | if (cmd->next){ 238 | continue; 239 | } else break; 240 | } 241 | res=libswd_drv_transmit(libswdctx, cmd); 242 | if (res<0) return res; 243 | cmdcnt=+res; 244 | if (cmd==lastcmd) break; 245 | } 246 | *cmdq=cmd; 247 | return cmdcnt; 248 | } 249 | 250 | /** @} */ 251 | -------------------------------------------------------------------------------- /src/libswd_core.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 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. 18 | * 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.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_core.c */ 36 | 37 | #include 38 | #include 39 | 40 | /******************************************************************************* 41 | * \defgroup libswd_core Library and Context (de)initialization routines. 42 | * @{ 43 | ******************************************************************************/ 44 | 45 | /** LibSWD initialization routine. 46 | * It should be called prior any operation made with libswd. It initializes 47 | * command queue and basic parameters for context that is returned as pointer. 48 | * \return pointer to the initialized swd context. 49 | */ 50 | libswd_ctx_t *libswd_init(void){ 51 | libswd_ctx_t *libswdctx; 52 | libswdctx=(libswd_ctx_t *)calloc(1,sizeof(libswd_ctx_t)); 53 | if (libswdctx==NULL) return NULL; 54 | libswdctx->driver=(libswd_driver_t *)calloc(1,sizeof(libswd_driver_t)); 55 | if (libswdctx->driver==NULL){ 56 | free(libswdctx); 57 | return NULL; 58 | } 59 | libswdctx->cmdq=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 60 | if (libswdctx->cmdq==NULL) { 61 | libswd_deinit_ctx(libswdctx); 62 | return NULL; 63 | } 64 | libswdctx->config.initialized=LIBSWD_TRUE; 65 | libswdctx->config.trnlen=LIBSWD_TURNROUND_DEFAULT_VAL; 66 | libswdctx->config.maxcmdqlen=LIBSWD_CMDQLEN_DEFAULT; 67 | libswdctx->config.loglevel=LIBSWD_LOGLEVEL_DEFAULT; 68 | libswdctx->config.autofixerrors=LIBSWD_AUTOFIX_DEFAULT; 69 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: Using " PACKAGE_STRING " (http://libswd.sf.net)\nLIBSWD_N: (c) Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info)\n"); 70 | return libswdctx; 71 | } 72 | 73 | /** De-initialize selected swd context and free its memory. 74 | * Note: This function will not free command queue for selected context! 75 | * \param *libswdctx swd context pointer. 76 | * \return LIBSWD_OK on success, LIBSWD_ERROR_CODE on failure. 77 | */ 78 | int libswd_deinit_ctx(libswd_ctx_t *libswdctx){ 79 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLPOINTER; 80 | free(libswdctx); 81 | return LIBSWD_OK; 82 | } 83 | 84 | /** De-initialize command queue and free its memory on selected swd context. 85 | * \param *libswdctx swd context pointer. 86 | * \return number of commands freed, or LIBSWD_ERROR_CODE on failure. 87 | */ 88 | int libswd_deinit_cmdq(libswd_ctx_t *libswdctx){ 89 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLPOINTER; 90 | int res; 91 | res=libswd_cmdq_free(libswdctx->cmdq); 92 | if (res<0) return res; 93 | return res; 94 | } 95 | 96 | /** De-initialize selected swd context and its command queue. 97 | * \param *libswdctx swd context pointer. 98 | * \return number of elements freed, or LIBSWD_ERROR_CODE on failure. 99 | */ 100 | int libswd_deinit(libswd_ctx_t *libswdctx){ 101 | int res, cmdcnt=0; 102 | if (libswdctx->membuf.data) free(libswdctx->membuf.data); 103 | res=libswd_deinit_cmdq(libswdctx); 104 | if (res<0) return res; 105 | cmdcnt=res; 106 | res=libswd_deinit_ctx(libswdctx); 107 | if (res<0) return res; 108 | return cmdcnt+res; 109 | } 110 | 111 | /** @} */ 112 | -------------------------------------------------------------------------------- /src/libswd_debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Debug Functionalities Body File. 4 | * 5 | * Copyright (C) 2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 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. 18 | * 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.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_debug.c Debug Related Routines. */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_debug High-level Debug operations using SWD DAP. 41 | ******************************************************************************/ 42 | 43 | /** Detect Debug Unit. 44 | * This is the full initialization and setup of the SW-DP. 45 | * It may come handy to bring DAP to a known state on error/stall etc. 46 | * \param *libswdctx swd context pointer. 47 | * \param operation type (LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE). 48 | * \return LIBSWD_OK if Debug Unit is supported, LIBSWD_ERROR_UNSUPPORTED otherwise. 49 | */ 50 | int libswd_debug_detect(libswd_ctx_t *libswdctx, libswd_operation_t operation) 51 | { 52 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_I: Executing libswd_debug_detect(*libswdctx=%p, operation=%s)\n", (void*)libswdctx, libswd_operation_string(operation)); 53 | 54 | if (!libswdctx) return LIBSWD_ERROR_NULLCONTEXT; 55 | int retval=0, cpuid; 56 | unsigned int i; 57 | 58 | if (!libswdctx->log.memap.initialized) 59 | { 60 | retval=libswd_memap_init(libswdctx, operation); 61 | if (retval<0) return retval; 62 | } 63 | 64 | retval=libswd_memap_read_int_32(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_ARM_DEBUG_CPUID_ADDR, 1, &cpuid); 65 | if (retval<0) return retval; 66 | 67 | for (i=0;ilog.debug.initialized=1; 92 | return LIBSWD_OK; 93 | } 94 | 95 | 96 | int libswd_debug_halt(libswd_ctx_t *libswdctx, libswd_operation_t operation) 97 | { 98 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 99 | if (operation!=LIBSWD_OPERATION_EXECUTE && operation!=LIBSWD_OPERATION_ENQUEUE) return LIBSWD_ERROR_PARAM; 100 | 101 | int retval, i, dbgdhcsr; 102 | 103 | if (!libswdctx->log.debug.initialized) 104 | { 105 | retval=libswd_debug_init(libswdctx, operation); 106 | if (retval<0) return retval; 107 | } 108 | // Halt the CPU. 109 | retval=libswd_memap_read_int_32(libswdctx, operation, LIBSWD_ARM_DEBUG_DHCSR_ADDR, 1, &dbgdhcsr); 110 | if (retval<0) return retval; 111 | for (i=LIBSWD_RETRY_COUNT_DEFAULT;i;i--) 112 | { 113 | dbgdhcsr=LIBSWD_ARM_DEBUG_DHCSR_DBGKEY; 114 | dbgdhcsr|=LIBSWD_ARM_DEBUG_DHCSR_CDEBUGEN; 115 | dbgdhcsr|=LIBSWD_ARM_DEBUG_DHCSR_CHALT; 116 | dbgdhcsr&=~LIBSWD_ARM_DEBUG_DHCSR_CMASKINTS; 117 | retval=libswd_memap_write_int_32(libswdctx, operation, LIBSWD_ARM_DEBUG_DHCSR_ADDR, 1, &dbgdhcsr); 118 | if (retval<0) return retval; 119 | retval=libswd_memap_read_int_32(libswdctx, operation, LIBSWD_ARM_DEBUG_DHCSR_ADDR, 1, &dbgdhcsr); 120 | if (retval<0) return retval; 121 | if (dbgdhcsr&LIBSWD_ARM_DEBUG_DHCSR_SHALT) 122 | { 123 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, "LIBSWD_I: libswd_debug_halt(): DHCSR=0x%08X\n", dbgdhcsr); 124 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: libswd_debug_halt(): TARGET HALT OK!\n"); 125 | libswdctx->log.debug.dhcsr=dbgdhcsr; 126 | return LIBSWD_OK; 127 | } 128 | } 129 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_debug_halt(): TARGET HALT ERROR!\n"); 130 | return LIBSWD_ERROR_MAXRETRY; 131 | } 132 | 133 | int libswd_debug_run(libswd_ctx_t *libswdctx, libswd_operation_t operation) 134 | { 135 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 136 | if (operation!=LIBSWD_OPERATION_EXECUTE && operation!=LIBSWD_OPERATION_ENQUEUE) return LIBSWD_ERROR_PARAM; 137 | 138 | int retval, i, dbgdhcsr; 139 | 140 | if (!libswdctx->log.debug.initialized) 141 | { 142 | retval=libswd_debug_init(libswdctx, operation); 143 | if (retval<0) return retval; 144 | } 145 | // UnHalt the CPU. 146 | retval=libswd_memap_read_int_32(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_ARM_DEBUG_DHCSR_ADDR, 1, &dbgdhcsr); 147 | if (retval<0) return retval; 148 | for (i=LIBSWD_RETRY_COUNT_DEFAULT;i;i--) 149 | { 150 | dbgdhcsr=LIBSWD_ARM_DEBUG_DHCSR_DBGKEY; 151 | dbgdhcsr|=LIBSWD_ARM_DEBUG_DHCSR_CDEBUGEN; 152 | dbgdhcsr&=~LIBSWD_ARM_DEBUG_DHCSR_CHALT; 153 | retval=libswd_memap_write_int_32(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_ARM_DEBUG_DHCSR_ADDR, 1, &dbgdhcsr); 154 | if (retval<0) return retval; 155 | retval=libswd_memap_read_int_32(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_ARM_DEBUG_DHCSR_ADDR, 1, &dbgdhcsr); 156 | if (retval<0) return retval; 157 | if (!(dbgdhcsr&LIBSWD_ARM_DEBUG_DHCSR_SHALT)) 158 | { 159 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: libswd_debug_run(): TARGET RUN OK!\n"); 160 | libswdctx->log.debug.dhcsr=dbgdhcsr; 161 | return LIBSWD_OK; 162 | } 163 | 164 | } 165 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_debug_run(): TARGET RUN ERROR!\n"); 166 | return LIBSWD_ERROR_MAXRETRY; 167 | } 168 | 169 | int libswd_debug_is_halted(libswd_ctx_t *libswdctx, libswd_operation_t operation) 170 | { 171 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 172 | if (operation!=LIBSWD_OPERATION_EXECUTE && operation!=LIBSWD_OPERATION_ENQUEUE) return LIBSWD_ERROR_PARAM; 173 | 174 | return (libswdctx->log.debug.dhcsr&LIBSWD_ARM_DEBUG_DHCSR_SHALT)?1:0; 175 | } 176 | 177 | 178 | /** @} */ 179 | -------------------------------------------------------------------------------- /src/libswd_drv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2014, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 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. 18 | * 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.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2014; 32 | * 33 | */ 34 | 35 | /** \file libswd_drv.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_drv SWD Bus and Interface Driver Transfer Functions that 41 | * executes command queue. 42 | * @{ 43 | ******************************************************************************/ 44 | 45 | extern int libswd_drv_mosi_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst); 46 | extern int libswd_drv_mosi_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst); 47 | extern int libswd_drv_miso_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst); 48 | extern int libswd_drv_miso_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst); 49 | extern int libswd_drv_mosi_trn(libswd_ctx_t *libswdctx, int bits); 50 | extern int libswd_drv_miso_trn(libswd_ctx_t *libswdctx, int bits); 51 | 52 | /** Transmit selected command from the *cmdq to the interface driver. 53 | * Also update the libswdctx->log structure (this should be done only here!). 54 | * Because commands that were queued does not get ack/parity data anymore, 55 | * we need to verify ACK/PARITY that was just read and return error if necesary. 56 | * When ACK/PARITY error is detected queue tail is removed as it is invalid. 57 | * When CTRL/STAT:STICKYORUN=1 ACK={WAIT,FAULT] requires additional data phase. 58 | * \param *libswdctx swd context pointer. 59 | * \param *cmd pointer to the command to be sent. 60 | * \return number of commands transmitted (1), or LIBSWD_ERROR_CODE on failure. 61 | */ 62 | int libswd_drv_transmit(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd){ 63 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 64 | if (cmd==NULL) return LIBSWD_ERROR_NULLPOINTER; 65 | 66 | int res=LIBSWD_ERROR_BADCMDTYPE, errcode=LIBSWD_ERROR_RESULT; 67 | 68 | switch (cmd->cmdtype){ 69 | case LIBSWD_CMDTYPE_MOSI: 70 | case LIBSWD_CMDTYPE_MISO: 71 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, "LIBSWD_W: libswd_drv_transmit(): This command does not contain payload."); 72 | break; 73 | 74 | case LIBSWD_CMDTYPE_MOSI_CONTROL: 75 | // 8 clock cycles. 76 | if (cmd->bits!=8) return LIBSWD_ERROR_BADCMDDATA; 77 | res=libswd_drv_mosi_8(libswdctx, cmd, &cmd->control, 8, LIBSWD_DIR_LSBFIRST); 78 | if (res>=0) libswdctx->log.write.control=cmd->control; 79 | break; 80 | 81 | case LIBSWD_CMDTYPE_MOSI_BITBANG: 82 | // 1 clock cycle. 83 | if (cmd->bits!=1) return LIBSWD_ERROR_BADCMDDATA; 84 | res=libswd_drv_mosi_8(libswdctx, cmd, &cmd->mosibit, 1, LIBSWD_DIR_LSBFIRST); 85 | if (res>=0) libswdctx->log.write.bitbang=cmd->mosibit; 86 | break; 87 | 88 | case LIBSWD_CMDTYPE_MOSI_PARITY: 89 | // 1 clock cycle. 90 | if (cmd->bits!=1) return LIBSWD_ERROR_BADCMDDATA; 91 | res=libswd_drv_mosi_8(libswdctx, cmd, &cmd->parity, 1, LIBSWD_DIR_LSBFIRST); 92 | if (res>=0) libswdctx->log.write.parity=cmd->parity; 93 | break; 94 | 95 | case LIBSWD_CMDTYPE_MOSI_TRN: 96 | // 1..4-bit clock cycle. 97 | if (cmd->bitsbits>LIBSWD_TURNROUND_MAX_VAL) 98 | return LIBSWD_ERROR_BADCMDDATA; 99 | res=libswd_drv_mosi_trn(libswdctx, cmd->bits); 100 | break; 101 | 102 | case LIBSWD_CMDTYPE_MOSI_REQUEST: 103 | // 8 clock cycles. 104 | if (cmd->bits!=LIBSWD_REQUEST_BITLEN) return LIBSWD_ERROR_BADCMDDATA; 105 | res=libswd_drv_mosi_8(libswdctx, cmd, &cmd->request, 8, LIBSWD_DIR_LSBFIRST); 106 | if (res>=0){ 107 | libswdctx->log.write.request=cmd->request; 108 | // Log human-readable request fields for easier transmission debug. 109 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: Sending Request: %s\n", \ 110 | libswd_request_string(libswdctx, cmd->request)); 111 | } 112 | break; 113 | 114 | case LIBSWD_CMDTYPE_MOSI_DATA: 115 | // 32 clock cycles. 116 | if (cmd->bits!=LIBSWD_DATA_BITLEN) return LIBSWD_ERROR_BADCMDDATA; 117 | res=libswd_drv_mosi_32(libswdctx, cmd, &cmd->mosidata, 32, LIBSWD_DIR_LSBFIRST); 118 | if (res>=0) libswdctx->log.write.data=cmd->mosidata; 119 | break; 120 | 121 | case LIBSWD_CMDTYPE_MISO_ACK: 122 | // 3 clock cycles. 123 | if (cmd->bits!=LIBSWD_ACK_BITLEN) return LIBSWD_ERROR_BADCMDDATA; 124 | res=libswd_drv_miso_8(libswdctx, cmd, &cmd->ack, cmd->bits, LIBSWD_DIR_LSBFIRST); 125 | if (res>=0) libswdctx->log.read.ack=cmd->ack; 126 | break; 127 | 128 | case LIBSWD_CMDTYPE_MISO_BITBANG: 129 | // 1 clock cycle. 130 | if (cmd->bits!=1) return LIBSWD_ERROR_BADCMDDATA; 131 | res=libswd_drv_miso_8(libswdctx, cmd, &cmd->misobit, 1, LIBSWD_DIR_LSBFIRST); 132 | if (res>=0) libswdctx->log.read.bitbang=cmd->misobit; 133 | break; 134 | 135 | case LIBSWD_CMDTYPE_MISO_PARITY: 136 | // 1 clock cycle. 137 | if (cmd->bits!=1) return LIBSWD_ERROR_BADCMDDATA; 138 | res=libswd_drv_miso_8(libswdctx, cmd, &cmd->parity, 1, LIBSWD_DIR_LSBFIRST); 139 | if (res>=0) libswdctx->log.read.parity=cmd->parity; 140 | break; 141 | 142 | case LIBSWD_CMDTYPE_MISO_TRN: 143 | // 1..4 clock cycles 144 | if (cmd->bitsbits>LIBSWD_TURNROUND_MAX_VAL) 145 | return LIBSWD_ERROR_BADCMDDATA; 146 | res=libswd_drv_miso_trn(libswdctx, cmd->bits); 147 | break; 148 | 149 | case LIBSWD_CMDTYPE_MISO_DATA: 150 | // 32 clock cycles 151 | if (cmd->bits!=LIBSWD_DATA_BITLEN) return LIBSWD_ERROR_BADCMDDATA; 152 | res=libswd_drv_miso_32(libswdctx, cmd, &cmd->misodata, cmd->bits, LIBSWD_DIR_LSBFIRST); 153 | if (res>=0) libswdctx->log.read.data=cmd->misodata; 154 | break; 155 | 156 | case LIBSWD_CMDTYPE_UNDEFINED: 157 | res=0; 158 | break; 159 | 160 | default: 161 | return LIBSWD_ERROR_BADCMDTYPE; 162 | } 163 | 164 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_PAYLOAD, 165 | "LIBSWD_P: libswd_drv_transmit(libswdctx=@%p, cmd=@%p) bits=%-2d cmdtype=%-12s returns=%-3d payload=0x%08x (%s)\n", 166 | libswdctx, cmd, cmd->bits, libswd_cmd_string_cmdtype(cmd), res, 167 | (cmd->bits>8)?cmd->data32:cmd->data8, 168 | (cmd->bits<=8)?libswd_bin8_string(&cmd->data8):libswd_bin32_string(&cmd->data32)); 169 | 170 | if (res<0) return res; 171 | cmd->done=1; 172 | 173 | /* Now verify the ACK value, notify caller about possible errors, truncate cmdq if libswdctx.config.autofixerrors is not set. 174 | * Accodring to ADIv5.0 specification (ARM IHI 0031A, section 5.4.5) data phase is required when STICKYORUN=1. 175 | * Unfortunately at this point we cannot read the CTRL/STAT flag, so we will write zeros to avoid random Request. 176 | */ 177 | if (cmd->cmdtype==LIBSWD_CMDTYPE_MISO_ACK){ 178 | switch(cmd->ack){ 179 | // If the ACK was OK then simply return to the caller. 180 | case LIBSWD_ACK_OK_VAL: return res; 181 | // For other ACK codes produce a warning and remember the code. 182 | case LIBSWD_ACK_FAULT_VAL: 183 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 184 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): LIBSWD_ACK_FAULT detected!\n", 185 | (void*)libswdctx, (void*)cmd ); 186 | errcode=LIBSWD_ERROR_ACK_FAULT; 187 | break; 188 | case LIBSWD_ACK_WAIT_VAL: 189 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 190 | "LIBSWD_D: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): LIBSWD_ACK_WAIT detectd!\n", 191 | (void*)libswdctx, (void*)cmd ); 192 | errcode=LIBSWD_ERROR_ACK_WAIT; 193 | break; 194 | default: 195 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 196 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): UnknownACK/ProtocolErrorSequence! Target Powered Off?\n", 197 | (void*)libswdctx, (void*)cmd ); 198 | errcode=LIBSWD_ERROR_ACKUNKNOWN; 199 | } 200 | // If libswdctx.config.autofixerrors is not set, on error truncate cmdq, append+execute dummy data phase, then let caller handle situation. 201 | // The reason for clearing out the queue is to preserve synchronization with Target. 202 | // As data phase is required in some situations and data are already enqueued use data pointers not to crash applications that rely on that poiters... 203 | if (!libswdctx->config.autofixerrors){ 204 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 205 | "LIBSWD_D: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): ACK!=OK, clearing cmdq tail to preserve synchronization...\n", 206 | (void*)libswdctx, (void*)cmd ); 207 | // Save DATA and PARITY queue elements for ACK={WAIT,FAULT} as they may be referenced by application. 208 | if (errcode==LIBSWD_ERROR_ACK_WAIT || errcode==LIBSWD_ERROR_ACK_FAULT) 209 | if (cmd->next) if(cmd->next->next) cmd=cmd->next->next; 210 | // Now free the queue tail. 211 | if (libswd_cmdq_free_tail(cmd)<0) { 212 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 213 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Cannot free cmdq tail in ACK error handling routine, Protocol Error Sequence imminent...\n", 214 | (void*)libswdctx, (void*)cmd ); 215 | return LIBSWD_ERROR_QUEUENOTFREE; 216 | } 217 | // TODO: MOVE THIS INTO SEPARATE ERROR HANDLING ROUTINE 218 | // If ACK={WAIT,FAULT} then append data phase and again flush the queue to maintain sync. 219 | // MOSI_TRN + 33 zero data cycles should be universal for STICKYORUN={0,1} ??? 220 | if (errcode==LIBSWD_ERROR_ACK_WAIT || errcode==LIBSWD_ERROR_ACK_FAULT){ 221 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Performing data phase after ACK={WAIT,FAULT}...\n", (void*)libswdctx, (void*)cmd); 222 | int data=0; 223 | char parity=0; 224 | res=libswd_bus_write_data_p(libswdctx, LIBSWD_OPERATION_EXECUTE, &data, &parity); 225 | if (res<0){ 226 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 227 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Cannot perform data phase after ACK=WAIT/FAIL, Protocol Error Sequence imminent...\n", 228 | (void*)libswdctx, (void*)cmd ); 229 | } 230 | // Caller now should read CTRL/STAT and clear STICKY Error Flags at this point. 231 | } 232 | } else { 233 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 234 | "LIBSWD_D: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): libswdctx->config.autofixerrors is set, applying error handling...\n", (void*)libswdctx, (void*)cmd ); 235 | res=libswd_error_handle(libswdctx); 236 | if (res<0){ 237 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "libswd_drv_transmit(libswdctx=@%p, @%p): error handling failed, %s\n", (void*)libswdctx, (void*)cmd, libswd_error_string(res)); 238 | return res; 239 | } 240 | errcode=LIBSWD_OK; 241 | } 242 | return errcode; 243 | } 244 | 245 | 246 | /* Verify the PARITY value and notify caller about possible errors. 247 | * If error was detected, delete trailing queue elements. 248 | */ 249 | if (cmd->cmdtype==LIBSWD_CMDTYPE_MISO_PARITY){ 250 | // Parity must be preceded with data, look for that data and verify parity. 251 | if (cmd->prev->cmdtype==LIBSWD_CMDTYPE_MISO_DATA){ 252 | char testparity; 253 | // Calculate parity based on data value or give warning it cannot be performed. 254 | if (libswd_bin32_parity_even(&cmd->prev->misodata, &testparity)<0) 255 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 256 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Cannot perform parity check (calculation error).\n", 257 | (void*)libswdctx, (void*)cmd ); 258 | // Verify calculated data parity with value received from target. 259 | if (cmd->parity!=testparity){ 260 | // Give error message. 261 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 262 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Parity mismatch detected (%s/%d)!\n", 263 | (void*)libswdctx, (void*)cmd, libswd_bin32_string(&cmd->prev->misodata), cmd->parity ); 264 | // Clean the cmdq tail (as it contains invalid operations). 265 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 266 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Bad PARITY, clearing cmdq tail to preserve synchronization...\n", 267 | (void*)libswdctx, (void*)cmd ); 268 | if (libswd_cmdq_free_tail(cmd)<0) { 269 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 270 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Cannot free cmdq tail in PARITY error hanlig routine!\n", 271 | (void*)libswdctx, (void*)cmd); 272 | return LIBSWD_ERROR_QUEUENOTFREE; 273 | } 274 | // Return parity error. 275 | return LIBSWD_ERROR_PARITY; 276 | } 277 | } else { 278 | // If data element was not found then parity cannot be calculated. 279 | // Give warning about that but does not return an error, as queue might be cleaned just before. 280 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 281 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Cannot perform parity check (data missing).\n", 282 | (void*)libswdctx, (void*)cmd ); 283 | return res; 284 | } 285 | } 286 | 287 | /* Everyting went fine, return number of elements processed. */ 288 | return res; 289 | } 290 | 291 | /** @} */ 292 | -------------------------------------------------------------------------------- /src/libswd_error.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 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. 18 | * 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.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_error.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_error Error handling and information routines. 41 | * @{ 42 | ******************************************************************************/ 43 | 44 | char *libswd_error_string(libswd_error_code_t error){ 45 | switch (error){ 46 | case LIBSWD_OK: return "[LIBSWD_OK] hmm, there was no error"; 47 | case LIBSWD_ERROR_GENERAL: return "[LIBSWD_ERROR_GENERAL] general error"; 48 | case LIBSWD_ERROR_NULLPOINTER: return "[LIBSWD_ERROR_NULLPOINTER] null pointer"; 49 | case LIBSWD_ERROR_NULLQUEUE: return "[LIBSWD_ERROR_NULLQUEUE] null queue"; 50 | case LIBSWD_ERROR_NULLTRN: return "[LIBSWD_ERROR_NULLTRN] null turnaround"; 51 | case LIBSWD_ERROR_PARAM: return "[LIBSWD_ERROR_PARAM] bad parameter"; 52 | case LIBSWD_ERROR_OUTOFMEM: return "[LIBSWD_ERROR_OUTOFMEM] out of memory"; 53 | case LIBSWD_ERROR_RESULT: return "[LIBSWD_ERROR_RESULT] bad result"; 54 | case LIBSWD_ERROR_RANGE: return "[LIBSWD_ERROR_RANGE] out of range"; 55 | case LIBSWD_ERROR_DEFINITION: return "[LIBSWD_ERROR_DEFINITION] definition error"; 56 | case LIBSWD_ERROR_NULLCONTEXT: return "[LIBSWD_ERROR_NULLCONTEXT] null context"; 57 | case LIBSWD_ERROR_QUEUE: return "[LIBSWD_ERROR_QUEUE] queue error"; 58 | case LIBSWD_ERROR_ADDR: return "[LIBSWD_ERROR_ADDR] addressing error"; 59 | case LIBSWD_ERROR_APnDP: return "[LIBSWD_ERROR_APnDP] bad APnDP value"; 60 | case LIBSWD_ERROR_RnW: return "[LIBSWD_ERROR_RnW] bad RnW value"; 61 | case LIBSWD_ERROR_PARITY: return "[LIBSWD_ERROR_PARITY] parity error"; 62 | case LIBSWD_ERROR_ACK: return "[LIBSWD_ERROR_ACK] acknowledge error"; 63 | case LIBSWD_ERROR_ACKUNKNOWN: return "[LIBSWD_ERROR_ACKUNKNOWN] got unknown acknowledge"; 64 | case LIBSWD_ERROR_ACKNOTDONE: return "[LIBSWD_ERROR_ACKNOTDONE] not yet executed on target"; 65 | case LIBSWD_ERROR_ACKMISSING: return "[LIBSWD_ERROR_ACKMISSING] command not found on the queue"; 66 | case LIBSWD_ERROR_ACKMISMATCH: return "[LIBSWD_ERROR_ACKMISMATCH] different result address/value expected"; 67 | case LIBSWD_ERROR_ACKORDER: return "[LIBSWD_ERROR_ACKORDER] cmdq not in sequence REQ->TRN->ACK"; 68 | case LIBSWD_ERROR_BADOPCODE: return "[LIBSWD_ERROR_BADOPCODE] unsupported operation requested"; 69 | case LIBSWD_ERROR_NODATACMD: return "[LIBSWD_ERROR_NODATACMD] command not found on the queue"; 70 | case LIBSWD_ERROR_DATAPTR: return "[LIBSWD_ERROR_DATAPTR] bad data pointer address"; 71 | case LIBSWD_ERROR_NOPARITYCMD: return "[LIBSWD_ERROR_NOPARITYCMD] parity command missing or misplaced"; 72 | case LIBSWD_ERROR_PARITYPTR: return "[LIBSWD_ERROR_PARITYPTR] bad parity pointer address"; 73 | case LIBSWD_ERROR_NOTDONE: return "[LIBSWD_ERROR_NOTDONE] could not end selected task"; 74 | case LIBSWD_ERROR_QUEUEROOT: return "[LIBSWD_ERROR_QUEUEROOT] queue root not found or null"; 75 | case LIBSWD_ERROR_QUEUETAIL: return "[LIBSWD_ERROR_QUEUETAIL] queue tail not found or null"; 76 | case LIBSWD_ERROR_BADCMDTYPE: return "[LIBSWD_ERROR_BADCMDTYPE] unknown command detected"; 77 | case LIBSWD_ERROR_BADCMDDATA: return "[LIBSWD_ERROR_BADCMDDATA] command contains bad data (out of range, etc)"; 78 | case LIBSWD_ERROR_ACK_WAIT: return "[LIBSWD_ERROR_ACK_WAIT] got ACK_WAIT response"; 79 | case LIBSWD_ERROR_ACK_FAULT: return "[LIBSWD_ERROR_ACK_FAULT] got ACK_FAULT response"; 80 | case LIBSWD_ERROR_QUEUENOTFREE: return "[LIBSWD_ERROR_QUEUENOTFREE] cannot free resources, queue not empty"; 81 | case LIBSWD_ERROR_TRANSPORT: return "[LIBSWD_ERROR_TRANSPORT] transport error or undefined"; 82 | case LIBSWD_ERROR_DIRECTION: return "[LIBSWD_ERROR_DIRECTION] MSb/LSb direction error"; 83 | case LIBSWD_ERROR_LOGLEVEL: return "[LIBSWD_ERROR_LOGLEVEL] invalid loglevel value"; 84 | case LIBSWD_ERROR_UNHANDLED: return "[LIBSWD_ERROR_UNHANDLED] cannot handle that error automatically"; 85 | case LIBSWD_ERROR_MAXRETRY: return "[LIBSWD_ERROR_MAXRETRY] maximum retry count exceeded"; 86 | case LIBSWD_ERROR_CLISYNTAX: return "[LIBSWD_ERROR_CLISYNTAX] CLI syntax error, see '?' for help"; 87 | case LIBSWD_ERROR_FILE: return "[LIBSWD_ERROR_FILE] file I/O related problem"; 88 | case LIBSWD_ERROR_UNSUPPORTED: return "[LIBSWD_ERROR_UNSUPPORTED] Target not supported"; 89 | case LIBSWD_ERROR_MEMAPACCSIZE: return "[LIBSWD_ERROR_MEMAPACCSIZE] Invalid MEM-AP access size"; 90 | case LIBSWD_ERROR_MEMAPALIGN: return "[LIBSWD_ERROR_MEMAPALIGN] Invalid address alignment for access size"; 91 | default: return "undefined error"; 92 | } 93 | return "undefined error"; 94 | } 95 | 96 | 97 | int libswd_error_handle(libswd_ctx_t *libswdctx){ 98 | // At this point we got negative return code from libswd_cmd_flush() so we need to handle errors accordingly here. 99 | // libswdctx->cmdq should point to the last element executed that produced error. 100 | int retval; 101 | libswd_cmd_t *exectail; 102 | 103 | // Verify if libswdctx->cmdq contains last executed element, correct if necessary. 104 | exectail=libswd_cmdq_find_exectail(libswdctx->cmdq); 105 | if (exectail==NULL) { 106 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_error_handle(libswdctx=@%p): Cannot find last executed element on the queue!\n", (void*)libswdctx); 107 | return LIBSWD_ERROR_QUEUE; 108 | } 109 | if (exectail!=libswdctx->cmdq){ 110 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, "LIBSWD_I: libswd_error_handle(libswdctx=@%p): Correcting libswdctx->cmdq to match last executed element...\n", (void*)libswdctx); 111 | libswdctx->cmdq=exectail; 112 | } 113 | 114 | switch (libswdctx->cmdq->cmdtype){ 115 | case LIBSWD_CMDTYPE_MISO_ACK: 116 | retval=libswd_error_handle_ack(libswdctx); 117 | break; 118 | default: 119 | return LIBSWD_ERROR_UNHANDLED; 120 | } 121 | 122 | if (retval<0){ 123 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, "LIBSWD_W: libswd_error_handle(@%p) failed! on cmdq=@%p", (void*)libswdctx, (void*)libswdctx->cmdq); 124 | } 125 | return retval; 126 | } 127 | 128 | int libswd_error_handle_ack(libswd_ctx_t *libswdctx){ 129 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 130 | // Make sure we are working on the ACK cmdq element. 131 | if (libswdctx->cmdq->cmdtype!=LIBSWD_CMDTYPE_MISO_ACK){ 132 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_error_handle_ack(@%p):libswdctx->cmdq does not point to ACK!", (void*)libswdctx); 133 | return LIBSWD_ERROR_UNHANDLED; //do we want to handle this kind of error here? 134 | } 135 | 136 | switch (libswdctx->cmdq->ack) { 137 | case LIBSWD_ACK_OK_VAL: 138 | // Uhm, there was no error. 139 | // Should we return OK or search for next ACK recursively? 140 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, "LIBSWD_W: libswd_error_handle_ack(libswdctx=@%p): ACK=OK, handling wrong element?\n", (void*)libswdctx); 141 | return LIBSWD_OK; 142 | case LIBSWD_ACK_WAIT_VAL: 143 | return libswd_error_handle_ack_wait(libswdctx); 144 | case LIBSWD_ACK_FAULT_VAL: 145 | // TODO: Handle ACK=FAULT accordingly. 146 | return LIBSWD_ERROR_UNHANDLED; 147 | default: 148 | // TODO: By default we assume lost synchronization, handle accordingly. 149 | return LIBSWD_ERROR_UNHANDLED; 150 | } 151 | } 152 | 153 | int libswd_error_handle_ack_wait(libswd_ctx_t *libswdctx){ 154 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 155 | // Make sure we are working on the ACK cmdq element. 156 | if (libswdctx->cmdq->cmdtype!=LIBSWD_CMDTYPE_MISO_ACK){ 157 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, "LIBSWD_W: libswd_error_handle_ack_wait(libswdctx=@%p):libswdctx->cmdq does not point to ACK!", (void*)libswdctx); 158 | return LIBSWD_ERROR_UNHANDLED; //do we want to handle this kind of error here? 159 | } 160 | // Make sure the ACK contains WAIT response. 161 | if (libswdctx->cmdq->ack!=LIBSWD_ACK_WAIT_VAL){ 162 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, "LIBSWD_W: libswd_error_handle_ack_wait(libswdctx=@%p):libswdctx->cmdq->ack does not contain WAIT response!", (void*)libswdctx); 163 | return LIBSWD_ERROR_ACKMISMATCH; 164 | } 165 | 166 | //TODO: NOW DECIDE IF AN OPERATION WAS READ OR WRITE AND PERFORM RETRY ACCORDINGLY 167 | // READ AND WRITE WILL HAVE DIFFERENT RETRY SEQUENCES 168 | 169 | char request = libswdctx->cmdq->prev->prev->request; 170 | char *ack, *rparity; 171 | char parity=0; 172 | 173 | // Remember original cmdq, restore on return. 174 | libswd_cmd_t *mastercmdq = libswdctx->cmdq; 175 | 176 | // Append dummy data phase, fix sticky flags and retry operation. 177 | int retval=0, *ctrlstat, *rdata, abort, retrycnt=50; 178 | // retval=libswd_cmdq_init(errors); 179 | libswdctx->cmdq->errors=(libswd_cmd_t*)calloc(1,sizeof(libswd_cmd_t)); 180 | //retval = LIBSWD_ERROR_OUTOFMEM; 181 | if (libswdctx->cmdq->errors==NULL) goto libswd_error_handle_ack_wait_end; 182 | libswdctx->cmdq=libswdctx->cmdq->errors; // From now, this becomes out main cmdq for use with standard functions. 183 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_error_handle_ack_wait(libswdctx=@%p): Performing data phase after ACK={WAIT,FAULT}...\n", (void*)libswdctx); 184 | int data=0; 185 | retval=libswd_bus_write_data_p(libswdctx, LIBSWD_OPERATION_EXECUTE, &data, &parity); 186 | if (retval<0) goto libswd_error_handle_ack_wait_end; 187 | 188 | // NOW WE CAN HANDLE MEM-AP READ RETRY: 189 | // 1. READ STICKY FLAGS FROM CTRL/STAT 190 | // 2. CLEAR STICKY FLAGS IN ABORT - this will discard AP transaction 191 | // 3. RETRY MEM-AP DRW READ - now it must be ACK=OK (it will return last mem-ap read result). 192 | // 4. READ DP RDBUFF TO OBTAIN READ DATA 193 | 194 | for (retrycnt=50/*LIBSWD_RETRY_COUNT_DEFAULT*/; retrycnt>0; retrycnt--){ 195 | retval=libswd_dp_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_DP_CTRLSTAT_ADDR, &ctrlstat); 196 | if (retval<0) goto libswd_error_handle_ack_wait_end; 197 | abort=0x00000014; 198 | retval=libswd_dp_write(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_DP_ABORT_ADDR, &abort); 199 | if (retval<0) goto libswd_error_handle_ack_wait_end; 200 | retval=libswd_bus_write_request_raw(libswdctx, LIBSWD_OPERATION_ENQUEUE, &request); 201 | retval=libswd_bus_read_ack(libswdctx, LIBSWD_OPERATION_EXECUTE, &ack); 202 | if (retval<0 || *ack!=LIBSWD_ACK_OK_VAL) goto libswd_error_handle_ack_wait_end; 203 | retval=libswd_bus_read_data_p(libswdctx, LIBSWD_OPERATION_EXECUTE, &rdata, &rparity); 204 | if (retval<0) goto libswd_error_handle_ack_wait_end; 205 | 206 | retval=libswd_dp_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_DP_CTRLSTAT_ADDR, &ctrlstat); 207 | if (retval<0) goto libswd_error_handle_ack_wait_end; 208 | 209 | 210 | if (*ctrlstat&LIBSWD_DP_CTRLSTAT_READOK){ 211 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "=========================GOT RESPONSE===========================\n\n\n"); 212 | retval=libswd_dp_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_DP_RDBUFF_ADDR, &rdata); 213 | if (retval<0) goto libswd_error_handle_ack_wait_end; 214 | break; 215 | } 216 | } 217 | if (retrycnt==0){ 218 | retval=LIBSWD_ERROR_MAXRETRY; 219 | goto libswd_error_handle_ack_wait_end; 220 | } 221 | 222 | //Make sure we have RDATA and PARITY elements after libswdctx->cmdq. 223 | //Should we check for this at the procedure start??? 224 | libswdctx->cmdq=mastercmdq; 225 | if (libswdctx->cmdq->cmdtype==LIBSWD_CMDTYPE_MISO_ACK && libswdctx->cmdq->next->cmdtype==LIBSWD_CMDTYPE_MISO_DATA && libswdctx->cmdq->next->next->cmdtype==LIBSWD_CMDTYPE_MISO_PARITY){ 226 | libswdctx->cmdq->ack=LIBSWD_ACK_OK_VAL; 227 | libswdctx->cmdq=libswdctx->cmdq->next; 228 | libswdctx->cmdq->misodata=*rdata; 229 | libswdctx->cmdq->done=1; 230 | libswdctx->cmdq=libswdctx->cmdq->next; 231 | //libswd_bin8_parity_even(rdata, &parity); 232 | libswdctx->cmdq->parity=*rparity; 233 | libswdctx->cmdq->done=1; 234 | return LIBSWD_OK; 235 | } else libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: UNSUPPORTED COMMAND SEQUENCE ON CMDQ (NOT ACK->RDATA->PARITY)\n"); 236 | 237 | 238 | // At this point we should have the read result from RDBUFF ready for MEM-AP read fix. 239 | 240 | 241 | libswd_error_handle_ack_wait_end: 242 | // Exit ACK WAIT handling routine, verify retval before return. 243 | if (retval<0||retrycnt==0){ 244 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_error_handle_ack_wait(libswdctx=@%p) ejecting: %s\n", (void*)libswdctx, libswd_error_string(retval)); 245 | } 246 | 247 | libswdctx->cmdq=mastercmdq; 248 | while (1) {printf("ACK WAIT HANDLER\n");usleep(1000);} 249 | return retval; 250 | } 251 | /** @} */ 252 | -------------------------------------------------------------------------------- /src/libswd_externs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * External Handlers Definition File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 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. 18 | * 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.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_externs.c Template for driver bridge between libswd and your application. */ 36 | 37 | #include 38 | #include 39 | 40 | int libswd_drv_mosi_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst){ 41 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 42 | if (bits<0 && bits>8) return LIBSWD_ERROR_PARAM; 43 | if (nLSBfirst!=0 && nLSBfirst!=1) return LIBSWD_ERROR_PARAM; 44 | 45 | // Your code goes here... 46 | 47 | return bits; 48 | } 49 | 50 | 51 | int libswd_drv_mosi_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst){ 52 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 53 | if (bits<0 && bits>8) return LIBSWD_ERROR_PARAM; 54 | if (nLSBfirst!=0 && nLSBfirst!=1) return LIBSWD_ERROR_PARAM; 55 | 56 | // Your code goes here... 57 | 58 | return bits; 59 | } 60 | 61 | int libswd_drv_miso_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst){ 62 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 63 | if (bits<0 && bits>8) return LIBSWD_ERROR_PARAM; 64 | if (nLSBfirst!=0 && nLSBfirst!=1) return LIBSWD_ERROR_PARAM; 65 | 66 | // Your code goes here... 67 | 68 | return bits; 69 | } 70 | 71 | int libswd_drv_miso_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst){ 72 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 73 | if (bits<0 && bits>8) return LIBSWD_ERROR_PARAM; 74 | if (nLSBfirst!=0 && nLSBfirst!=1) return LIBSWD_ERROR_PARAM; 75 | 76 | // Your code goes here... 77 | 78 | return bits; 79 | } 80 | 81 | 82 | /* This function sets interface buffers to MOSI direction. 83 | * Master Output Slave Input - SWD Write operation. 84 | * bits specify how many clock cycles must be used. */ 85 | int libswd_drv_mosi_trn(libswd_ctx_t *libswdctx, int bits){ 86 | if (bitsLIBSWD_TURNROUND_MAX_VAL) 87 | return LIBSWD_ERROR_TURNAROUND; 88 | 89 | // Your code goes here... 90 | 91 | return bits; 92 | } 93 | 94 | int libswd_drv_miso_trn(libswd_ctx_t *libswdctx, int bits){ 95 | if (bitsLIBSWD_TURNROUND_MAX_VAL) 96 | return LIBSWD_ERROR_TURNAROUND; 97 | 98 | // Your code goes here... 99 | 100 | return bits; 101 | } 102 | 103 | 104 | /** Set debug level according to caller's application settings. 105 | * \params *libswdctx swd context to work on. 106 | * \params loglevel caller's application log level to be converted. 107 | * \return LIBSWD_OK on success, of error code on failure. 108 | */ 109 | int libswd_log_level_inherit(libswd_ctx_t *libswdctx, int loglevel){ 110 | if (libswdctx==NULL){ 111 | // log(LOG_LEVEL_DEBUG, "libswd_log_level_inherit(): SWD Context not (yet) initialized...\n"); 112 | return LIBSWD_OK; 113 | } 114 | 115 | libswd_loglevel_t new_swdlevel; 116 | switch (loglevel){ 117 | // Your code goes here... 118 | default: 119 | new_swdlevel=LIBSWD_LOGLEVEL_NORMAL; 120 | } 121 | 122 | int res=libswd_log_level_set(libswdctx, new_swdlevel); 123 | if (res<0) { 124 | // Your error routine goes here... 125 | // return URJ_ERROR_SYNTAX; 126 | } else return LIBSWD_OK; 127 | } 128 | 129 | /** By default we want to use internal logging mechanisms. 130 | * It is possible however to use target program mechanisms to log messages. 131 | * In order to correctly parse variable number of arguments we need to use 132 | * dedicated libswd_log_internal_va() function... 133 | */ 134 | int libswd_log(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel, char *msg, ...){ 135 | int retval; 136 | va_list ap; 137 | va_start(ap, msg); 138 | retval=libswd_log_internal_va(libswdctx, loglevel, msg, ap); 139 | va_end(ap); 140 | return retval; 141 | }; 142 | 143 | -------------------------------------------------------------------------------- /src/libswd_log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 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. 18 | * 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.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_log.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_log Miscelanous logging functionalities. 41 | * @{ 42 | ******************************************************************************/ 43 | 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(). 50 | */ 51 | extern int libswd_log(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel, char *msg, ...); 52 | 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. 61 | */ 62 | int libswd_log_internal(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel, char *msg, ...){ 63 | if (loglevelLIBSWD_LOGLEVEL_MAX) 64 | return LIBSWD_ERROR_LOGLEVEL; 65 | if (loglevel > libswdctx->config.loglevel) return LIBSWD_OK; 66 | int res; 67 | va_list ap; 68 | va_start(ap, msg); 69 | res=vprintf(msg, ap); 70 | va_end(ap); 71 | return res; 72 | } 73 | 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. 81 | */ 82 | int libswd_log_internal_va(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel, char *fmt, va_list ap){ 83 | if (loglevelLIBSWD_LOGLEVEL_MAX) 84 | return LIBSWD_ERROR_LOGLEVEL; 85 | if (loglevel > libswdctx->config.loglevel) return LIBSWD_OK; 86 | int res; 87 | res=vprintf(fmt, ap); 88 | return res; 89 | } 90 | 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. 95 | */ 96 | int libswd_log_level_set(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel){ 97 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 98 | if (loglevelLIBSWD_LOGLEVEL_MAX) 99 | return LIBSWD_ERROR_LOGLEVEL; 100 | 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)); 103 | return LIBSWD_OK; 104 | } 105 | 106 | /** Return integer log level value. 107 | * \param *libswdctx swd context. 108 | * \return integer log level value or LIBSWD_ERROR code on failure. 109 | */ 110 | int libswd_log_level_get(libswd_ctx_t *libswdctx){ 111 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 112 | return libswdctx->config.loglevel; 113 | } 114 | 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. 118 | */ 119 | const char *libswd_log_level_string(libswd_loglevel_t loglevel){ 120 | switch (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"; 128 | } 129 | return "UNKNOWN_LOGLEVEL"; 130 | }; 131 | 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. 135 | */ 136 | const char *libswd_operation_string(libswd_operation_t operation){ 137 | switch(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"; 145 | } 146 | return "UNKNOWN_LIBSWD_OPERATION"; 147 | } 148 | 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. 156 | */ 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; 160 | int addr=0; 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; 166 | 167 | strcat(string, apndp?"AccessPort ":"DebugPort "); 168 | strcat(string, rnw?"Read ":"Write "); 169 | strcat(string, "Addr="); sprintf(tmp, "0x%02X", addr); strcat(string, tmp); 170 | 171 | if (apndp){ 172 | // APnDP=1 so we print out the AHB-AP registers 173 | addr|=libswdctx->log.dp.select&LIBSWD_DP_SELECT_APBANKSEL; 174 | switch (addr){ 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) "); 186 | } 187 | } else { 188 | // APnDP=0 so we print out the SW-DP registers 189 | if (rnw) { 190 | switch (addr){ 191 | case LIBSWD_DP_IDCODE_ADDR: strcat(string, "(IDCODE)"); break; 192 | case LIBSWD_DP_CTRLSTAT_ADDR: strcat(string, (libswdctx->log.dp.select&1<log.dp.select&1<