├── .coveragerc ├── .github └── workflows │ ├── publish.yml │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── LICENSE.md ├── MANIFEST.in ├── README.md ├── TROUBLESHOOTING.md ├── docs ├── Makefile ├── about.rst ├── assets │ ├── square.ico │ └── square.png ├── cli.rst ├── conf.py ├── index.rst ├── installation.rst ├── make.bat ├── pylink.bindings.rst ├── pylink.extras.rst ├── pylink.protocols.rst ├── pylink.rst ├── pylink.unlockers.rst ├── swd.rst ├── troubleshooting.rst └── tutorial.rst ├── examples ├── README.md ├── __init__.py ├── core.py ├── endian.py ├── pylink-rtt ├── pylink-swv ├── strace.py ├── swd.py └── windows_update.py ├── pylink ├── __init__.py ├── __main__.py ├── binpacker.py ├── decorators.py ├── enums.py ├── errors.py ├── jlink.py ├── jlock.py ├── library.py ├── protocols │ ├── __init__.py │ └── swd.py ├── registers.py ├── structs.py ├── threads.py ├── unlockers │ ├── __init__.py │ └── unlock_kinetis.py └── util.py ├── setup.cfg ├── setup.py └── tests ├── README.md ├── __init__.py ├── functional ├── __init__.py ├── features │ ├── environment.py │ ├── jlink │ │ ├── canary.feature │ │ ├── debugger.feature │ │ ├── emulator.feature │ │ ├── flash.feature │ │ ├── license.feature │ │ ├── memory.feature │ │ ├── register.feature │ │ ├── rtt.feature │ │ ├── swd.feature │ │ ├── swo.feature │ │ ├── unlock.feature │ │ └── update.feature │ ├── steps │ │ ├── __init__.py │ │ ├── common.py │ │ ├── debug.py │ │ ├── licenses.py │ │ ├── memory.py │ │ ├── registers.py │ │ ├── rtt.py │ │ ├── swd.py │ │ ├── swo.py │ │ ├── unlock.py │ │ └── update.py │ └── utility.py └── firmware │ ├── k21-canary │ ├── .gdbinit │ ├── Makefile │ ├── README.md │ ├── asm │ │ ├── bootloader.s │ │ └── gcc.ld │ └── src │ │ └── main.c │ ├── k21-etm │ ├── .gdbinit │ ├── Makefile │ ├── README.md │ ├── asm │ │ ├── bootloader.s │ │ └── gcc.ld │ └── src │ │ ├── etm.c │ │ ├── etm.h │ │ ├── main.c │ │ ├── swo.c │ │ └── swo.h │ ├── k21-loop │ ├── .gdbinit │ ├── Makefile │ ├── README.md │ ├── asm │ │ ├── bootloader.s │ │ └── gcc.ld │ └── src │ │ └── main.c │ ├── k21-rtt │ ├── Makefile │ ├── README.md │ ├── asm │ │ ├── bootloader.s │ │ └── gcc.ld │ ├── src │ │ └── main.c │ └── vendor │ │ ├── SEGGER_RTT.c │ │ ├── SEGGER_RTT.h │ │ ├── SEGGER_RTT_Conf.h │ │ └── SEGGER_RTT_printf.c │ ├── k21-swd │ ├── .gdbinit │ ├── Makefile │ ├── README.md │ └── asm │ │ ├── bootloader.s │ │ ├── gcc.ld │ │ └── main.s │ └── k21-swo │ ├── .gdbinit │ ├── Makefile │ ├── README.md │ ├── asm │ ├── bootloader.s │ └── gcc.ld │ └── src │ ├── main.c │ ├── swo.c │ └── swo.h └── unit ├── __init__.py ├── protocols ├── __init__.py └── test_swd.py ├── test_binpacker.py ├── test_decorators.py ├── test_enums.py ├── test_errors.py ├── test_jlink.py ├── test_jlock.py ├── test_library.py ├── test_main.py ├── test_structs.py ├── test_threads.py ├── test_util.py └── unlockers ├── __init__.py ├── test_unlock.py └── test_unlock_kinetis.py /.coveragerc: -------------------------------------------------------------------------------- 1 | # .coveragerc to control coverage.py 2 | 3 | [report] 4 | exclude_lines = 5 | if __name__ == '__main__': 6 | exit(main()) 7 | 8 | [run] 9 | parallel = False 10 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Python distributions to TestPyPi and PyPi 2 | 3 | on: 4 | release: 5 | types: [ published ] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Set up Python 13 | uses: actions/setup-python@v5 14 | with: 15 | python-version: '3.9' 16 | - name: Install Dependencies 17 | run: | 18 | sudo apt-get install pandoc 19 | python -m pip install --upgrade pip 20 | pip install pypandoc 21 | pip install -e ".[dev,test]" 22 | - name: Test Package 23 | run: | 24 | python -m unittest 25 | - name: Build Package 26 | run: | 27 | python setup.py bdist_wheel sdist 28 | - name: Publish Package 29 | uses: pypa/gh-action-pypi-publish@v1.4.2 30 | with: 31 | user: __token__ 32 | password: ${{ secrets.PYPI_API_TOKEN }} 33 | packages_dir: ./dist/ 34 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test Builds 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | os: [ ubuntu-latest, macos-latest ] 15 | python-version: [ 3.8, 3.9 ] 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Set up Python ${{ matrix.python-version }} 19 | uses: actions/setup-python@v5 20 | with: 21 | python-version: ${{ matrix.python-version}} 22 | - name: Install Dependencies 23 | run: | 24 | python -m pip install --upgrade pip 25 | pip install -e ".[dev,test]" 26 | - name: Lint with PyCodeStyle 27 | run: | 28 | pycodestyle . 29 | - name: Run Unit Tests 30 | run: | 31 | python -m unittest 32 | - name: Build a Wheel 33 | run: | 34 | python setup.py bdist_wheel 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | html_cov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *,cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/**/** 66 | !docs/* 67 | !docs/assets/** 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # IPython Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # dotenv 82 | .env 83 | 84 | # virtualenv 85 | .venv/ 86 | venv/ 87 | ENV/ 88 | 89 | # Spyder project settings 90 | .spyderproject 91 | 92 | # Rope project settings 93 | .ropeproject 94 | 95 | # DLLs 96 | *.dll 97 | *.so 98 | *.dylib 99 | 100 | # C Build Artifacts 101 | *.o 102 | 103 | # Mac Artifacts 104 | **.DS_Store 105 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Bug Reports 4 | A good bug report involves a *demonstrable* problem in the existing code with 5 | steps to reproduce it. In general, include the following: 6 | 7 | - What was your environment? 8 | - ex. operating system, J-Link model, weather. 9 | - What was the expected behaviour vs. what was the actual behaviour? 10 | - Steps to reproduce. 11 | - Any other information you feel is relevant. 12 | - ex. where you think the bug might be. 13 | 14 | 15 | ## Feature Requests 16 | Feature requests are always welcome, but please detail your feature request in 17 | full, and explain how it would fit into the current project. 18 | 19 | 20 | ## Pull Requests 21 | Pull requests are always welcome, but please ask first before embarking on any 22 | significant pull request (e.g. implementing a new feature, refactoring existing 23 | code, porting to a different language), otherwise you risk spending a lot of 24 | time working on something that the project's developers might not want to merge 25 | into the project. 26 | 27 | Please adhere to the coding conventions used through the project (indentation, 28 | comments, etc.), and any other requirements (such as test coverage). 29 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | # Contributors 2 | 3 | In the order of appearance in the commit history: 4 | 5 | | First Name & Last Name | GitHub username | 6 | |---------------------------|--------------------| 7 | | Ford Peprah | @hkpeprah | 8 | | Steven Stallion | @sstallion | 9 | | Charles Nicholson | @charlesnicholson | 10 | | Marek Novak | @MarekNovakNXP | 11 | | Michał Fita | @michalfita | 12 | | Bojan Potočnik | @bojanpotocnik | 13 | | Sottas Guillaume | @sauci | 14 | | Volker Kettenbach | @kettenbach-it | 15 | | Jacob Siverskog | @jsiverskog | 16 | | Johannes Neyer | @johannesneyer | 17 | | Chris Duf | @dottspina | 18 | | Bora Özgen | @boraozgen | 19 | | Marco Nilsson | @denravonska | 20 | | Curtis | @CurtisHx | 21 | | Avinash Jois | @avi-jois | 22 | | Olivier Chanquelin | @chanqueo | 23 | | Christopher Pattenden | @cpattenden-sq | 24 | | Dominic Shelton | @frogamic | 25 | | Fletcher D | @FletcherD | 26 | | G Towers | @gtowers-dukosi | 27 | | Ben Brown | @bbrown1867 | 28 | | Karl Sigurdsson | @karl-rainlabs | 29 | | - | @tianxiaoMCU | 30 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include CHANGELOG.md 2 | include LICENSE.md 3 | include README.md 4 | recursive-include tests *.py *.feature Makefile .gdbinit *.md *.s *.ld *.c *.h 5 | global-exclude *.pyc *.o *.bin *.elf 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pylink 2 | 3 | [![Build Status](https://travis-ci.org/square/pylink.svg?branch=master)](https://travis-ci.org/square/pylink) 4 | 5 | Python interface for the SEGGER J-Link. 6 | 7 | 8 | ## Requirements 9 | 10 | - [Python >= 2.7](https://www.python.org/downloads/) 11 | - [GNU ARM Embedded Toolchain](https://launchpad.net/gcc-arm-embedded) (for functional tests) 12 | - [SEGGER J-Link Tools >= 6.0b](https://www.segger.com/downloads/jlink) 13 | 14 | 15 | ## Installation 16 | 17 | Clone the project into a local repository, then navigate to the directory and 18 | run: 19 | 20 | ``` 21 | $ python setup.py install 22 | ``` 23 | 24 | 25 | ### External Dependencies 26 | 27 | In order to use this library, you will need to have installed the SEGGER tools. 28 | The tools can be installed from the SEGGER website 29 | [here](https://www.segger.com/downloads/jlink). This package is compatible 30 | with versions of the SEGGER tool `>= 6.0b`. Download the software under 31 | `J-Link Software and Documentation Pack` for your specific hardware. `PyLink` 32 | will automatically find the library if you have installed it this way, but for 33 | best results, you should use one of the two methods listed below depending on 34 | your operating system: 35 | 36 | #### On Mac 37 | 38 | ``` 39 | # Option A: Copy the library to your libraries directory. 40 | $ cp libjlinkarm.dylib /usr/local/lib/ 41 | 42 | # Option B: Add SEGGER's J-Link directory to your dynamic libraries path. 43 | $ export DYLD_LIBRARY_PATH=/Applications/SEGGER/JLink:$DYLD_LIBRARY_PATH 44 | ``` 45 | 46 | 47 | #### On Windows 48 | 49 | Windows searches for DLLs in the following order: 50 | 51 | 1. The current directory of execution. 52 | 2. The Windows system directory. 53 | 3. The Windows directory. 54 | 55 | You can copy the `JLinkARM.dll` to any of the directories listed above. 56 | Alternatively, add the SEGGER J-Link directory to your `%PATH%`. 57 | 58 | 59 | #### On Linux 60 | 61 | ``` 62 | # Option A: Copy the library to your libraries directory. 63 | $ cp libjlinkarm.so /usr/local/lib/ 64 | 65 | # Option B: Add SEGGER's J-Link library path to your libraries path. 66 | $ export LD_LIBRARY_PATH=/path/to/SEGGER/JLink:$LD_LIBRARY_PATH 67 | ``` 68 | 69 | 70 | ## Usage 71 | 72 | ``` 73 | import pylink 74 | 75 | if __name__ == '__main__': 76 | serial_no = '123456789' 77 | jlink = pylink.JLink() 78 | 79 | # Open a connection to your J-Link. 80 | jlink.open(serial_no) 81 | 82 | # Connect to the target device. 83 | jlink.connect('device', verbose=True) 84 | 85 | # Do whatever you want from here on in. 86 | jlink.flash(firmware, 0x0) 87 | jlink.reset() 88 | ``` 89 | 90 | 91 | ## Troubleshooting 92 | 93 | Should you run into any issues, refer to the documentation, as well as check 94 | out our [troubleshooting](./TROUBLESHOOTING.md) document. 95 | 96 | 97 | ## Documentation 98 | 99 | Documentation follows the 100 | [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html), 101 | and uses [Sphinx](http://www.sphinx-doc.org/en/stable/) documentation 102 | generator with the 103 | [Napoleon](http://www.sphinx-doc.org/en/stable/ext/napoleon.html) extension 104 | to provide Google style Python support. To generate the documentation, these 105 | packages will need to be installed (they are included in the provided 106 | `requirements.txt` file). With these packages installed, you can generate the 107 | documentation as follows: 108 | 109 | ``` 110 | $ cd docs 111 | $ make html 112 | ``` 113 | 114 | 115 | ## Developing for PyLink 116 | 117 | First install the development requirements by running: 118 | 119 | ``` 120 | pip install -e ".[dev,test]" 121 | ``` 122 | 123 | After you've installed the requirements, decide on the development work you 124 | want to do. See the documentation about [contributing](./CONTRIBUTING.md) 125 | before you begin your development work. 126 | 127 | 128 | ## Testing 129 | 130 | To run tests, execute the following: 131 | 132 | ``` 133 | # Unit tests 134 | $ python setup.py test 135 | 136 | # Functional tests 137 | $ python setup.py bddtest 138 | ``` 139 | 140 | There are two types of tests: `functional` and `unit`. Information about both 141 | can be found under [tests/README.md](tests/README.md). 142 | 143 | 144 | ### Coverage 145 | 146 | Code coverage can be generated as follows: 147 | 148 | ``` 149 | $ python setup.py coverage 150 | $ open htmlcov/index.html 151 | ``` 152 | 153 | 154 | ## Contributing 155 | 156 | Please see the documentation on [contributing](./CONTRIBUTING.md). 157 | 158 | ## License 159 | 160 | ``` 161 | Copyright 2017 Square, Inc. 162 | 163 | Licensed under the Apache License, Version 2.0 (the "License"); 164 | you may not use this file except in compliance with the License. 165 | You may obtain a copy of the License at 166 | 167 | http://www.apache.org/licenses/LICENSE-2.0 168 | 169 | Unless required by applicable law or agreed to in writing, software 170 | distributed under the License is distributed on an "AS IS" BASIS, 171 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 172 | See the License for the specific language governing permissions and 173 | limitations under the License. 174 | ``` 175 | 176 | See terms and conditions [here](./LICENSE.md). 177 | -------------------------------------------------------------------------------- /TROUBLESHOOTING.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | This document describes troubleshooting for common exceptions and issues that 4 | you may run into using the library. 5 | 6 | 7 | ## Unspecified Error during Open 8 | 9 | If you see the unspecified error during `open()`, it means that one of the 10 | following is true: 11 | 12 | - Your J-Link is not connected to your computer. 13 | - Your J-Link is connected to your computer, but is currently held open by 14 | another application. 15 | 16 | 17 | ## Unspecified Error during Connect 18 | 19 | If you see the unspecified error during `connect()`, it means that any of the 20 | following is not true: 21 | 22 | - The target device's chip name you passed to `connect()` is not the chip 23 | name of the actual target. 24 | - You're trying to connect to the target over `JTAG` when it only supports 25 | `SWD`. 26 | - You're trying to connect to the target, but the target is not plugged in. 27 | - You're trying to connect to the target using a J-Link that does not have 28 | the target plugged in under its "Target" port. 29 | - The connection speed is bad (try `'auto'` instead). 30 | 31 | 32 | ## Unspecified Error during Erase 33 | 34 | If you see the unspecified error during `erase()`, it means that your device is 35 | not properly halted. IF you're using a Cortex-M device, try setting the reset 36 | strategy to `JLinkResetStrategyCortexM3.RESETPIN` to avoid your device's 37 | application running when the system is booted; this is particularly useful if 38 | your application launches the watchdog or another service which would interpret 39 | the J-Link when erasing. 40 | 41 | 42 | ## Unspecified Error during Flash 43 | 44 | If you see the unspecified error during `flash()`, it means that either: 45 | 46 | - Your device is not properly halt. While `flash()` attempts to halt the 47 | CPU, it cannot if the device is breakpointed or similar. 48 | - The device is locked, in which case you have to unlock the device first by 49 | calling `unlock()`. 50 | 51 | 52 | ## Unspecified Error in Coresight 53 | 54 | If you see an unspecified error while using a Coresight method, it means that 55 | you are trying to read from / write to an invalid register. 56 | -------------------------------------------------------------------------------- /docs/about.rst: -------------------------------------------------------------------------------- 1 | About 2 | ===== 3 | 4 | PyLink is a Python library for interfacing with a J-Link. It leverages the 5 | J-Link C SDK. PyLink is in no way endorsed by or developed by SEGGER. 6 | 7 | Goals 8 | ----- 9 | 10 | - Provide a Python interface for the J-Link C SDK. 11 | - Provide a high-level API for flashing/running firmware via Python. 12 | - Provide a high-level API for debugging devices. 13 | - Provide a high-level API for unlocking locked devices. 14 | 15 | License 16 | ------- 17 | 18 | PyLink is licensed under the 19 | `Apache 2.0 Open-Source License `_. 20 | 21 | Copyright 22 | --------- 23 | 24 | Copyright 2017 Square, Inc. 25 | 26 | Sponsorship 27 | ----------- 28 | 29 | This library was made possible by `Square `_. 30 | -------------------------------------------------------------------------------- /docs/assets/square.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/pylink/9a06468a50fa9d91361e1795debbe2d91d2ff3fa/docs/assets/square.ico -------------------------------------------------------------------------------- /docs/assets/square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/pylink/9a06468a50fa9d91361e1795debbe2d91d2ff3fa/docs/assets/square.png -------------------------------------------------------------------------------- /docs/cli.rst: -------------------------------------------------------------------------------- 1 | Command-Line Tool 2 | ================= 3 | 4 | PyLink ships with a command-line interface that provides common functionality. 5 | After you've installed the package, the command should be readily available for 6 | use. 7 | 8 | .. argparse:: 9 | :ref: pylink.__main__.create_parser 10 | :prog: pylink 11 | :nodefault: 12 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | PyLink: Control your J-Link with Python 2 | ======================================= 3 | 4 | PyLink is a Python package that enables you to control your J-Link from Python. 5 | This library was developed at `Square `_ to enable us to 6 | leverage our J-Link as a part of our test infrastructure, which was written in 7 | Python. 8 | 9 | Getting started is as simple as: 10 | 11 | .. code:: python 12 | 13 | >>> import pylink 14 | >>> jlink = pylink.JLink() 15 | >>> jlink.open(serial_no=123456789) 16 | >>> jlink.product_name 17 | J-Trace Cortex-M 18 | 19 | .. toctree:: 20 | :maxdepth: 1 21 | :caption: Getting Started 22 | 23 | Installation 24 | Tutorial 25 | Command-Line 26 | 27 | .. toctree:: 28 | :maxdepth: 1 29 | :caption: Documentation 30 | 31 | PyLink 32 | Protocols 33 | Unlockers 34 | Bindings 35 | Extras 36 | Troubleshooting 37 | 38 | .. toctree:: 39 | :maxdepth: 1 40 | :caption: Debugging 41 | 42 | Serial Wire Debug 43 | 44 | .. toctree:: 45 | :caption: About PyLink 46 | :hidden: 47 | 48 | About 49 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | .. warning:: 5 | 6 | This package requires the 7 | `J-Link Software and Development Pack `__ 8 | provided by SEGGER. If you do not currently have the development pack 9 | installed, you must install it first before using this Python package. 10 | 11 | .. note:: 12 | 13 | This library is known to support Python versions 2.4 - 2.7. Support for 14 | versions higher than 2.7 is not guaranteed. 15 | 16 | Basic Installation 17 | ------------------ 18 | 19 | Installing PyLink with **pip**: 20 | 21 | .. code:: bash 22 | 23 | $ pip install pylink-square 24 | 25 | Or use **easy_install**: 26 | 27 | .. code:: bash 28 | 29 | $ easy_install pylink-square 30 | 31 | Building From Source 32 | -------------------- 33 | 34 | Clone the project into a local repository, then navigate to that directory and 35 | run: 36 | 37 | .. code:: bash 38 | 39 | $ python setup.py install 40 | 41 | This will give you the tip of **master** (the development branch). While we 42 | strive for this to be stable at all times, some bugs may be introduced, so it is 43 | best to check out a release branch first before installing. 44 | 45 | .. code:: bash 46 | 47 | $ git checkout release-major.minor 48 | $ python setup.py install 49 | 50 | External Dependencies 51 | --------------------- 52 | 53 | In order to use this library, the 54 | `J-Link Software and Development Pack `__ 55 | provided by SEGGER is required. Once you have a copy of the development pack, 56 | you can start using PyLink. PyLink will automatically find the library if you 57 | installed it using one of the installers available from SEGGER's site, but for 58 | best results, you should also do one of the following depending on your 59 | operating system: 60 | 61 | On Mac 62 | ~~~~~~ 63 | 64 | .. code:: bash 65 | 66 | # Option A: Copy the library file to your libraries directory. 67 | cp libjlinkarm.dylib /usr/local/lib/ 68 | 69 | # Option B: Add SEGGER's J-Link directory to your dynamic libraries path. 70 | $ export DYLD_LIBRARY_PATH=/Applications/SEGGER/JLink:$DYLD_LIBRARY_PATH 71 | 72 | On Windows 73 | ~~~~~~~~~~ 74 | 75 | Windows searches for DLLs in the following order: 76 | 77 | 1. The current directory of execution. 78 | 2. The Windows system directory. 79 | 3. The Windows directory. 80 | 81 | You can copy the ``JLinkARM.dll`` to any of the directories listed above. 82 | Alternatively, add the SEGGER J-Link directory to your ``%PATH%``. 83 | 84 | On Linux 85 | ~~~~~~~~ 86 | 87 | .. code:: bash 88 | 89 | # Option A: Copy the library to your libraries directory. 90 | $ cp libjlinkarm.so /usr/local/lib/ 91 | 92 | # Option B: Add SEGGER's J-Link library path to your libraries path. 93 | $ export LD_LIBRARY_PATH=/path/to/SEGGER/JLink:$LD_LIBRARY_PATH 94 | -------------------------------------------------------------------------------- /docs/pylink.bindings.rst: -------------------------------------------------------------------------------- 1 | Bindings 2 | ======== 3 | 4 | The native J-Link SDK is a C library. PyLink makes use of ``ctypes`` to 5 | interface with the library, and as such implements native Python structure 6 | bindings, and constants for values returned by the C SDK. 7 | 8 | Structures 9 | ---------- 10 | 11 | .. automodule:: pylink.structs 12 | :members: 13 | :undoc-members: 14 | :show-inheritance: 15 | 16 | Enumerations 17 | ------------ 18 | 19 | .. automodule:: pylink.enums 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/pylink.extras.rst: -------------------------------------------------------------------------------- 1 | Extras 2 | ====== 3 | 4 | PyLink makes use of a number of different submodules as a part of its 5 | implementation. These submdules are *extras*, and the user should not need to 6 | use them explicitly. 7 | 8 | Binpacker 9 | --------- 10 | 11 | This submodule provides functions for creating arrays of bytes from an integer. 12 | 13 | .. automodule:: pylink.binpacker 14 | :members: 15 | :undoc-members: 16 | :show-inheritance: 17 | 18 | Decorators 19 | ---------- 20 | 21 | This submodule provides different decorator functions. 22 | 23 | .. automodule:: pylink.decorators 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | 28 | Registers 29 | --------- 30 | 31 | This submodule provides `ctypes` bindings for different registers. 32 | 33 | .. automodule:: pylink.registers 34 | :members: 35 | :undoc-members: 36 | :show-inheritance: 37 | 38 | Threads 39 | ------- 40 | 41 | This submodule provides custom `threading.Thread` types. 42 | 43 | .. automodule:: pylink.threads 44 | :members: 45 | :undoc-members: 46 | :show-inheritance: 47 | 48 | Util 49 | ---- 50 | 51 | This submodule provides different utility functions. 52 | 53 | .. automodule:: pylink.util 54 | :members: 55 | :undoc-members: 56 | :show-inheritance: 57 | -------------------------------------------------------------------------------- /docs/pylink.protocols.rst: -------------------------------------------------------------------------------- 1 | Protocols 2 | ========= 3 | 4 | The J-Link has multiple ways of communicating with a target: Serial Wire 5 | Debug (SWD), Serial Wire Output (SWO), Memory, Coresight, Registers, etc. For 6 | some of these communication methods, there is a specific protocol that defines 7 | how the communication takes place. 8 | 9 | This module provides definitions to facilate communicating over the different 10 | protocols. All the methods use a ``JLink`` instance, but take care of the 11 | housekeeping work involved with each protocol. 12 | 13 | Serial Wire Debug (SWD) 14 | ----------------------- 15 | 16 | This subsection defines the classes and methods needed to use the SWD protocol. 17 | 18 | .. automodule:: pylink.protocols.swd 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/pylink.rst: -------------------------------------------------------------------------------- 1 | PyLink 2 | ====== 3 | 4 | The PyLink package provides a Pythonic interface for interacting with the 5 | J-Link C SDK. This interface is provided through the ``JLink`` class, which 6 | provides several of the functions provided by the native SDK. Some methods 7 | require a specific interface, a target being connected, or an emulator being 8 | connected, and will raise errors as appropriate if these conditions are not 9 | met. 10 | 11 | In lieu of return codes, this library uses the object-oriented paradigm of 12 | raising an exception. All exceptions are inherited from the ``JLinkException`` 13 | base class. 14 | 15 | Exceptions 16 | ---------- 17 | 18 | This submodule defines the different exceptions that can be generated by the 19 | ``JLink`` methods. 20 | 21 | .. automodule:: pylink.errors 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | 26 | 27 | Library 28 | ------- 29 | 30 | This submodule defines a ``Library``. This is not needed unless explicitly 31 | specifying a different version of the J-Link dynamic library. 32 | 33 | .. automodule:: pylink.library 34 | :members: 35 | :undoc-members: 36 | :show-inheritance: 37 | 38 | JLock 39 | ----- 40 | 41 | This submodule defines a ``JLock``. This acts as a lockfile-like interface for 42 | interacting with a particular emulator in order to prevent multiple threads or 43 | processes from creating instances of ``JLink`` to interact with the same 44 | emulator. 45 | 46 | .. automodule:: pylink.jlock 47 | :members: 48 | :undoc-members: 49 | :show-inheritance: 50 | 51 | JLink 52 | ----- 53 | 54 | This submodule provides the definition for the ``JLink`` class, which is the 55 | interface to the J-Link. 56 | 57 | .. automodule:: pylink.jlink 58 | :members: 59 | :undoc-members: 60 | :show-inheritance: 61 | -------------------------------------------------------------------------------- /docs/pylink.unlockers.rst: -------------------------------------------------------------------------------- 1 | Unlocking 2 | ========= 3 | 4 | Sometimes a user error may result in a device becoming **locked**. When a 5 | device is locked, it's memory cannot be written to, nor can it's memory be 6 | read from. This is a security feature in many MCUs. 7 | 8 | This module provides functions for unlocking a locked device. 9 | 10 | .. note:: 11 | 12 | Unlocking a device results in a mass-erase. Do not unlock a device if you 13 | do not want it be erased. 14 | 15 | .. automodule:: pylink.unlockers 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | 20 | .. automodule:: pylink.unlockers.unlock_kinetis 21 | :members: 22 | :undoc-members: 23 | :show-inheritance: 24 | -------------------------------------------------------------------------------- /docs/swd.rst: -------------------------------------------------------------------------------- 1 | Serial Wire Debug 2 | ================= 3 | 4 | Serial Wire Output (SWO) alongside Serial Wire Debug (SWD) allows for the CPU 5 | to emit real-time trace data. In particular, when used with an Instrumentation 6 | Trace Macrocell (ITM), it can be used to form a Serial Wire Viewer (SWV). The 7 | ITM ports are provided by the ARM controller. The SWV typically implements a 8 | form of ``printf`` style debugging for embedded systems. 9 | 10 | Getting Started 11 | --------------- 12 | 13 | First, get your J-Link set up by instantiating an instance of a ``JLink`` and 14 | connecting to your target device. Once that is established, you want to call 15 | either ``swo_start()``: 16 | 17 | .. code:: python 18 | 19 | speed = 9600 20 | jlink.swo_start(swo_speed=speed) 21 | 22 | or call ``swo_enable()``: 23 | 24 | .. code:: python 25 | 26 | swo_speed = 9600 27 | cpu_speed = 72000000 # 72 MHz 28 | port_mask = 0x01 29 | jlink.swo_enable(cpu_speed, swo_speed, port_mask) 30 | 31 | Once enabled, you can begin reading data from the target. 32 | 33 | Serial Wire Methods 34 | ------------------- 35 | 36 | .. automodule:: pylink.jlink 37 | :noindex: 38 | 39 | .. autoclass:: pylink.jlink.JLink 40 | :noindex: 41 | :members: swd_read8, swd_read16, swd_read32, swd_write, swd_write8, 42 | swd_write16, swd_write32, swd_sync, swo_start, swo_enable, 43 | swo_stop, swo_flush, swo_speed_info, swo_num_bytes, 44 | swo_set_host_buffer_size, swo_set_emu_buffer_size, 45 | swo_supported_speeds, swo_read, swo_read_stimulus 46 | 47 | Examples 48 | -------- 49 | 50 | Serial Wire Viewer 51 | ~~~~~~~~~~~~~~~~~~ 52 | 53 | .. literalinclude:: ../examples/swv.py 54 | :name: swv-py 55 | :language: python 56 | :linenos: 57 | -------------------------------------------------------------------------------- /docs/troubleshooting.rst: -------------------------------------------------------------------------------- 1 | Troubleshooting 2 | =============== 3 | 4 | This page details common errors people run into while using PyLink. These 5 | errors do not mean the library is not working as intended, but rather a fault 6 | on the user end. If you cannot solve your issue by following any of the steps 7 | below, feel free to reach out. 8 | 9 | Unspecified Error 10 | ----------------- 11 | 12 | If you ever see something similar to the following: 13 | 14 | .. code:: python 15 | 16 | Traceback (most recent call last): 17 | File "pylink/decorators.py", line 38, in async_wrapper 18 | return func(*args, **kwargs) 19 | File "pylink/jlink.py", line 256, in open 20 | raise JLinkException(result) 21 | __main__.JLinkException: Unspecified error. 22 | 23 | Then congratulations, you've run into a catch-all error. This is a limitation 24 | imposed by native C SDK in which there is a catch-all error case. There are a 25 | couple possible solutions to this, and they are detailed below. 26 | 27 | Unspecified Error during ``open()`` 28 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 29 | 30 | If you see the unspecified error during ``open()``, it means that one of the 31 | following is true: 32 | 33 | - Your J-Link is not connected to your computer. 34 | - Your J-Link is connected to your computer, but is currently held open by 35 | another application. 36 | 37 | Unspecified Error during ``connect()`` 38 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 39 | 40 | If you see the unspecified error during ``connect()``, it means that any of the 41 | following is not true: 42 | 43 | - The target device's chip name you passed to ``connect()`` is not the chip 44 | name of the actual target. 45 | - You're trying to connect to the target over JTAG when it only supports 46 | SWD. 47 | - You're trying to connect to the target, but the target is not plugged in. 48 | - You're trying to connect to the target using a J-Link that does not have 49 | the target plugged in under its "Target" port. 50 | - The connection speed is bad (try ``'auto'`` instead). 51 | 52 | Unspecified Error during ``erase()`` 53 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 54 | 55 | If you see the unspecified error during ``erase()``, it means that your device is 56 | not properly halted. IF you're using a Cortex-M device, try setting the reset 57 | strategy to ``JLinkResetStrategyCortexM3.RESETPIN`` to avoid your device's 58 | application running when the system is booted; this is particularly useful if 59 | your application launches the watchdog or another service which would interpret 60 | the J-Link when erasing. 61 | 62 | Unspecified Error during ``flash()`` 63 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 64 | 65 | If you see the unspecified error during ``flash()``, it means that either: 66 | 67 | - Your device is not properly halt. While ``flash()`` attempts to halt the 68 | CPU, it cannot if the device is breakpointed or similar. 69 | - The device is locked, in which case you have to unlock the device first. 70 | 71 | Unspecified Error in Coresight 72 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 73 | 74 | If you see an unspecified error while using a Coresight method, it means that 75 | you are trying to read from / write to an invalid register. 76 | -------------------------------------------------------------------------------- /docs/tutorial.rst: -------------------------------------------------------------------------------- 1 | Tutorial 2 | ======== 3 | 4 | In this tutorial, assume that the serial number of the J-Link emulator being 5 | connected to is ``123456789``, and that the target device is an 6 | ``Mkxxxxxxxxxx7``. 7 | 8 | Connecting to an Emulator 9 | ------------------------- 10 | 11 | .. code:: python 12 | 13 | >>> import pylink 14 | >>> jlink = pylink.JLink() 15 | >>> jlink.open(123456789) 16 | >>> jlink.product_name 17 | J-Trace Cortex-M 18 | >>> jlink.oem 19 | >>> jlink.opened() 20 | True 21 | >>> jlink.connected() 22 | True 23 | >>> jlink.target_connected() 24 | False 25 | 26 | Updating the Emulator 27 | --------------------- 28 | 29 | .. code:: python 30 | 31 | >>> jlink.update_firmware() 32 | 1 33 | 34 | Connecting to a Target CPU 35 | -------------------------- 36 | 37 | .. code:: python 38 | 39 | >>> jlink.connect('MKxxxxxxxxxx7') 40 | >>> jlink.core_id() 41 | 50331903 42 | >>> jlink.device_family() 43 | 3 44 | >>> jlink.target_connected() 45 | True 46 | 47 | Flashing from a File 48 | -------------------- 49 | 50 | .. code:: python 51 | 52 | >>> jlink.flash_file('/path/to/file', address) 53 | 1337 54 | >>> jlink.memory_read8(0, 1337) 55 | [ 0, 0, .... ] 56 | 57 | Flashing from a List of Bytes 58 | ----------------------------- 59 | 60 | .. code:: python 61 | 62 | >>> data = [1, 2, 3, 4] 63 | >>> jlink.flash(data, 0) 64 | 4 65 | >>> jlink.memory_read8(0, 4) 66 | [1, 2, 3, 4] 67 | 68 | Unlocking a Device 69 | ------------------ 70 | 71 | .. note:: 72 | 73 | Currently unlock is only supported for Kinetis on SWD. 74 | 75 | .. code:: python 76 | 77 | >>> pylink.unlock(jlink, 'Kinetis') 78 | True 79 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | This directory contains examples for different scripts and applications that 4 | can be developed using `pylink`. 5 | 6 | ## Current Examples 7 | 8 | ### Core Information Printer 9 | 10 | #### Source 11 | [Core Information Printer](./core.py) 12 | 13 | #### Description 14 | The core information printer prints information about the target core. 15 | 16 | 17 | ### Serial Wire Viewer 18 | 19 | #### Source 20 | [Serial Wire Viewer](./swv.py) 21 | 22 | #### Description 23 | The serial wire viewer is a tool that uses the Instruction Trace Macrocell 24 | (ITM) and Serial Wire Output (SWO) to provide an asynchronous method of 25 | obtaining information from outside the MCU. This can be used for tracing, 26 | `printf` style debugging, watchpoints, and timestamping. 27 | 28 | 29 | ### Simple Trace 30 | 31 | #### Source 32 | [Simple Trace](./strace.py) 33 | 34 | #### Description 35 | Tool demonstrating the use of simple trace. 36 | 37 | 38 | ### Target Endianness 39 | 40 | #### Source 41 | [Target Endianess](./endian.py) 42 | 43 | #### Description 44 | Prints the endian mode of the target hardware. 45 | 46 | 47 | ### Windows Update 48 | 49 | #### Source 50 | [Windows Update](./windows_update.py) 51 | 52 | #### Description 53 | Tool for updating J-Links on a Windows platform. 54 | 55 | 56 | ### Real Time Transfer (RTT) 57 | 58 | #### Source 59 | [RTT](./rtt.py) 60 | 61 | #### Description 62 | Tool for a simple command-line terminal that communicates over RTT. 63 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/pylink/9a06468a50fa9d91361e1795debbe2d91d2ff3fa/examples/__init__.py -------------------------------------------------------------------------------- /examples/core.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017 Square, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # 17 | # Example core information printer. 18 | # 19 | # This module prints the core's information. 20 | # 21 | # Usage: core.py jlink_serial_number device 22 | # Author: Ford Peprah 23 | # Date: October 1st, 2016 24 | # Copyright: 2016 Square, Inc. 25 | 26 | import pylink 27 | 28 | try: 29 | import StringIO 30 | except ImportError: 31 | import io as StringIO 32 | import sys 33 | 34 | 35 | def main(jlink_serial, device): 36 | """Prints the core's information. 37 | 38 | Args: 39 | jlink_serial (str): the J-Link serial number 40 | device (str): the target CPU 41 | 42 | Returns: 43 | Always returns ``0``. 44 | 45 | Raises: 46 | JLinkException: on error 47 | """ 48 | buf = StringIO.StringIO() 49 | jlink = pylink.JLink(log=buf.write, detailed_log=buf.write) 50 | jlink.open(serial_no=jlink_serial) 51 | 52 | # Use Serial Wire Debug as the target interface. 53 | jlink.set_tif(pylink.enums.JLinkInterfaces.SWD) 54 | jlink.connect(device, verbose=True) 55 | 56 | sys.stdout.write('ARM Id: %d\n' % jlink.core_id()) 57 | sys.stdout.write('CPU Id: %d\n' % jlink.core_cpu()) 58 | sys.stdout.write('Core Name: %s\n' % jlink.core_name()) 59 | sys.stdout.write('Device Family: %d\n' % jlink.device_family()) 60 | 61 | 62 | if __name__ == '__main__': 63 | exit(main(sys.argv[1], sys.argv[2])) 64 | -------------------------------------------------------------------------------- /examples/endian.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 *-* 2 | # Copyright 2017 Square, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # 17 | # Example Endianness. 18 | # 19 | # This module demonstrates getting the endianess of the target. 20 | # 21 | # Usage: endian.py jlink_serial_number device 22 | # Author: Ford Peprah 23 | # Date: October 11th, 2016 24 | # Copyright: 2016 Square, Inc. 25 | 26 | import pylink 27 | 28 | try: 29 | import StringIO 30 | except ImportError: 31 | import io as StringIO 32 | import sys 33 | 34 | 35 | def main(jlink_serial, device): 36 | """Main function. 37 | 38 | Args: 39 | jlink_serial (str): the J-Link serial number 40 | device (str): the target CPU 41 | 42 | Returns: 43 | ``None`` 44 | 45 | Raises: 46 | JLinkException: on error 47 | """ 48 | buf = StringIO.StringIO() 49 | jlink = pylink.JLink(log=buf.write, detailed_log=buf.write) 50 | jlink.open(serial_no=jlink_serial) 51 | 52 | jlink.set_tif(pylink.enums.JLinkInterfaces.SWD) 53 | jlink.connect(device, verbose=True) 54 | 55 | # Figure out our original endianess first. 56 | big_endian = jlink.set_little_endian() 57 | if big_endian: 58 | jlink.set_big_endian() 59 | 60 | print('Target Endian Mode: %s Endian' % ('Big' if big_endian else 'Little')) 61 | 62 | 63 | if __name__ == '__main__': 64 | main(sys.argv[1], sys.argv[2]) 65 | -------------------------------------------------------------------------------- /examples/pylink-swv: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2017 Square, Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | # 18 | # Example Serial Wire Viewer. 19 | # 20 | # This module demonstrates implementing a Serial Wire Viewer using the PyLink 21 | # library. 22 | # 23 | # Usage: swv.py jlink_serial_number device 24 | # Author: Ford Peprah 25 | # Date: Friday, September 23rd, 2016 26 | # Copyright: 2016 Square, Inc. 27 | 28 | import pylink 29 | 30 | try: 31 | import StringIO 32 | except ImportError: 33 | import io as StringIO 34 | import string 35 | import sys 36 | import time 37 | 38 | 39 | def serial_wire_viewer(jlink_serial, device): 40 | """Implements a Serial Wire Viewer (SWV). 41 | 42 | A Serial Wire Viewer (SWV) allows us implement real-time logging of output 43 | from a connected device over Serial Wire Output (SWO). 44 | 45 | Args: 46 | jlink_serial (str): the J-Link serial number 47 | device (str): the target CPU 48 | 49 | Returns: 50 | Always returns ``0``. 51 | 52 | Raises: 53 | JLinkException: on error 54 | """ 55 | buf = StringIO.StringIO() 56 | jlink = pylink.JLink(log=buf.write, detailed_log=buf.write) 57 | jlink.open(serial_no=jlink_serial) 58 | 59 | # Use Serial Wire Debug as the target interface. Need this in order to use 60 | # Serial Wire Output. 61 | jlink.set_tif(pylink.enums.JLinkInterfaces.SWD) 62 | jlink.connect(device, verbose=True) 63 | jlink.coresight_configure() 64 | jlink.set_reset_strategy(pylink.enums.JLinkResetStrategyCortexM3.RESETPIN) 65 | 66 | # Have to halt the CPU before getitng its speed. 67 | jlink.reset() 68 | jlink.halt() 69 | 70 | cpu_speed = jlink.cpu_speed() 71 | swo_speed = jlink.swo_supported_speeds(cpu_speed, 10)[0] 72 | 73 | # Start logging serial wire output. 74 | jlink.swo_start(swo_speed) 75 | jlink.swo_flush() 76 | 77 | # Output the information about the program. 78 | sys.stdout.write('Serial Wire Viewer\n') 79 | sys.stdout.write('Press Ctrl-C to Exit\n') 80 | sys.stdout.write('Reading data from port 0:\n\n') 81 | 82 | # Reset the core without halting so that it runs. 83 | jlink.reset(ms=10, halt=False) 84 | 85 | # Use the `try` loop to catch a keyboard interrupt in order to stop logging 86 | # serial wire output. 87 | try: 88 | while True: 89 | # Check for any bytes in the stream. 90 | num_bytes = jlink.swo_num_bytes() 91 | 92 | if num_bytes == 0: 93 | # If no bytes exist, sleep for a bit before trying again. 94 | time.sleep(1) 95 | continue 96 | 97 | data = jlink.swo_read_stimulus(0, num_bytes) 98 | sys.stdout.write(''.join(map(chr, data))) 99 | sys.stdout.flush() 100 | except KeyboardInterrupt: 101 | pass 102 | 103 | sys.stdout.write('\n') 104 | 105 | # Stop logging serial wire output. 106 | jlink.swo_stop() 107 | 108 | return 0 109 | 110 | 111 | if __name__ == '__main__': 112 | exit(serial_wire_viewer(sys.argv[1], sys.argv[2])) 113 | -------------------------------------------------------------------------------- /examples/strace.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # 16 | # Example simple trace. 17 | # 18 | # Usage: strace.py device trace_address breakpoint_address 19 | # Author: Ford Peprah 20 | # Date: March 23rd, 2017 21 | # Copyright: 2017 Square, Inc. 22 | 23 | import pylink 24 | 25 | import sys 26 | import time 27 | 28 | 29 | def strace(device, trace_address, breakpoint_address): 30 | """Implements simple trace using the STrace API. 31 | 32 | Args: 33 | device (str): the device to connect to 34 | trace_address (int): address to begin tracing from 35 | breakpoint_address (int): address to breakpoint at 36 | 37 | Returns: 38 | ``None`` 39 | """ 40 | jlink = pylink.JLink() 41 | jlink.open() 42 | 43 | # Do the initial connection sequence. 44 | jlink.power_on() 45 | jlink.set_tif(pylink.JLinkInterfaces.SWD) 46 | jlink.connect(device) 47 | jlink.reset() 48 | 49 | # Clear any breakpoints that may exist as of now. 50 | jlink.breakpoint_clear_all() 51 | 52 | # Start the simple trace. 53 | op = pylink.JLinkStraceOperation.TRACE_START 54 | jlink.strace_clear_all() 55 | jlink.strace_start() 56 | 57 | # Set the breakpoint and trace events, then restart the CPU so that it 58 | # will execute. 59 | bphandle = jlink.breakpoint_set(breakpoint_address, thumb=True) 60 | trhandle = jlink.strace_code_fetch_event(op, address=trace_address) 61 | jlink.restart() 62 | time.sleep(1) 63 | 64 | # Run until the CPU halts due to the breakpoint being hit. 65 | while True: 66 | if jlink.halted(): 67 | break 68 | 69 | # Print out all instructions that were captured by the trace. 70 | while True: 71 | instructions = jlink.strace_read(1) 72 | if len(instructions) == 0: 73 | break 74 | instruction = instructions[0] 75 | print(jlink.disassemble_instruction(instruction)) 76 | 77 | jlink.power_off() 78 | jlink.close() 79 | 80 | 81 | if __name__ == '__main__': 82 | exit(strace(sys.argv[1], int(sys.argv[2], 16), int(sys.argv[3], 16))) 83 | -------------------------------------------------------------------------------- /examples/swd.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017 Square, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # 17 | # Example Serial Wire Debug Viewer. 18 | # 19 | # This module demonstrates implementing a Serial Wire Viewer using the PyLink 20 | # library. 21 | # 22 | # Usage: swd.py jlink_serial_number device 23 | # Author: Ford Peprah 24 | # Date: Friday, September 23rd, 2016 25 | # Copyright: 2016 Square, Inc. 26 | 27 | import pylink 28 | 29 | try: 30 | import StringIO 31 | except ImportError: 32 | import io as StringIO 33 | import string 34 | import sys 35 | import time 36 | 37 | 38 | def serial_wire_viewer(jlink_serial, device): 39 | """Implements a Serial Wire Viewer (SWV). 40 | 41 | A Serial Wire Viewer (SWV) allows us implement real-time logging of output 42 | from a connected device over Serial Wire Output (SWO). 43 | 44 | Args: 45 | jlink_serial (str): the J-Link serial number 46 | device (str): the target CPU 47 | 48 | Returns: 49 | Always returns ``0``. 50 | 51 | Raises: 52 | JLinkException: on error 53 | """ 54 | buf = StringIO.StringIO() 55 | jlink = pylink.JLink(log=buf.write, detailed_log=buf.write) 56 | jlink.open(serial_no=jlink_serial) 57 | 58 | # Use Serial Wire Debug as the target interface. Need this in order to use 59 | # Serial Wire Output. 60 | jlink.set_tif(pylink.enums.JLinkInterfaces.SWD) 61 | jlink.connect(device, verbose=True) 62 | jlink.coresight_configure() 63 | jlink.set_reset_strategy(pylink.enums.JLinkResetStrategyCortexM3.RESETPIN) 64 | 65 | # Have to halt the CPU before getitng its speed. 66 | jlink.reset() 67 | jlink.halt() 68 | 69 | # Output the information about the program. 70 | sys.stdout.write('Serial Wire Viewer\n') 71 | sys.stdout.write('Press Ctrl-C to Exit\n') 72 | sys.stdout.write('Reading data from port 0:\n\n') 73 | 74 | # Reset the core without halting so that it runs. 75 | jlink.reset(ms=10, halt=False) 76 | 77 | # Use the `try` loop to catch a keyboard interrupt in order to stop logging 78 | # serial wire output. 79 | try: 80 | while True: 81 | # Check the vector catch. 82 | if jlink.register_read(0x0) != 0x05: 83 | continue 84 | 85 | offset = jlink.register_read(0x1) 86 | handle, ptr, num_bytes = jlink.memory_read32(offset, 3) 87 | read = ''.join(map(chr, jlink.memory_read8(ptr, num_bytes))) 88 | 89 | if num_bytes == 0: 90 | # If no bytes exist, sleep for a bit before trying again. 91 | time.sleep(1) 92 | continue 93 | 94 | jlink.register_write(0x0, 0) 95 | jlink.step(thumb=True) 96 | jlink.restart(2, skip_breakpoints=True) 97 | 98 | sys.stdout.write(read) 99 | sys.stdout.flush() 100 | except KeyboardInterrupt: 101 | pass 102 | 103 | sys.stdout.write('\n') 104 | 105 | return 0 106 | 107 | 108 | if __name__ == '__main__': 109 | exit(serial_wire_viewer(sys.argv[1], sys.argv[2])) 110 | -------------------------------------------------------------------------------- /examples/windows_update.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017 Square, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # 17 | # Automatic updating of J-Link software on Windows. 18 | # 19 | # This script demonstrates automatically updating the J-Link firmware to match 20 | # the firmware provided by the J-Link DLL on windows platform. This is 21 | # particularly useful for automated testing infrastructure where the desire is 22 | # to automatically role out upgrades of the J-Link software. This would be run 23 | # after the latest version of the DLL is installed. 24 | # 25 | # Usage: windows_update.py 26 | # Author: Ford Peprah 27 | # Date: December 8th, 2016 28 | # Copyright: 2016 Square, Inc. 29 | 30 | import pylink 31 | 32 | import os 33 | 34 | 35 | def main(): 36 | """Upgrades the firmware of the J-Links connected to a Windows device. 37 | 38 | Returns: 39 | None. 40 | 41 | Raises: 42 | OSError: if there are no J-Link software packages. 43 | """ 44 | windows_libraries = list(pylink.Library.find_library_windows()) 45 | latest_library = None 46 | for lib in windows_libraries: 47 | if os.path.dirname(lib).endswith('JLinkARM'): 48 | # Always use the one pointed to by the 'JLinkARM' directory. 49 | latest_library = lib 50 | break 51 | elif latest_library is None: 52 | latest_library = lib 53 | elif os.path.dirname(lib) > os.path.dirname(latest_library): 54 | latest_library = lib 55 | 56 | if latest_library is None: 57 | raise OSError('No J-Link library found.') 58 | 59 | library = pylink.Library(latest_library) 60 | jlink = pylink.JLink(lib=library) 61 | 62 | print('Found version: %s' % jlink.version) 63 | 64 | for emu in jlink.connected_emulators(): 65 | jlink.disable_dialog_boxes() 66 | jlink.open(serial_no=emu.SerialNumber) 67 | jlink.sync_firmware() 68 | print('Updated emulator with serial number %s' % emu.SerialNumber) 69 | 70 | return None 71 | 72 | 73 | if __name__ == '__main__': 74 | exit(main()) 75 | -------------------------------------------------------------------------------- /pylink/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | __version__ = '1.6.0' 16 | __title__ = 'pylink' 17 | __author__ = 'Square Embedded Software Team' 18 | __author_email__ = 'esw-team@squareup.com' 19 | __copyright__ = 'Copyright 2017 Square, Inc.' 20 | __license__ = 'Apache 2.0' 21 | __url__ = 'http://www.github.com/Square/pylink' 22 | __description__ = 'Python interface for SEGGER J-Link.' 23 | __long_description__ = '''This module provides a Python implementation of the 24 | J-Link SDK by leveraging the SDK's DLL. 25 | ''' 26 | 27 | from .enums import * 28 | from .errors import * 29 | from .jlink import * 30 | from .library import * 31 | from .structs import * 32 | from .unlockers import * 33 | -------------------------------------------------------------------------------- /pylink/binpacker.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import ctypes 16 | import math 17 | 18 | 19 | BITS_PER_BYTE = 8 20 | 21 | 22 | def pack_size(value): 23 | """Returns the number of bytes required to represent a given value. 24 | 25 | Args: 26 | value (int): the natural number whose size to get 27 | 28 | Returns: 29 | The minimal number of bytes required to represent the given integer. 30 | 31 | Raises: 32 | ValueError: if ``value < 0``. 33 | TypeError: if ``value`` is not a number. 34 | """ 35 | if value == 0: 36 | return 1 37 | elif value < 0: 38 | raise ValueError('Expected non-negative integer.') 39 | return int(math.log(value, 256)) + 1 40 | 41 | 42 | def pack(value, nbits=None): 43 | """Packs a given value into an array of 8-bit unsigned integers. 44 | 45 | If ``nbits`` is not present, calculates the minimal number of bits required 46 | to represent the given ``value``. The result is little endian. 47 | 48 | Args: 49 | value (int): the integer value to pack 50 | nbits (int): optional number of bits to use to represent the value 51 | 52 | Returns: 53 | An array of ``ctypes.c_uint8`` representing the packed ``value``. 54 | 55 | Raises: 56 | ValueError: if ``value < 0`` and ``nbits`` is ``None`` or ``nbits <= 0``. 57 | TypeError: if ``nbits`` or ``value`` are not numbers. 58 | """ 59 | if nbits is None: 60 | nbits = pack_size(value) * BITS_PER_BYTE 61 | elif nbits <= 0: 62 | raise ValueError('Given number of bits must be greater than 0.') 63 | 64 | buf_size = int(math.ceil(nbits / float(BITS_PER_BYTE))) 65 | buf = (ctypes.c_uint8 * buf_size)() 66 | 67 | for (idx, _) in enumerate(buf): 68 | buf[idx] = (value >> (idx * BITS_PER_BYTE)) & 0xFF 69 | 70 | return buf 71 | -------------------------------------------------------------------------------- /pylink/decorators.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from . import threads 16 | 17 | import functools 18 | 19 | 20 | def async_decorator(func): 21 | """Asynchronous function decorator. Interprets the function as being 22 | asynchronous, so returns a function that will handle calling the 23 | Function asynchronously. 24 | 25 | Args: 26 | func (function): function to be called asynchronously 27 | 28 | Returns: 29 | The wrapped function. 30 | 31 | Raises: 32 | AttributeError: if ``func`` is not callable 33 | """ 34 | 35 | @functools.wraps(func) 36 | def async_wrapper(*args, **kwargs): 37 | """Wraps up the call to ``func``, so that it is called from a separate 38 | thread. 39 | 40 | The callback, if given, will be called with two parameters, 41 | ``exception`` and ``result`` as ``callback(exception, result)``. If 42 | the thread ran to completion without error, ``exception`` will be 43 | ``None``, otherwise ``exception`` will be the generated exception that 44 | stopped the thread. Result is the result of the exected function. 45 | 46 | Args: 47 | callback (function): the callback to ultimately be called 48 | args: list of arguments to pass to ``func`` 49 | kwargs: key-word arguments dictionary to pass to ``func`` 50 | 51 | Returns: 52 | A thread if the call is asynchronous, otherwise the the return value 53 | of the wrapped function. 54 | 55 | Raises: 56 | TypeError: if ``callback`` is not callable or is missing 57 | """ 58 | if 'callback' not in kwargs or not kwargs['callback']: 59 | return func(*args, **kwargs) 60 | 61 | callback = kwargs.pop('callback') 62 | 63 | if not callable(callback): 64 | raise TypeError('Expected \'callback\' is not callable.') 65 | 66 | def thread_func(*args, **kwargs): 67 | """Thread function on which the given ``func`` and ``callback`` 68 | are executed. 69 | 70 | Args: 71 | args: list of arguments to pass to ``func`` 72 | kwargs: key-word arguments dictionary to pass to ``func`` 73 | 74 | Returns: 75 | Return value of the wrapped function. 76 | """ 77 | exception, res = None, None 78 | try: 79 | res = func(*args, **kwargs) 80 | except Exception as e: 81 | exception = e 82 | return callback(exception, res) 83 | 84 | thread = threads.ThreadReturn(target=thread_func, 85 | args=args, 86 | kwargs=kwargs) 87 | thread.daemon = True 88 | thread.start() 89 | return thread 90 | 91 | return async_wrapper 92 | -------------------------------------------------------------------------------- /pylink/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from . import enums 16 | from . import util 17 | 18 | 19 | class JLinkException(enums.JLinkGlobalErrors, Exception): 20 | """Generic J-Link exception.""" 21 | 22 | def __init__(self, code): 23 | """Generates an exception by coercing the given ``code`` to an error 24 | string if is a number, otherwise assumes it is the message. 25 | 26 | Args: 27 | self (JLinkException): the 'JLinkException' instance 28 | code (object): message or error code 29 | 30 | Returns: 31 | ``None`` 32 | """ 33 | message = code 34 | 35 | self.code = None 36 | 37 | if util.is_integer(code): 38 | message = self.to_string(code) 39 | self.code = code 40 | 41 | super(JLinkException, self).__init__(message) 42 | self.message = message 43 | 44 | 45 | class JLinkEraseException(enums.JLinkEraseErrors, JLinkException): 46 | """J-Link erase exception.""" 47 | pass 48 | 49 | 50 | class JLinkFlashException(enums.JLinkFlashErrors, JLinkException): 51 | """J-Link flash exception.""" 52 | pass 53 | 54 | 55 | class JLinkWriteException(enums.JLinkWriteErrors, JLinkException): 56 | """J-Link write exception.""" 57 | pass 58 | 59 | 60 | class JLinkReadException(enums.JLinkReadErrors, JLinkException): 61 | """J-Link read exception.""" 62 | pass 63 | 64 | 65 | class JLinkDataException(enums.JLinkDataErrors, JLinkException): 66 | """J-Link data event exception.""" 67 | pass 68 | 69 | 70 | class JLinkRTTException(enums.JLinkRTTErrors, JLinkException): 71 | """J-Link RTT exception.""" 72 | pass 73 | -------------------------------------------------------------------------------- /pylink/jlock.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import psutil 16 | 17 | import errno 18 | import tempfile 19 | import os 20 | 21 | 22 | class JLock(object): 23 | """Lockfile for accessing a particular J-Link. 24 | 25 | The J-Link SDK does not prevent accessing the same J-Link multiple times 26 | from the same process or multiple processes. As a result, a user can 27 | have the same J-Link being accessed by multiple processes. This class 28 | provides an interface to a lock-file like structure for the physical 29 | J-Links to ensure that any instance of a ``JLink`` with an open emulator 30 | connection will be the only one accessing that emulator. 31 | 32 | This class uses a PID-style lockfile to allow acquiring of the lockfile in 33 | the instances where the lockfile exists, but the process which created it 34 | is no longer running. 35 | 36 | To share the same emulator connection between multiple threads, processes, 37 | or functions, a single instance of a ``JLink`` should be created and passed 38 | between the threads and processes. 39 | 40 | Attributes: 41 | name: the name of the lockfile. 42 | path: full path to the lockfile. 43 | fd: file description of the lockfile. 44 | acquired: boolean indicating if the lockfile lock has been acquired. 45 | """ 46 | 47 | SERIAL_NAME_FMT = '.pylink-usb-{}.lck' 48 | IPADDR_NAME_FMT = '.pylink-ip-{}.lck' 49 | 50 | def __init__(self, serial_no): 51 | """Creates an instance of a ``JLock`` and populates the name. 52 | 53 | Note: 54 | This method may fail if there is no temporary directory in which to 55 | have the lockfile placed. 56 | 57 | Args: 58 | self (JLock): the ``JLock`` instance 59 | serial_no (int): the serial number of the J-Link 60 | 61 | Returns: 62 | ``None`` 63 | """ 64 | self.name = self.SERIAL_NAME_FMT.format(serial_no) 65 | self.acquired = False 66 | self.fd = None 67 | self.path = None 68 | self.path = os.path.join(tempfile.gettempdir(), self.name) 69 | 70 | def __del__(self): 71 | """Cleans up the lockfile instance if it was acquired. 72 | 73 | Args: 74 | self (JLock): the ``JLock`` instance 75 | 76 | Returns: 77 | ``None`` 78 | """ 79 | self.release() 80 | 81 | def acquire(self): 82 | """Attempts to acquire a lock for the J-Link lockfile. 83 | 84 | If the lockfile exists but does not correspond to an active process, 85 | the lockfile is first removed, before an attempt is made to acquire it. 86 | 87 | Args: 88 | self (Jlock): the ``JLock`` instance 89 | 90 | Returns: 91 | ``True`` if the lock was acquired, otherwise ``False``. 92 | 93 | Raises: 94 | OSError: on file errors. 95 | """ 96 | if os.path.exists(self.path): 97 | try: 98 | pid = None 99 | 100 | with open(self.path, 'r') as f: 101 | line = f.readline().strip() 102 | pid = int(line) 103 | 104 | # In the case that the lockfile exists, but the pid does not 105 | # correspond to a valid process, remove the file. 106 | if not psutil.pid_exists(pid): 107 | os.remove(self.path) 108 | 109 | except ValueError as e: 110 | # Pidfile is invalid, so just delete it. 111 | os.remove(self.path) 112 | 113 | except IOError as e: 114 | # Something happened while trying to read/remove the file, so 115 | # skip trying to read/remove it. 116 | pass 117 | 118 | try: 119 | self.fd = os.open(self.path, os.O_CREAT | os.O_EXCL | os.O_RDWR) 120 | 121 | # PID is written to the file, so that if a process exits wtihout 122 | # cleaning up the lockfile, we can still acquire the lock. 123 | to_write = '%s%s' % (os.getpid(), os.linesep) 124 | os.write(self.fd, to_write.encode()) 125 | 126 | except OSError as e: 127 | if not os.path.exists(self.path): 128 | raise 129 | return False 130 | 131 | self.acquired = True 132 | return True 133 | 134 | def release(self): 135 | """Cleans up the lockfile if it was acquired. 136 | 137 | Args: 138 | self (JLock): the ``JLock`` instance 139 | 140 | Returns: 141 | ``False`` if the lock was not released or the lock is not acquired, 142 | otherwise ``True``. 143 | """ 144 | if not self.acquired: 145 | return False 146 | 147 | os.close(self.fd) 148 | 149 | if os.path.exists(self.path): 150 | os.remove(self.path) 151 | 152 | self.acquired = False 153 | return True 154 | -------------------------------------------------------------------------------- /pylink/protocols/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /pylink/threads.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import threading 16 | 17 | 18 | class ThreadReturn(threading.Thread): 19 | """Implementation of a thread with a return value. 20 | 21 | See also: 22 | `StackOverflow `__. 23 | """ 24 | 25 | def __init__(self, daemon=False, *args, **kwargs): 26 | """Initializes the thread. 27 | 28 | Args: 29 | self (ThreadReturn): the ``ThreadReturn`` instance 30 | daemon (bool): if the thread should be spawned as a daemon 31 | args: optional list of arguments 32 | kwargs: optional key-word arguments 33 | 34 | Returns: 35 | ``None`` 36 | """ 37 | super(ThreadReturn, self).__init__(*args, **kwargs) 38 | self.daemon = daemon 39 | self._return = None 40 | 41 | def run(self): 42 | """Runs the thread. 43 | 44 | Args: 45 | self (ThreadReturn): the ``ThreadReturn`` instance 46 | 47 | Returns: 48 | ``None`` 49 | """ 50 | target = getattr(self, '_Thread__target', getattr(self, '_target', None)) 51 | args = getattr(self, '_Thread__args', getattr(self, '_args', None)) 52 | kwargs = getattr(self, '_Thread__kwargs', getattr(self, '_kwargs', None)) 53 | if target is not None: 54 | self._return = target(*args, **kwargs) 55 | 56 | return None 57 | 58 | def join(self, *args, **kwargs): 59 | """Joins the thread. 60 | 61 | Args: 62 | self (ThreadReturn): the ``ThreadReturn`` instance 63 | args: optional list of arguments 64 | kwargs: optional key-word arguments 65 | 66 | Returns: 67 | The return value of the exited thread. 68 | """ 69 | super(ThreadReturn, self).join(*args, **kwargs) 70 | return self._return 71 | -------------------------------------------------------------------------------- /pylink/unlockers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from .unlock_kinetis import unlock_kinetis 16 | 17 | 18 | def unlock(jlink, name): 19 | """Unlocks a J-Link's target device. 20 | 21 | Args: 22 | jlink (JLink): the connected J-Link device 23 | name (str): the MCU name (e.g. Kinetis) 24 | 25 | Supported Names: 26 | - Kinetis 27 | 28 | Returns: 29 | ``True`` if the device was unlocked, otherwise ``False``. 30 | 31 | Raises: 32 | NotImplementedError: if no unlock method exists for the MCU. 33 | """ 34 | if name.lower() in ['kinetis', 'freescale', 'nxp']: 35 | return unlock_kinetis(jlink) 36 | raise NotImplementedError('No unlock method for %s' % name) 37 | -------------------------------------------------------------------------------- /pylink/util.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017 Square, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | from . import enums 17 | 18 | import platform 19 | import sys 20 | 21 | 22 | def is_integer(val): 23 | """Returns whether the given value is an integer. 24 | 25 | Args: 26 | val (object): value to check 27 | 28 | Returns: 29 | ``True`` if the given value is an integer, otherwise ``False``. 30 | """ 31 | try: 32 | val += 1 33 | except TypeError: 34 | return False 35 | return True 36 | 37 | 38 | def is_natural(val): 39 | """Returns whether the given value is a natrual number. 40 | 41 | Args: 42 | val (object): value to check 43 | 44 | Returns: 45 | ``True`` if the given value is a natural number, otherwise ``False``. 46 | """ 47 | return is_integer(val) and (val >= 0) 48 | 49 | 50 | def is_os_64bit(): 51 | """Returns whether the current running platform is 64bit. 52 | 53 | Returns: 54 | ``True`` if the platform is 64bit, otherwise ``False``. 55 | """ 56 | return platform.machine().endswith('64') 57 | 58 | 59 | def noop(*args, **kwargs): 60 | """No-op. Does nothing. 61 | 62 | Args: 63 | args: list of arguments 64 | kwargs: keyword arguments dictionary 65 | 66 | Returns: 67 | ``None`` 68 | """ 69 | pass 70 | 71 | 72 | def unsecure_hook_dialog(title, msg, flags): 73 | """No-op that ignores the dialog. 74 | 75 | Args: 76 | title (str): title of the unsecure dialog 77 | msg (str): text of the unsecure dialog 78 | flags (int): flags specifying which values can be returned 79 | 80 | Returns: 81 | ``enums.JLinkFlags.DLG_BUTTON_NO`` 82 | """ 83 | return enums.JLinkFlags.DLG_BUTTON_NO 84 | 85 | 86 | def progress_bar(iteration, 87 | total, 88 | prefix=None, 89 | suffix=None, 90 | decs=1, 91 | length=100): 92 | """Creates a console progress bar. 93 | 94 | This should be called in a loop to create a progress bar. 95 | 96 | See `StackOverflow `__. 97 | 98 | Args: 99 | iteration (int): current iteration 100 | total (int): total iterations 101 | prefix (str): prefix string 102 | suffix (str): suffix string 103 | decs (int): positive number of decimals in percent complete 104 | length (int): character length of the bar 105 | 106 | Returns: 107 | ``None`` 108 | 109 | Note: 110 | This function assumes that nothing else is printed to the console in the 111 | interim. 112 | """ 113 | if prefix is None: 114 | prefix = '' 115 | 116 | if suffix is None: 117 | suffix = '' 118 | 119 | format_str = '{0:.' + str(decs) + 'f}' 120 | percents = format_str.format(100 * (iteration / float(total))) 121 | filled_length = int(round(length * iteration / float(total))) 122 | bar = '█' * filled_length + '-' * (length - filled_length) 123 | 124 | prefix, suffix = prefix.strip(), suffix.strip() 125 | 126 | sys.stdout.write('\r%s |%s| %s%s %s' % (prefix, bar, percents, '%', suffix)) 127 | sys.stdout.flush() 128 | 129 | if iteration == total: 130 | sys.stdout.write('\n') 131 | sys.stdout.flush() 132 | 133 | return None 134 | 135 | 136 | def flash_progress_callback(action, progress_string, percentage): 137 | """Callback that can be used with ``JLink.flash()``. 138 | 139 | This callback generates a progress bar in the console to show the progress 140 | of each of the steps of the flash. 141 | 142 | Args: 143 | action (str): the current action being invoked 144 | progress_string (str): the current step in the progress 145 | percentage (int): the percent to which the current step has been done 146 | 147 | Returns: 148 | ``None`` 149 | 150 | Note: 151 | This function ignores the compare action. 152 | """ 153 | if action.lower() != 'compare': 154 | return progress_bar(min(100, percentage), 100, prefix=action) 155 | 156 | return None 157 | 158 | 159 | def calculate_parity(n): 160 | """Calculates and returns the parity of a number. 161 | 162 | The parity of a number is ``1`` if the number has an odd number of ones 163 | in its binary representation, otherwise ``0``. 164 | 165 | Args: 166 | n (int): the number whose parity to calculate 167 | 168 | Returns: 169 | ``1`` if the number has an odd number of ones, otherwise ``0``. 170 | 171 | Raises: 172 | ValueError: if ``n`` is less than ``0``. 173 | """ 174 | if not is_natural(n): 175 | raise ValueError('Expected n to be a positive integer.') 176 | 177 | y = 0 178 | n = abs(n) 179 | while n: 180 | y += n & 1 181 | n = n >> 1 182 | return y & 1 183 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [pycodestyle] 2 | max-line-length = 120 3 | exclude = .eggs 4 | 5 | [metadata] 6 | description-file = README.md 7 | 8 | [bdist_wheel] 9 | universal = 1 10 | 11 | [behave] 12 | color = True 13 | summary = True 14 | 15 | [options.extras_require] 16 | dev = 17 | behave==1.2.5 18 | coverage==4.4.1 19 | psutil>=5.2.2 20 | pycodestyle>=2.3.1 21 | setuptools>=70.2.0 22 | six 23 | sphinx==1.4.8 24 | sphinx-argparse==0.1.15 25 | sphinx_rtd_theme==0.2.4 26 | sphinxcontrib-napoleon==0.5.3 27 | wheel 28 | test = 29 | mock==2.0.0 30 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | The tests for this project are split into two sections: unit tests, and 3 | functional tests. Functional tests live under the `functional` directory, 4 | while unit tests live under the `unit` directory. 5 | 6 | 7 | ## Unit Tests 8 | Unit tests are those that verify the behaviour of the library. These use 9 | mocked calls for calls that require actual hardware (such as the J-Link DLL 10 | calls). Unit tests should be created for every function to test that the 11 | correct behaviour is there. This is especially necessary since Python is a 12 | dynamic language, so things such as misspellings will not be caught until the 13 | actual code is run. 14 | 15 | 16 | ## Functional Tests 17 | Functional Tests live under the `functional` directory. The functional tests 18 | are implemented using [`behave`](http://pythonhosted.org/behave/), a Behaviour 19 | Driven Development (BDD) library. 20 | 21 | 22 | ### Firmware 23 | Firmware goes underneath the `firmware` directory within the `functional` 24 | directory. It must include a `Makefile` that builds its dependency underneath 25 | a `build` directory within the same directory (the output firmware should be 26 | labelled `firmware.{elf,bin}`. 27 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /tests/functional/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /tests/functional/features/jlink/canary.feature: -------------------------------------------------------------------------------- 1 | @connection 2 | Feature: Stack Canary 3 | In order to prevent unusual behaviour 4 | When my stack is corrupted 5 | I want the stack canary to trigger 6 | 7 | Scenario: Buffer Overflow 8 | Given my J-Link is connected 9 | And target interface SWD 10 | And device MK21FX512xxx12 (ALLOW SECURITY) 11 | When I flash the firmware K21-Canary 12 | And I reset my device 13 | Then the device should be halted 14 | -------------------------------------------------------------------------------- /tests/functional/features/jlink/debugger.feature: -------------------------------------------------------------------------------- 1 | @connection 2 | Feature: Debugging Firmware 3 | As a developer, 4 | I want to be able to trace my code. 5 | 6 | Scenario: Setting a Breakpoint 7 | Given my J-Link is connected 8 | And target interface SWD 9 | And device MK21FX512xxx12 (ALLOW SECURITY) 10 | And I enable soft breakpoints 11 | When I flash the firmware K21-LOOP 12 | And I reset my device 13 | And I set a breakpoint at address 0x480 14 | Then the device should be halted 15 | And I should have 1 breakpoint 16 | 17 | Scenario: Clearing a Breakpoint 18 | Given my J-Link is connected 19 | And target interface SWD 20 | And device MK21FX512xxx12 (ALLOW SECURITY) 21 | And I enable soft breakpoints 22 | When I flash the firmware K21-LOOP 23 | And I reset my device 24 | And I set a breakpoint at address 0x480 25 | Then I can clear the breakpoints 26 | And I should have 0 breakpoints 27 | 28 | Scenario: Setting a Watchpoint 29 | Given my J-Link is connected 30 | And target interface SWD 31 | And device MK21FX512xxx12 (ALLOW SECURITY) 32 | When I flash the firmware K21-LOOP 33 | And I set a watchpoint at address 0x1FFF0000 for data 0x1337 34 | And I reset my device 35 | Then I should have 1 watchpoint 36 | 37 | Scenario: Clearing a Watchpoint 38 | Given my J-Link is connected 39 | And target interface SWD 40 | And device MK21FX512xxx12 (ALLOW SECURITY) 41 | When I flash the firmware K21-LOOP 42 | And I set a watchpoint at address 0x1FFF0000 for data 0x1337 43 | Then I can clear the watchpoints 44 | And I should have 0 watchpoints 45 | -------------------------------------------------------------------------------- /tests/functional/features/jlink/emulator.feature: -------------------------------------------------------------------------------- 1 | @connection 2 | Feature: J-Link Communication 3 | As a developer, 4 | I want to be able to communicate with my J-Links. 5 | 6 | Scenario: Disconnecting from the J-Link 7 | Given my J-Link is connected 8 | And I close the J-Link 9 | Then the emulator should not be connected 10 | 11 | Scenario: Accessing multiple J-links from the same process 12 | Given my J-Link is connected 13 | Then a new J-Link should not be connected 14 | 15 | @nix 16 | Scenario: Accessing one J-link from multiple processes 17 | Given my J-Link is connected 18 | When I create a new process with my J-Link 19 | Then that process's J-Link is also connected 20 | 21 | Scenario: Accessing the same J-Link multiple times 22 | Given my J-Link is connected 23 | Then I should not be able to open a new connection to it 24 | -------------------------------------------------------------------------------- /tests/functional/features/jlink/flash.feature: -------------------------------------------------------------------------------- 1 | @connection 2 | Feature: Flashing Firmware 3 | In order to use my device 4 | I want to be able to flash firmware. 5 | 6 | Scenario: Flashing New Firmware From a File 7 | Given my J-Link is connected 8 | And target interface SWD 9 | And device MK21FX512xxx12 (ALLOW SECURITY) 10 | Then I can flash the firmware K21-SWO with 0 retries 11 | 12 | Scenario: Flashing New Firmware From a Bytestream 13 | Given my J-Link is connected 14 | And target interface SWD 15 | And device MK21FX512xxx12 (ALLOW SECURITY) 16 | When I read the firmware K21-SWO into a bytestream 17 | Then I can flash the firmware with 0 retries 18 | -------------------------------------------------------------------------------- /tests/functional/features/jlink/license.feature: -------------------------------------------------------------------------------- 1 | @connection 2 | Feature: Licenses 3 | As a J-Link owner, 4 | I want to be able to control the licenses on my J-Link 5 | In order to enable or disable functionality for third party software. 6 | 7 | Scenario: Adding a license 8 | Given my J-Link is connected 9 | When I add the license: 10 | """ 11 | IAR 12 | """ 13 | Then my J-Link should have the license 14 | """ 15 | IAR 16 | """ 17 | 18 | Scenario: Erasing a license 19 | Given my J-Link is connected 20 | And has the license: 21 | """ 22 | VCOM 23 | """ 24 | When I erase the licenses 25 | Then my J-Link should have no licenses 26 | -------------------------------------------------------------------------------- /tests/functional/features/jlink/memory.feature: -------------------------------------------------------------------------------- 1 | @connection 2 | Feature: Memory 3 | As a developer, 4 | I want to be able to write and read from memory. 5 | 6 | Scenario Outline: Writing to Device Memory 7 | Given my J-Link is connected 8 | And target interface SWD 9 | And device MK21FX512xxx12 (ALLOW SECURITY) 10 | When I write the -bit integer to memory 11 | Then I should read the -bit integer from memory 12 | 13 | Examples: 14 | | size | value | 15 | | 8 | 254 | 16 | | 16 | 32767 | 17 | | 32 | 2147483637 | 18 | | 64 | 9223372036854775807 | 19 | 20 | Scenario: Overflow on Writing to Device Memory 21 | Given my J-Link is connected 22 | And target interface SWD 23 | And device MK21FX512xxx12 24 | When I write the 8-bit integer 256 to memory 25 | Then I should read the 8-bit integer 0 from memory 26 | 27 | Scenario: Underflow on Reading from Device Memory 28 | Given my J-Link is connected 29 | And target interface SWD 30 | And device MK21FX512xxx12 31 | When I write the 16-bit integer 256 to memory 32 | Then I should read the 8-bit integer 0 from memory 33 | 34 | Scenario: Reading from Code Memory 35 | Given my J-Link is connected 36 | And target interface SWD 37 | And device MK21FX512xxx12 38 | When I write the 8-bit integer 92 to memory 39 | Then I should read the integer 92 from code memory 40 | -------------------------------------------------------------------------------- /tests/functional/features/jlink/register.feature: -------------------------------------------------------------------------------- 1 | @connection 2 | Feature: Registers 3 | As a developer, 4 | I want to be able to write and read from registers. 5 | 6 | Scenario: Writing to a Single Register 7 | Given my J-Link is connected 8 | And target interface SWD 9 | And device MK21FX512xxx12 (ALLOW SECURITY) 10 | When I halt the device 11 | And I write 42 to register 0 12 | Then register 0 should have the value 42 13 | 14 | Scenario: Writing to Multiple Registers 15 | Given my J-Link is connected 16 | And target interface SWD 17 | And device MK21FX512xxx12 (ALLOW SECURITY) 18 | When I halt the device 19 | And I write to the registers: 20 | | register | value | 21 | | 0 | 32 | 22 | | 1 | 43 | 23 | | 7 | 1337 | 24 | | 11 | 99 | 25 | Then I should read from the registers: 26 | | register | value | 27 | | 0 | 32 | 28 | | 1 | 43 | 29 | | 7 | 1337 | 30 | | 11 | 99 | 31 | -------------------------------------------------------------------------------- /tests/functional/features/jlink/rtt.feature: -------------------------------------------------------------------------------- 1 | @connection 2 | Feature: RTT 3 | In order to debug my firmware 4 | I want to be able to use RTT 5 | To write and receive real-time debug information 6 | 7 | Scenario: Echoing data over RTT 8 | Given my J-Link is connected 9 | And target interface SWD 10 | And device MK21FX512xxx12 (ALLOW SECURITY) 11 | When I flash the firmware K21-RTT 12 | And I reset my device 13 | And I enable RTT with config block 0x1FFF0424 14 | When I write "aardvark" to RTT channel 0 15 | Then I should read "aardvark" on RTT channel 0 16 | -------------------------------------------------------------------------------- /tests/functional/features/jlink/swd.feature: -------------------------------------------------------------------------------- 1 | @connection 2 | Feature: Serial Wire Debug 3 | In order to debug my firmware 4 | I want to be able to use semihosting 5 | To receive semihosted operations 6 | 7 | Scenario: Calling printf under semihosting 8 | Given my J-Link is connected 9 | And target interface SWD 10 | And device MK21FX512xxx12 (ALLOW SECURITY) 11 | When I flash the firmware K21-SWD 12 | And I enable semihosting 13 | And I reset my device 14 | Then the device should be halted 15 | And I should see over SWD: 16 | """ 17 | You must construct additional pylons. 18 | """ 19 | -------------------------------------------------------------------------------- /tests/functional/features/jlink/swo.feature: -------------------------------------------------------------------------------- 1 | @connection 2 | Feature: Serial Wire Output 3 | In order to test my firmware 4 | I want to be able to use Serial Wire Output 5 | To trace the instructions 6 | 7 | Scenario: Reading from Serial Wire Output 8 | Given my J-Link is connected 9 | And target interface SWD 10 | And device MK21FX512xxx12 (ALLOW SECURITY) 11 | When I flash the firmware K21-SWO 12 | And I enable SWO on port 0 13 | Then I should see "You must construct additional pylons." 14 | -------------------------------------------------------------------------------- /tests/functional/features/jlink/unlock.feature: -------------------------------------------------------------------------------- 1 | @connection 2 | Feature: Unlocking a Device 3 | When my device is locked 4 | I want to be able to unlock it. 5 | 6 | Scenario: Unlocking a Kinetis Device 7 | Given my J-Link is connected 8 | And target interface SWD 9 | And device MK21FX512xxx12 (ALLOW SECURITY) 10 | When my Kinetis device is locked 11 | And I unlock it 12 | Then I should be able to write to flash 13 | -------------------------------------------------------------------------------- /tests/functional/features/jlink/update.feature: -------------------------------------------------------------------------------- 1 | @connection 2 | Feature: Firmware Update 3 | In order to get the latest bug fixes 4 | I want to be able to update my J-Link's firmware 5 | 6 | Scenario: Updating the Firmware 7 | Given my J-Link is connected 8 | Then I can update the firmware 9 | 10 | Scenario: Forcing a Firmware Update 11 | Given my J-Link is connected 12 | And I invalidate the firmware 13 | Then I can force a firmware update 14 | -------------------------------------------------------------------------------- /tests/functional/features/steps/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /tests/functional/features/steps/licenses.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import behave 16 | 17 | 18 | @behave.given('has the license') 19 | @behave.when('I add the license') 20 | def step_add_license(context): 21 | """Adds a license to the J-Link. 22 | 23 | Args: 24 | context (Context): the ``Context`` instance 25 | 26 | Returns: 27 | ``None`` 28 | """ 29 | jlink = context.jlink 30 | assert jlink.add_license(str(context.text)) 31 | 32 | 33 | @behave.when('I erase the licenses') 34 | def step_erase_licenses(context): 35 | """Erases the J-Link's licenses. 36 | 37 | Args: 38 | context (Context): the ``Context`` instance 39 | 40 | Returns: 41 | ``None`` 42 | """ 43 | jlink = context.jlink 44 | assert jlink.erase_licenses() 45 | 46 | 47 | @behave.then('my J-Link should have the license') 48 | def step_has_license(context): 49 | """Asserts the J-Link has the given licenese. 50 | 51 | Args: 52 | context (Context): the ``Context`` instance 53 | 54 | Returns: 55 | ``None`` 56 | """ 57 | jlink = context.jlink 58 | expected = context.text.strip() 59 | actual = jlink.custom_licenses.strip() 60 | assert actual.startswith(expected) 61 | assert jlink.erase_licenses() 62 | 63 | 64 | @behave.then('my J-Link should have no licenses') 65 | def step_no_licenses(context): 66 | """Asserts the J-Link has no licenses. 67 | 68 | Args: 69 | context (Context): the ``Context`` instance 70 | 71 | Returns: 72 | ``None`` 73 | """ 74 | assert len(context.jlink.custom_licenses) == 0 75 | -------------------------------------------------------------------------------- /tests/functional/features/steps/memory.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import behave 16 | 17 | MEMORY_ADDR = 0x500 18 | 19 | 20 | @behave.when('I write the {size}-bit integer {value} to memory') 21 | def step_write_memory(context, size, value): 22 | """Writes a value to the memory of the device. 23 | 24 | Args: 25 | context (Context): the ``Context`` instance 26 | size (str): the number of bits to use for the value 27 | value (str): the value to write 28 | 29 | Returns: 30 | ``None`` 31 | """ 32 | jlink = context.jlink 33 | methods = { 34 | '8': jlink.memory_write8, 35 | '16': jlink.memory_write16, 36 | '32': jlink.memory_write32, 37 | '64': jlink.memory_write64 38 | } 39 | 40 | method = methods.get(size, None) 41 | assert method is not None 42 | 43 | data = [int(value)] 44 | num_bytes = method(MEMORY_ADDR, data) 45 | expected_num_bytes = int(size) / 8 46 | assert num_bytes == expected_num_bytes 47 | 48 | 49 | @behave.then('I should read the {size}-bit integer {value} from memory') 50 | def step_read_memory(context, size, value): 51 | """Reads a value from the memory of the device. 52 | 53 | Args: 54 | context (Context): the ``Context`` instance 55 | size (str): the number of bits to use for the value 56 | value (str): the value to read 57 | 58 | Returns: 59 | ``None`` 60 | """ 61 | jlink = context.jlink 62 | methods = { 63 | '8': jlink.memory_read8, 64 | '16': jlink.memory_read16, 65 | '32': jlink.memory_read32, 66 | '64': jlink.memory_read64 67 | } 68 | 69 | method = methods.get(size, None) 70 | assert method is not None 71 | 72 | expected = int(value) 73 | actual = method(MEMORY_ADDR, 1)[0] 74 | assert expected == actual 75 | 76 | 77 | @behave.then('I should read the integer {value} from code memory') 78 | def step_read_code_memory(context, value): 79 | """Reads and checks a value from code memory. 80 | 81 | Args: 82 | context (Context): the ``Context`` instance 83 | value (str): the value that should be read 84 | 85 | Returns: 86 | ``None`` 87 | """ 88 | actual = context.jlink.code_memory_read(MEMORY_ADDR, 1)[0] 89 | expected = int(value) 90 | assert actual == expected 91 | -------------------------------------------------------------------------------- /tests/functional/features/steps/registers.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import behave 16 | 17 | 18 | @behave.when('I write {value} to ICE register {register}') 19 | def step_write_to_ice_register(context, value, register): 20 | """Writes a value to a single ICE register. 21 | 22 | Args: 23 | context (Context): the ``Context`` instance 24 | value (str): the value to write to the register 25 | register (str): the register to write to 26 | 27 | Returns: 28 | ``None`` 29 | """ 30 | jlink = context.jlink 31 | register = int(register, 0) 32 | value = int(value, 0) 33 | jlink.ice_register_write(register, value) 34 | 35 | 36 | @behave.when('I write {value} to register {register}') 37 | def step_write_to_register(context, value, register): 38 | """Writes a value to a single register. 39 | 40 | Args: 41 | context (Context): the ``Context`` instance 42 | value (str): the value to write to the register 43 | register (str): the register to write to 44 | 45 | Returns: 46 | ``None`` 47 | """ 48 | jlink = context.jlink 49 | jlink.register_write(int(register), int(value)) 50 | 51 | 52 | @behave.when('I write to the registers') 53 | def step_write_to_registers(context): 54 | """Writes multiple values to multiple registers. 55 | 56 | The values and registers are loaded from the context's table. 57 | 58 | Args: 59 | context (Context): the ``Context`` instance 60 | 61 | Returns: 62 | ``None`` 63 | """ 64 | jlink = context.jlink 65 | registers, values = [], [] 66 | for row in context.table: 67 | registers.append(int(row['register'])) 68 | values.append(int(row['value'])) 69 | jlink.register_write_multiple(registers, values) 70 | 71 | 72 | @behave.then('ICE register {register} should have the value {value}') 73 | def step_ice_register_has_value(context, register, value): 74 | """Checks that an ICE register has a particular value. 75 | 76 | Args: 77 | context (Context): the ``Context`` instance 78 | register (str): the ICE register to read from 79 | value (str): the value the ICE register should have 80 | 81 | Returns: 82 | ``None`` 83 | """ 84 | jlink = context.jlink 85 | register = int(register, 0) 86 | expected = int(value, 0) 87 | assert jlink.ice_register_read(register) == expected 88 | 89 | 90 | @behave.then('register {register} should have the value {value}') 91 | def step_register_has_value(context, register, value): 92 | """Reads a single value from a single register and asserts equality. 93 | 94 | Args: 95 | context (Context): the ``Context`` instance 96 | 97 | Returns: 98 | ``None`` 99 | """ 100 | jlink = context.jlink 101 | actual = jlink.register_read(int(register)) 102 | assert actual == int(value) 103 | 104 | 105 | @behave.then('I should read from the registers') 106 | def step_registers_have_values(context): 107 | """Reads multiple values from multiple registers and asserts equality. 108 | 109 | Args: 110 | context (Context): the ``Context`` instance 111 | 112 | Returns: 113 | ``None`` 114 | """ 115 | jlink = context.jlink 116 | registers, expected_values = [], [] 117 | for row in context.table: 118 | registers.append(int(row['register'])) 119 | expected_values.append(int(row['value'])) 120 | assert expected_values == jlink.register_read_multiple(registers) 121 | -------------------------------------------------------------------------------- /tests/functional/features/steps/rtt.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import behave 16 | import pylink 17 | 18 | import time 19 | 20 | 21 | @behave.when('I enable RTT with config block {block_address}') 22 | def step_enable_rtt(context, block_address): 23 | """Enables RTT. 24 | 25 | Args: 26 | context (Context): the ``Context`` instance 27 | block_address (str): the RTT config block address 28 | 29 | Returns: 30 | ``None`` 31 | """ 32 | jlink = context.jlink 33 | jlink.rtt_start(int(block_address, 16)) 34 | while True: 35 | try: 36 | jlink.rtt_get_num_up_buffers() 37 | jlink.rtt_get_num_down_buffers() 38 | break 39 | except pylink.errors.JLinkRTTException as e: 40 | time.sleep(0.1) 41 | 42 | assert jlink.rtt_get_num_up_buffers() > 0 43 | assert jlink.rtt_get_num_down_buffers() > 0 44 | 45 | 46 | @behave.when('I write "{message}" to RTT channel {channel}') 47 | def step_write_rtt_channel(context, message, channel): 48 | """Writes a message to an RTT channel. 49 | 50 | Args: 51 | context (Context): the ``Context`` instance 52 | message (str): the message to write 53 | channel (str): the RTT channel to write to 54 | 55 | Returns: 56 | ``None`` 57 | """ 58 | bytes_to_write = list(bytearray(message, 'utf-8') + b'\x0A\x00') 59 | jlink = context.jlink 60 | bytes_written = jlink.rtt_write(int(channel), bytes_to_write) 61 | assert len(bytes_to_write) == bytes_written 62 | 63 | 64 | @behave.then('I should read "{message}" on RTT channel {channel}') 65 | def step_read_rtt_channel(context, message, channel): 66 | """Checks that the expected message is read over the RTT channel. 67 | 68 | Args: 69 | context (Context): the ``Context`` instance 70 | message (str): the expected message 71 | channel (str): the RTT channel to read from 72 | 73 | Returns: 74 | ``None`` 75 | """ 76 | jlink = context.jlink 77 | expected = str(message) 78 | 79 | bytes_read = [] 80 | while len(bytes_read) < len(message): 81 | bytes_read += jlink.rtt_read(int(channel), 1024) 82 | time.sleep(0.1) 83 | 84 | actual = ''.join(map(chr, bytes_read)).strip() 85 | assert expected == actual 86 | -------------------------------------------------------------------------------- /tests/functional/features/steps/swd.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import behave 16 | 17 | import time 18 | 19 | 20 | @behave.when('I enable semihosting') 21 | def step_enable_semihosting(context): 22 | """Enables semihosting by setting a SVC break instruction. 23 | 24 | Args: 25 | context (Context): the ``Context`` instance 26 | 27 | Returns: 28 | ``None`` 29 | """ 30 | jlink = context.jlink 31 | jlink.set_vector_catch(1 << 2) 32 | 33 | 34 | @behave.then('I should see over SWD') 35 | def step_should_see_swd(context): 36 | """Asserts that the text over the SWD interface matches the given text. 37 | 38 | Args: 39 | context (Context): the ``Context`` instance 40 | 41 | Returns: 42 | ``None`` 43 | """ 44 | jlink = context.jlink 45 | expected_strings = context.text.split('\n') 46 | 47 | # r0 holds the type of command that resulted in the SVC exception. For a 48 | # full list of what these commands can be, please see the J-Link 49 | # documentation on semihosting ``UM8001_JLink.pdf`` 50 | command_register = 0x0 51 | 52 | # r1 holds a pointer to an address on the target that holds the additional 53 | # function arguments as 32-bit aligned words. 54 | command_info_register = 0x1 55 | 56 | while len(expected_strings) > 0: 57 | if not jlink.halted(): 58 | time.sleep(1) 59 | continue 60 | 61 | # The CPU is halted after a Vector Catch, so we can now examine why 62 | # the CPU halted. 63 | sys_write = 0x05 64 | command = jlink.register_read(command_register) 65 | assert command == sys_write 66 | 67 | command_info = jlink.register_read(command_info_register) 68 | handle, ptr, num_bytes = jlink.memory_read32(command_info, 3) 69 | actual_string = ''.join(map(chr, jlink.memory_read8(ptr, num_bytes))).strip() 70 | print(actual_string) 71 | 72 | actual_stripped = ''.join(actual_string.strip().split()) 73 | expected_stripped = ''.join(expected_strings.pop(0).strip().split()) 74 | assert actual_stripped.startswith(expected_stripped) 75 | 76 | # Resume execution to the original mode. Have to write the result of 77 | # the SVC call (always 0), and step over the breakpointed instruction. 78 | jlink.register_write(0x0, 0) 79 | jlink.step(thumb=True) 80 | assert jlink.restart(num_instructions=2, skip_breakpoints=True) 81 | -------------------------------------------------------------------------------- /tests/functional/features/steps/swo.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pylink 16 | 17 | import behave 18 | 19 | import string 20 | import time 21 | 22 | 23 | @behave.when('I enable SWO') 24 | def step_enable_swo(context): 25 | """Enables Serial Wire Output. 26 | 27 | Args: 28 | context (Context): the ``Context`` instance 29 | 30 | Returns: 31 | ``None`` 32 | """ 33 | return step_enable_swo_on_port(context, 0) 34 | 35 | 36 | @behave.when('I enable SWO on port {port}') 37 | def step_enable_swo_on_port(context, port): 38 | """Enables Serial Wire Output. 39 | 40 | Args: 41 | context (Context): the ``Context`` instance 42 | port (int): the port SWO is enabled on 43 | 44 | Returns: 45 | ``None`` 46 | """ 47 | jlink = context.jlink 48 | 49 | # Have to halt the CPU before getting its speed. 50 | jlink.reset() 51 | jlink.halt() 52 | assert jlink.halted() 53 | 54 | cpu_speed = jlink.cpu_speed() 55 | swo_speed = jlink.swo_supported_speeds(cpu_speed, 3)[0] 56 | 57 | # Enable SWO and flush. This must come before the reset to ensure that no 58 | # data is present in the SWO buffer when the core restarts. 59 | jlink.swo_start(swo_speed) 60 | jlink.swo_flush() 61 | 62 | assert jlink.swo_enabled() 63 | 64 | # Reset the core without halting so that it runs. 65 | jlink.reset(ms=10, halt=False) 66 | time.sleep(1) 67 | 68 | 69 | @behave.then('I should see "{message}"') 70 | def step_should_see(context, message): 71 | """Asserts that the given message was read. 72 | 73 | Args: 74 | context (Context): the ``Context`` instance 75 | message (str): the message at the head of the SWO buffer 76 | 77 | Returns: 78 | ``None`` 79 | """ 80 | data = context.jlink.swo_read_stimulus(0, 0x800) 81 | actual = ''.join(map(chr, data)) 82 | 83 | print('Actual = %s' % actual) 84 | print('Expected = %s' % message) 85 | assert len(actual) == len(message) 86 | assert actual == message 87 | -------------------------------------------------------------------------------- /tests/functional/features/steps/unlock.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pylink 16 | 17 | import behave 18 | 19 | import time 20 | 21 | 22 | @behave.when('my {device} device is locked') 23 | def step_device_locked(context, device): 24 | """Locks the specified device. 25 | 26 | Note: 27 | Currently only supports Kinetis. 28 | 29 | Args: 30 | context (Context): the ``Context`` instance 31 | device (str): the type of device to lock 32 | 33 | Returns: 34 | ``None`` 35 | """ 36 | assert device.lower() == 'kinetis' 37 | 38 | context.device = device 39 | 40 | # Security bytes. These bytes control the device security. We want to 41 | # secure the device, but still allow it to be mass-erased (otherwise the 42 | # device will be permanently locked. 43 | fcf_offset = 0x400 44 | fcf_bytes = [ 45 | 0xFF, # Backdoor comparison key (unused, 8 bytes long) 46 | 0xFF, 47 | 0xFF, 48 | 0xFF, 49 | 0xFF, 50 | 0xFF, 51 | 0xFF, 52 | 0xFF, 53 | 0xFF, # Flash protection settings (4 bytes long) 54 | 0xFF, 55 | 0xFF, 56 | 0xFF, 57 | 0x03, # FSEC register - mass erase enabled, flash security enabled 58 | 0x07, # FOPT register - NMI enabled, EzPort enabled, normal boot 59 | 0xFF, # Data flash protection settings (unused) 60 | 0xFF, # EEPROM settings (unused) 61 | ] 62 | assert context.jlink.flash_write(fcf_offset, fcf_bytes) >= 0 63 | 64 | # Reset the device for the changes to take. 65 | context.jlink.reset() 66 | context.jlink.halt() 67 | 68 | try: 69 | # This write should fail as the device is flash protected now. 70 | context.jlink.flash_write(fcf_offset, fcf_bytes) 71 | except Exception as e: 72 | pass 73 | else: 74 | assert False 75 | 76 | time.sleep(1) 77 | 78 | 79 | @behave.when('I unlock it') 80 | def step_unlock_device(context): 81 | """Unlocks the connected device. 82 | 83 | Args: 84 | context (Context): the ``Context`` instance 85 | 86 | Returns: 87 | ``None`` 88 | """ 89 | jlink = context.jlink 90 | device = context.device 91 | 92 | assert jlink.halt() 93 | 94 | jlink.set_reset_strategy(pylink.JLinkResetStrategyCortexM3.RESETPIN) 95 | jlink.reset() 96 | jlink.set_reset_strategy(pylink.JLinkResetStrategyCortexM3.NORMAL) 97 | 98 | assert jlink.target_connected() 99 | assert jlink.unlock() 100 | 101 | 102 | @behave.then('I should be able to write to flash') 103 | def step_check_write_to_flash(context): 104 | """Checks that the target can be written to over flash. 105 | 106 | Args: 107 | context (Context): the ``Context`` instance 108 | 109 | Returns: 110 | ``None`` 111 | """ 112 | jlink = context.jlink 113 | assert jlink.target_connected() 114 | assert context.jlink.flash_write(0x40C, [0x2]) >= 0 115 | -------------------------------------------------------------------------------- /tests/functional/features/steps/update.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pylink 16 | 17 | import behave 18 | 19 | 20 | @behave.given('I invalidate the firmware') 21 | def step_firmware_invalidate(context): 22 | """Invalidtes the emulator's firmware. 23 | 24 | Args: 25 | context: the ``Context`` instance 26 | 27 | Returns: 28 | ``None`` 29 | """ 30 | context.jlink.invalidate_firmware() 31 | 32 | 33 | @behave.then('I can update the firmware') 34 | def step_firmware_update(context): 35 | """Asserts that the firmware can be updated. 36 | 37 | Args: 38 | context: the ``Context`` instance 39 | 40 | Returns: 41 | ``None`` 42 | """ 43 | assert context.jlink.update_firmware() >= 0 44 | 45 | 46 | @behave.then('I can force a firmware update') 47 | def step_force_firmware_update(context): 48 | """Asserts that the firmware can be force updated. 49 | 50 | Args: 51 | context: the ``Context`` instance 52 | 53 | Returns: 54 | ``None`` 55 | """ 56 | assert context.jlink.update_firmware() >= 0 57 | 58 | log_messages = context.log.getvalue().split('\n') 59 | assert 'New firmware booted successfully' in log_messages[-1] 60 | -------------------------------------------------------------------------------- /tests/functional/features/utility.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pylink 16 | 17 | import os 18 | import subprocess 19 | import sys 20 | 21 | 22 | def root_dir(): 23 | """Retrives the root testing directory. 24 | 25 | Returns: 26 | The root testing directory. 27 | """ 28 | dirname = os.path.abspath(os.path.dirname(__file__)) 29 | return os.path.abspath(os.path.join(dirname, os.pardir)) 30 | 31 | 32 | def firmware_path(firmware): 33 | """Returns the path to given firmware, provided it exists. 34 | 35 | Args: 36 | firmware (str): the firmware to search for 37 | 38 | Returns: 39 | The file path to the firmware if it exists, otherwise ``None``. 40 | """ 41 | fw = os.path.join(root_dir(), 'firmware', firmware, 'build', 'firmware.bin') 42 | if not os.path.isfile(fw): 43 | return None 44 | 45 | if not sys.platform.startswith('cygwin'): 46 | return fw 47 | 48 | cygpath_exe = os.path.join(os.path.abspath(os.sep), 'bin', 'cygpath.exe') 49 | cygpath_cmd = [cygpath_exe, '-a', '-m', '-f', '-'] 50 | cygpath_proc = subprocess.Popen(cygpath_cmd, 51 | stdin=subprocess.PIPE, 52 | stdout=subprocess.PIPE) 53 | cygpath_proc.stdin.write(fw + os.sep) 54 | return cygpath_proc.stdout.readline().rstrip() 55 | 56 | 57 | def flash(jlink, firmware): 58 | """Flashes the given firmware to the target. 59 | 60 | Args: 61 | jlink (JLink): the connected ``JLink`` instance 62 | firmware (str): the path to the firmware to flash 63 | 64 | Returns: 65 | The number of bytes flashed. 66 | """ 67 | return jlink.flash_file(firmware, 0) 68 | 69 | 70 | def flash_k21(jlink, firmware): 71 | """Flashes the given firmware onto K21. 72 | 73 | Args: 74 | jlink (JLink): the connected ``JLink`` instance 75 | firmware (str): the path to the firmware to flash 76 | 77 | Returns: 78 | The number of bytes flashed. 79 | """ 80 | jlink.power_on() 81 | jlink.set_reset_strategy(pylink.enums.JLinkResetStrategyCortexM3.RESETPIN) 82 | jlink.reset() 83 | 84 | if not pylink.unlock_kinetis(jlink): 85 | jlink.power_off() 86 | return -1 87 | 88 | res = jlink.flash_file(firmware, 0) 89 | jlink.reset() 90 | jlink.power_off() 91 | 92 | return res 93 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-canary/.gdbinit: -------------------------------------------------------------------------------- 1 | target remote :2331 2 | monitor speed auto 3 | monitor endian little 4 | monitor flash device $DEVICE 5 | monitor flash breakpoints = 1 6 | monitor semihosting enable 7 | monitor semihosting IOClient = 2 8 | monitor reset 6 9 | load build/firmware.elf 10 | file build/firmware.elf 11 | monitor reset 6 12 | monitor reset 6 13 | 14 | # Continue 15 | c 16 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-canary/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Square, Inc. 2 | 3 | # Commands 4 | TARGET_PREFIX = arm-none-eabi- 5 | AS = $(TARGET_PREFIX)as 6 | LD = $(TARGET_PREFIX)ld 7 | CC = $(TARGET_PREFIX)gcc 8 | CPP = $(TARGET_PREFIX)g++ 9 | OBJCOPY = $(TARGET_PREFIX)objcopy 10 | CP = cp 11 | MKDIR = mkdir 12 | 13 | # Directories 14 | BUILDDIR = build 15 | ASMDIR = asm 16 | SRCDIR = src 17 | 18 | # Flags 19 | ASFLAGS = -g -mthumb -mcpu=cortex-m4 20 | LDFLAGS = -T$(ASMDIR)/gcc.ld --specs=nosys.specs -mthumb -mcpu=cortex-m4 21 | CCFLAGS = -S -Wall -O0 -mcpu=cortex-m4 -mthumb -g -fstack-protector-all 22 | 23 | # Output Files 24 | BIN = $(BUILDDIR)/firmware.bin 25 | ELF = $(BUILDDIR)/firmware.elf 26 | ASOURCES = $(notdir $(wildcard $(ASMDIR)/*.s)) 27 | CSOURCES = $(notdir $(wildcard $(SRCDIR)/*.c)) 28 | OBJS = $(addprefix $(BUILDDIR)/,$(ASOURCES:.s=.o)) $(addprefix $(BUILDDIR)/,$(CSOURCES:.c=.o)) 29 | 30 | .PHONY: all clean 31 | 32 | all: $(BIN) 33 | 34 | clean: 35 | -$(RM) -rf $(BUILDDIR) 36 | 37 | $(ELF): $(OBJS) 38 | @$(MKDIR) -p $(BUILDDIR) 39 | $(CC) $(LDFLAGS) -o $@ $^ 40 | 41 | $(BUILDDIR)/%.o: $(BUILDDIR)/%.s 42 | @$(MKDIR) -p $(BUILDDIR) 43 | $(AS) $(ASFLAGS) -o $@ $< 44 | 45 | $(BUILDDIR)/%.s: $(ASMDIR)/%.s 46 | @$(MKDIR) -p $(BUILDDIR) 47 | $(CP) $< $(BUILDDIR)/ 48 | 49 | $(BUILDDIR)/%.s: $(SRCDIR)/%.c 50 | @$(MKDIR) -p $(BUILDDIR) 51 | $(CC) $(CCFLAGS) -o $@ $< 52 | 53 | %.bin: %.elf 54 | $(OBJCOPY) -O binary $< $@ 55 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-canary/README.md: -------------------------------------------------------------------------------- 1 | # K21 Stack Canary 2 | 3 | This firmware build demonstrates implementing a stack canary. If the build is 4 | successfull, the canary will cause a hard fault, otherwise the firmware will 5 | sit in a while loop forever. This firmware is known to work on the `K21F120M` 6 | and `K21D50M` evaluation boards. 7 | 8 | ## Bulding the Firmware 9 | 10 | To build the firmware, run `make` from within the directory. This will create 11 | a build directory containing the binary files. 12 | 13 | ## Firmware Overview 14 | 15 | This firmware does the following things on boot: 16 | 17 | 1. Stops the watchdog timer. 18 | 2. Calls a function that overflows its stack. 19 | 3. Sits in a while-loop forever if the canary was not triggered. 20 | 21 | Provided the stack canary was hit, it should trigger a `BKPT` instruction, 22 | which will halt the CPU. 23 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-canary/asm/gcc.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K 4 | RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 64K 5 | } 6 | 7 | /* Linker script to place sections and symbol values. Should be used together 8 | * with other linker script that defines memory regions FLASH and RAM. 9 | * It references following symbols, which must be defined in code: 10 | * Reset_Handler : Entry of reset handler 11 | * 12 | * It defines following symbols, which code can use without definition: 13 | * __exidx_start 14 | * __exidx_end 15 | * __copy_table_start__ 16 | * __copy_table_end__ 17 | * __zero_table_start__ 18 | * __zero_table_end__ 19 | * __etext 20 | * __data_start__ 21 | * __preinit_array_start 22 | * __preinit_array_end 23 | * __init_array_start 24 | * __init_array_end 25 | * __fini_array_start 26 | * __fini_array_end 27 | * __data_end__ 28 | * __bss_start__ 29 | * __bss_end__ 30 | * __end__ 31 | * end 32 | * __HeapLimit 33 | * __StackLimit 34 | * __StackTop 35 | * __stack 36 | */ 37 | ENTRY(Reset_Handler) 38 | 39 | SECTIONS 40 | { 41 | .text : 42 | { 43 | KEEP(*(.isr_vector)) 44 | 45 | /* Flash configuration field; woe be to the one who relocates 46 | * this section. Extremem care should be taken when modifying 47 | * this region. 48 | */ 49 | . = 0x400; 50 | KEEP(*(.fcf)) 51 | 52 | *(.text*) 53 | 54 | KEEP(*(.init)) 55 | KEEP(*(.fini)) 56 | 57 | /* .ctors */ 58 | *crtbegin.o(.ctors) 59 | *crtbegin?.o(.ctors) 60 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) 61 | *(SORT(.ctors.*)) 62 | *(.ctors) 63 | 64 | /* .dtors */ 65 | *crtbegin.o(.dtors) 66 | *crtbegin?.o(.dtors) 67 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) 68 | *(SORT(.dtors.*)) 69 | *(.dtors) 70 | 71 | *(.rodata*) 72 | 73 | KEEP(*(.eh_frame*)) 74 | } > FLASH 75 | 76 | .ARM.extab : 77 | { 78 | *(.ARM.extab* .gnu.linkonce.armextab.*) 79 | } > FLASH 80 | 81 | __exidx_start = .; 82 | .ARM.exidx : 83 | { 84 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 85 | } > FLASH 86 | __exidx_end = .; 87 | 88 | __etext = .; 89 | 90 | .data : AT (__etext) 91 | { 92 | __data_start__ = .; 93 | *(vtable) 94 | *(.data*) 95 | 96 | . = ALIGN(4); 97 | /* preinit data */ 98 | PROVIDE_HIDDEN (__preinit_array_start = .); 99 | KEEP(*(.preinit_array)) 100 | PROVIDE_HIDDEN (__preinit_array_end = .); 101 | 102 | . = ALIGN(4); 103 | /* init data */ 104 | PROVIDE_HIDDEN (__init_array_start = .); 105 | KEEP(*(SORT(.init_array.*))) 106 | KEEP(*(.init_array)) 107 | PROVIDE_HIDDEN (__init_array_end = .); 108 | 109 | 110 | . = ALIGN(4); 111 | /* finit data */ 112 | PROVIDE_HIDDEN (__fini_array_start = .); 113 | KEEP(*(SORT(.fini_array.*))) 114 | KEEP(*(.fini_array)) 115 | PROVIDE_HIDDEN (__fini_array_end = .); 116 | 117 | KEEP(*(.jcr*)) 118 | . = ALIGN(4); 119 | /* All data end */ 120 | __data_end__ = .; 121 | 122 | } > RAM 123 | 124 | .bss : 125 | { 126 | . = ALIGN(4); 127 | __bss_start__ = .; 128 | *(.bss*) 129 | *(COMMON) 130 | . = ALIGN(4); 131 | __bss_end__ = .; 132 | } > RAM 133 | 134 | .heap (COPY): 135 | { 136 | __end__ = .; 137 | PROVIDE(end = .); 138 | *(.heap*) 139 | __HeapLimit = .; 140 | } > RAM 141 | 142 | /* .stack_dummy section doesn't contains any symbols. It is only 143 | * used for linker to calculate size of stack sections, and assign 144 | * values to stack symbols later */ 145 | .stack_dummy (COPY): 146 | { 147 | *(.stack*) 148 | } > RAM 149 | 150 | /* Set stack top to end of RAM, and stack limit move down by 151 | * size of stack_dummy section */ 152 | __StackTop = ORIGIN(RAM) + LENGTH(RAM); 153 | __StackLimit = __StackTop - SIZEOF(.stack_dummy); 154 | PROVIDE(__stack = __StackTop); 155 | 156 | /* Check if data + heap + stack exceeds RAM limit */ 157 | ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") 158 | } 159 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-canary/src/main.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: main.c 3 | * 4 | * Copyright (c) 2016 Square, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Author: Ford Peprah 19 | * 20 | * Created: September 28th, 2016 21 | * Modified: September 28th, 2016 22 | *****************************************************************************/ 23 | #include 24 | #include 25 | #define BUFFER_SIZE (40) 26 | #define OVERFLOW_SIZE (BUFFER_SIZE + 8) 27 | #if UINT32_MAX == UINTPTR_MAX 28 | #define STACK_CHK_GUARD 0xe2dee396 29 | #else 30 | #define STACK_CHK_GUARD 0x595e9fbd94fda766 31 | #endif 32 | 33 | uintptr_t __stack_chk_guard = STACK_CHK_GUARD; 34 | 35 | __attribute__((noreturn)) void __stack_chk_fail(void) { 36 | asm("BKPT"); 37 | abort(); 38 | } 39 | 40 | int function_that_overflows(void) { 41 | volatile unsigned int data[BUFFER_SIZE]; 42 | volatile unsigned int i = 0; 43 | for (i = 0; i < OVERFLOW_SIZE; i++) { 44 | data[i] = i; 45 | } 46 | return data[i - 1]; 47 | } 48 | 49 | int main(void) { 50 | function_that_overflows(); 51 | 52 | while (1); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-etm/.gdbinit: -------------------------------------------------------------------------------- 1 | target remote :2331 2 | monitor speed auto 3 | monitor endian little 4 | monitor flash device $DEVICE 5 | monitor flash breakpoints = 1 6 | monitor semihosting enable 7 | monitor semihosting IOClient = 2 8 | monitor reset 6 9 | load build/firmware.elf 10 | file build/firmware.elf 11 | monitor reset 6 12 | monitor reset 6 13 | 14 | # monitor SWO EnableTarget 15 | # If 0 is given for the CPU and SWO frequency, it is determined automatically. 16 | monitor SWO EnableTarget 20958600 0 0xFFFFFFFF 0 17 | 18 | # Continue 19 | c 20 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-etm/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Square, Inc. 2 | 3 | # Commands 4 | TARGET_PREFIX = arm-none-eabi- 5 | AS = $(TARGET_PREFIX)as 6 | LD = $(TARGET_PREFIX)ld 7 | CC = $(TARGET_PREFIX)gcc 8 | CPP = $(TARGET_PREFIX)g++ 9 | OBJCOPY = $(TARGET_PREFIX)objcopy 10 | CP = cp 11 | MKDIR = mkdir 12 | 13 | # Directories 14 | BUILDDIR = build 15 | ASMDIR = asm 16 | SRCDIR = src 17 | 18 | # Flags 19 | ASFLAGS = -g -mthumb -mcpu=cortex-m4 20 | LDFLAGS = -T$(ASMDIR)/gcc.ld --specs=nosys.specs -mthumb -mcpu=cortex-m4 -nostartfiles 21 | CCFLAGS = -S -Wall -O0 -mcpu=cortex-m4 -mthumb -g 22 | 23 | # Output Files 24 | BIN = $(BUILDDIR)/firmware.bin 25 | ELF = $(BUILDDIR)/firmware.elf 26 | ASOURCES = $(notdir $(wildcard $(ASMDIR)/*.s)) 27 | CSOURCES = $(notdir $(wildcard $(SRCDIR)/*.c)) 28 | OBJS = $(addprefix $(BUILDDIR)/,$(ASOURCES:.s=.o)) $(addprefix $(BUILDDIR)/,$(CSOURCES:.c=.o)) 29 | 30 | .PHONY: all clean 31 | 32 | all: $(BIN) 33 | 34 | clean: 35 | -$(RM) -rf $(BUILDDIR) 36 | 37 | $(ELF): $(OBJS) 38 | @$(MKDIR) -p $(BUILDDIR) 39 | $(CC) $(LDFLAGS) -o $@ $^ 40 | 41 | $(BUILDDIR)/%.o: $(BUILDDIR)/%.s 42 | @$(MKDIR) -p $(BUILDDIR) 43 | $(AS) $(ASFLAGS) -o $@ $< 44 | 45 | $(BUILDDIR)/%.s: $(ASMDIR)/%.s 46 | @$(MKDIR) -p $(BUILDDIR) 47 | $(CP) $< $(BUILDDIR)/ 48 | 49 | $(BUILDDIR)/%.s: $(SRCDIR)/%.c 50 | @$(MKDIR) -p $(BUILDDIR) 51 | $(CC) $(CCFLAGS) -o $@ $< 52 | 53 | %.bin: %.elf 54 | $(OBJCOPY) -O binary $< $@ 55 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-etm/README.md: -------------------------------------------------------------------------------- 1 | # K21 ETM 2 | 3 | This firmware build demonstrates using Embedded Trace Macrocell on K21. 4 | This firmware is known to work on the `K21F120M` evaluation board. 5 | 6 | ## Building the Firmware 7 | 8 | To build the firmware, run `make` from within the directory. This will create 9 | a build directory containing the binary files. 10 | 11 | ## Using ETM 12 | 13 | To inspect the instruction trace, load the .elf file into SEGGER Ozone. The 14 | instruction trace will be populated at each breakpoint, after the ETM module is 15 | initialized in firmware. 16 | Reference: https://www.segger.com/ozone-trace-tutorial.html 17 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-etm/asm/gcc.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K 4 | RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 64K 5 | } 6 | 7 | /* Linker script to place sections and symbol values. Should be used together 8 | * with other linker script that defines memory regions FLASH and RAM. 9 | * It references following symbols, which must be defined in code: 10 | * Reset_Handler : Entry of reset handler 11 | * 12 | * It defines following symbols, which code can use without definition: 13 | * __exidx_start 14 | * __exidx_end 15 | * __copy_table_start__ 16 | * __copy_table_end__ 17 | * __zero_table_start__ 18 | * __zero_table_end__ 19 | * __etext 20 | * __data_start__ 21 | * __preinit_array_start 22 | * __preinit_array_end 23 | * __init_array_start 24 | * __init_array_end 25 | * __fini_array_start 26 | * __fini_array_end 27 | * __data_end__ 28 | * __bss_start__ 29 | * __bss_end__ 30 | * __end__ 31 | * end 32 | * __HeapLimit 33 | * __StackLimit 34 | * __StackTop 35 | * __stack 36 | */ 37 | ENTRY(Reset_Handler) 38 | 39 | SECTIONS 40 | { 41 | .text : 42 | { 43 | KEEP(*(.isr_vector)) 44 | 45 | /* Flash configuration field; woe be to the one who relocates 46 | * this section. Extremem care should be taken when modifying 47 | * this region. 48 | */ 49 | . = 0x400; 50 | KEEP(*(.fcf)) 51 | 52 | *(.text*) 53 | 54 | KEEP(*(.init)) 55 | KEEP(*(.fini)) 56 | 57 | /* .ctors */ 58 | *crtbegin.o(.ctors) 59 | *crtbegin?.o(.ctors) 60 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) 61 | *(SORT(.ctors.*)) 62 | *(.ctors) 63 | 64 | /* .dtors */ 65 | *crtbegin.o(.dtors) 66 | *crtbegin?.o(.dtors) 67 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) 68 | *(SORT(.dtors.*)) 69 | *(.dtors) 70 | 71 | *(.rodata*) 72 | 73 | KEEP(*(.eh_frame*)) 74 | } > FLASH 75 | 76 | .ARM.extab : 77 | { 78 | *(.ARM.extab* .gnu.linkonce.armextab.*) 79 | } > FLASH 80 | 81 | __exidx_start = .; 82 | .ARM.exidx : 83 | { 84 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 85 | } > FLASH 86 | __exidx_end = .; 87 | 88 | __etext = .; 89 | 90 | .data : AT (__etext) 91 | { 92 | __data_start__ = .; 93 | *(vtable) 94 | *(.data*) 95 | 96 | . = ALIGN(4); 97 | /* preinit data */ 98 | PROVIDE_HIDDEN (__preinit_array_start = .); 99 | KEEP(*(.preinit_array)) 100 | PROVIDE_HIDDEN (__preinit_array_end = .); 101 | 102 | . = ALIGN(4); 103 | /* init data */ 104 | PROVIDE_HIDDEN (__init_array_start = .); 105 | KEEP(*(SORT(.init_array.*))) 106 | KEEP(*(.init_array)) 107 | PROVIDE_HIDDEN (__init_array_end = .); 108 | 109 | 110 | . = ALIGN(4); 111 | /* finit data */ 112 | PROVIDE_HIDDEN (__fini_array_start = .); 113 | KEEP(*(SORT(.fini_array.*))) 114 | KEEP(*(.fini_array)) 115 | PROVIDE_HIDDEN (__fini_array_end = .); 116 | 117 | KEEP(*(.jcr*)) 118 | . = ALIGN(4); 119 | /* All data end */ 120 | __data_end__ = .; 121 | 122 | } > RAM 123 | 124 | .bss : 125 | { 126 | . = ALIGN(4); 127 | __bss_start__ = .; 128 | *(.bss*) 129 | *(COMMON) 130 | . = ALIGN(4); 131 | __bss_end__ = .; 132 | } > RAM 133 | 134 | .heap (COPY): 135 | { 136 | __end__ = .; 137 | PROVIDE(end = .); 138 | *(.heap*) 139 | __HeapLimit = .; 140 | } > RAM 141 | 142 | /* .stack_dummy section doesn't contains any symbols. It is only 143 | * used for linker to calculate size of stack sections, and assign 144 | * values to stack symbols later */ 145 | .stack_dummy (COPY): 146 | { 147 | *(.stack*) 148 | } > RAM 149 | 150 | /* Set stack top to end of RAM, and stack limit move down by 151 | * size of stack_dummy section */ 152 | __StackTop = ORIGIN(RAM) + LENGTH(RAM); 153 | __StackLimit = __StackTop - SIZEOF(.stack_dummy); 154 | PROVIDE(__stack = __StackTop); 155 | 156 | /* Check if data + heap + stack exceeds RAM limit */ 157 | ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") 158 | } 159 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-etm/src/etm.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: etm.c 3 | * 4 | * Copyright (c) 2017 Square, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Author: Ford Peprah 19 | * 20 | * Created: March 22nd, 2017 21 | * Modified: March 22nd, 2017 22 | *****************************************************************************/ 23 | 24 | #define ETM_LAR (*((volatile unsigned *)0xE0041FB0)) 25 | #define ETM_CR (*((volatile unsigned *)0xE0041000)) 26 | #define ETF_FCR (*((volatile unsigned *)0xE0043000u)) 27 | #define MCM_ETBCC (*((volatile unsigned *)0xE0080014u)) 28 | #define SIM_SOPT2 (*((volatile unsigned *)0x40048004u)) 29 | #define SIM_SCGC5 (*((volatile unsigned *)0x40048004u)) 30 | 31 | #define ETM_LAR_UNLOCK 0xC5ACCE55 32 | #define ETF_ETM_ENABLE 0x1u 33 | #define ETMCR_POWER_DOWN_MASK 0x1u 34 | #define MCM_ETBCC_ETDIS_MASK 0x10u 35 | 36 | #define SIM_SOPT2_TRACECLKSEL_MASK 0x1000u 37 | 38 | #define PORT_PCR_REG(base,index) (base[index]) 39 | #define PORTE_BASE_PTR ((volatile unsigned *)0x4004D000u) 40 | #define PORTE_PCR0 PORT_PCR_REG(PORTE_BASE_PTR,0) 41 | #define PORTE_PCR1 PORT_PCR_REG(PORTE_BASE_PTR,1) 42 | #define PORTE_PCR2 PORT_PCR_REG(PORTE_BASE_PTR,2) 43 | #define PORTE_PCR3 PORT_PCR_REG(PORTE_BASE_PTR,3) 44 | #define PORTE_PCR4 PORT_PCR_REG(PORTE_BASE_PTR,4) 45 | 46 | #define PORT_PCR_DSE_ENABLE (1<<6) /* Port Configuration Register, Drive Strength Enable (DSE) bit */ 47 | #define PORT_PCR_MUX_ALTERNATE_5 (5<<8) /* Port Configuration Register, Alternate 5 function (mux as trace pin) */ 48 | #define PORT_PCR_CONFIG_FOR_TRACE (PORT_PCR_DSE_ENABLE|PORT_PCR_MUX_ALTERNATE_5) /* for trace, mux it with function 5 and high drive strength */ 49 | #define PORTE_CLOCK_GATE (1<<13) 50 | 51 | void etm_configure_gpio(void) { 52 | /* check and enable clocking of PORTE */ 53 | SIM_SCGC5 |= PORTE_CLOCK_GATE; 54 | SIM_SOPT2 |= SIM_SOPT2_TRACECLKSEL_MASK; /* Debug trace clock select = Core/system clock */ 55 | /* Trace data (PTE1-4) and clock pin (PTE0), high drive strength */ 56 | PORTE_PCR0 = PORT_PCR_CONFIG_FOR_TRACE; /* PTE0, PORTE_PCR0 at 0x4004D000, trace clock pin, high drive strength */ 57 | PORTE_PCR1 = PORT_PCR_CONFIG_FOR_TRACE; /* PTE1, PORTE_PCR1 at 0x4004D004, trace data pin, high drive strength */ 58 | PORTE_PCR2 = PORT_PCR_CONFIG_FOR_TRACE; /* PTE2, PORTE_PCR3 at 0x4004D008, trace data pin, high drive strength */ 59 | PORTE_PCR3 = PORT_PCR_CONFIG_FOR_TRACE; /* PTE3, PORTE_PCR3 at 0x4004D00C, trace data pin, high drive strength */ 60 | PORTE_PCR4 = PORT_PCR_CONFIG_FOR_TRACE; /* PTE4, PORTE_PCR4 at 0x4004D010, trace data pin, high drive strength */ 61 | } 62 | 63 | void etm_configure_registers(void) { 64 | // A privileged write of `0xC5ACCE55` enables write access to the ETM 65 | // Control Register. 66 | ETM_LAR = ETM_LAR_UNLOCK; 67 | 68 | // The Power Down bit in the ETM control register must be cleared in order 69 | // to enable ETM. 70 | ETM_CR &= ~(ETMCR_POWER_DOWN_MASK); 71 | 72 | /* Set up Embedded Trace FIFO to enable the ETM path. */ 73 | ETF_FCR |= ETF_ETM_ENABLE; 74 | 75 | // Enable the signal path from ETM to TPIU 76 | // MCM is Kinetis-specific, not ARM. 77 | MCM_ETBCC &= (~MCM_ETBCC_ETDIS_MASK); 78 | } 79 | 80 | void etm_init(void) { 81 | etm_configure_gpio(); 82 | etm_configure_registers(); 83 | } 84 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-etm/src/etm.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: etm.h 3 | * 4 | * Copyright (c) 2017 Square, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Author: Ford Peprah 19 | * 20 | * Created: March 22nd, 2017 21 | * Modified: March 22nd, 2017 22 | *****************************************************************************/ 23 | #ifndef __ETM_H__ 24 | #define __ETM_H__ 25 | 26 | #define ETM_Init etm_init 27 | 28 | /** 29 | * etm_init: 30 | * Performs initialization sequence for Embedded Trace Macrocell (ETM). 31 | * 32 | * This is a blocking call. 33 | */ 34 | void etm_init(void); 35 | 36 | #endif /* __ETM_H__ */ 37 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-etm/src/main.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: main.c 3 | * 4 | * Copyright (c) 2017 Square, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Author: Ford Peprah 19 | * 20 | * Created: March 22nd, 2017 21 | * Modified: March 22nd, 2017 22 | *****************************************************************************/ 23 | #include "etm.h" 24 | #include "swo.h" 25 | #define CPU_SPEED 21004050 // 21 MHz 26 | #define SWO_SPEED 3000000 // 3 MHz 27 | #define PORT_MASK 0x1 // Enable one port. 28 | #define FOREVER for(;;) 29 | 30 | void test_func(void) { 31 | static volatile int counter = 0; 32 | counter++; 33 | } 34 | 35 | int main(void) { 36 | int counter = 0; 37 | const char *string = "You must construct additional pylons."; 38 | SWO_Init(CPU_SPEED, SWO_SPEED, PORT_MASK); 39 | ETM_Init(); 40 | 41 | FOREVER { 42 | counter++; 43 | SWO_Puts(0, string); 44 | if (counter % 3) { 45 | test_func(); 46 | } 47 | } 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-etm/src/swo.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: swo.c 3 | * 4 | * Copyright (c) 2016 Square, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Author: Ford Peprah 19 | * 20 | * Created: September 14th, 2016 21 | * Modified: September 14th, 2016 22 | *****************************************************************************/ 23 | #include "swo.h" 24 | 25 | /** 26 | * Debug Exception and Monitor Control Register (DEMCR) 27 | * 28 | * This is a read/write register used for vector catching and debug monitor 29 | * control. 30 | */ 31 | #define DEMCR (*((volatile unsigned *)0xE000EDFC)) 32 | #define TRCENA (1 << 24) 33 | 34 | /** 35 | * Selected Pin Protocol Register (TPIU_SPPR) 36 | * 37 | * This is a read/write register that is reset with a value of `0x1`, which 38 | * indicates manchester encoding. This is a trace point unit register which is 39 | * used to select which protocol to use for trace output. 40 | */ 41 | #define TPIU_SPPR (*((volatile unsigned *)0xE00400F0)) 42 | #define MANCHESTER 0x00000001 43 | #define NRZ 0x00000002 44 | 45 | /** 46 | * Asynchronous Clock Prescaler Register (ACPR) 47 | * 48 | * This is a read/write register that is reset with a value of `0`. It is used 49 | * to set a prescaler in order to scale the baud rate of the asynchronous 50 | * output. 51 | */ 52 | #define TPIU_ACPR (*((volatile unsigned *)0xE0040010)) 53 | 54 | /** 55 | * Data Watchpoint and Trace Control Register (DWT_CTRL) 56 | * 57 | * This is a read/write register that has various reset values. This register 58 | * is used to provide information about the data watchpoint. 59 | */ 60 | #define DWT_CTRL (*((volatile unsigned *)0xE0001000)) 61 | 62 | /** 63 | * Trace Port Interface Unit Formatter and Flush Control Register (TPIU_FFCR) 64 | * 65 | * This is a read/write register that is reset with a value of `0x102`. This 66 | * register is used to trigger events, enable and configure formatting, and 67 | * generate flush events. 68 | */ 69 | #define TPIU_FFCR (*((volatile unsigned *)0xE0040304)) 70 | 71 | #define ITM_Port8(n) (*((volatile unsigned char *)(ITM_BASEADDR + 4 * n))) 72 | #define ITM_Port16(n) (*((volatile unsigned short *)(ITM_BASEADDR + 4 * n))) 73 | #define ITM_Port32(n) (*((volatile unsigned int *)(ITM_BASEADDR + 4 * n))) 74 | 75 | void swo_init(unsigned int cpu_speed, unsigned int swo_speed, unsigned int port_mask) { 76 | // Bit [24] Read/write TRCENA. Must be set to `1` to enable use of the 77 | // trace and debug blocks: Data Watchpoint and Trace (DWT), Instrumentation 78 | // Trace Macrocell (ITM), Embedded Trace Macrocell (ETM), and Trace Port 79 | // Interface Unit (TPIU). 80 | DEMCR |= TRCENA; 81 | 82 | // A privileged write of `0xC5ACCE55` enables more write access to Control 83 | // Register `0xE00::0xFFC`. An invalid write removes write access. 84 | ITM_LAR = 0xC5ACCE55; 85 | 86 | // Bits [1:0] read/write select the protocol to use. `0` and `3` are 87 | // reserved, while `01` is SWO using Manchester encoding, and `10` is SWO 88 | // using NRZ encoding. 89 | TPIU_SPPR = NRZ; 90 | 91 | // Prescaler value is computed as the quotient between the cpu speed and 92 | // the SWO speed. We subtract one, as the prescaler is ultimately computed 93 | // by adding `1` to the value written to the ACPR. 94 | unsigned int prescaler = (cpu_speed / swo_speed) - 1; 95 | TPIU_ACPR = prescaler; 96 | 97 | // Bits [3:0] specify which stimulus ports can be accessed and describe the 98 | // ranges from `31-24`, `23-16`, `15-8`, and `7-0` respectively. By 99 | // default, we want to allow access to all. Note that this is different 100 | // from actually enabling writing to them. 101 | ITM_TPR = 0x00000000; 102 | 103 | // DWT Control Register. We enable the exception trace and exception 104 | // overhead. 105 | DWT_CTRL |= 0x400003FE; 106 | 107 | // Bit [0] enables ITM. Bits[4:2] enable SWV behaviour, DWT stimulus, and 108 | // sync packets for TPIU respectively. Bit `16` sets the ATB ID for the 109 | // Coresight System (we set this to `1`). 110 | ITM_TCR = 0x0001001F; 111 | 112 | // Bit [9] indicates that a trigger should be fired on a trigger event. 113 | // This will allow tracing of trigger events. The rest of the events are 114 | // disabled. 115 | TPIU_FFCR = 0x00000100; 116 | 117 | // We set the user specified port mask to enable tracing on the specified 118 | // ITM stimulus ports. One bit per stimulus port. 119 | ITM_TER = port_mask; 120 | } 121 | 122 | int swo_putchar(stimulus_port_t port, char ch) { 123 | // Check that tracing is enabled on the debug monitor. 124 | if ((DEMCR & TRCENA) == 0) { 125 | return 0; 126 | } 127 | 128 | // Check that ITM is enabled. 129 | if ((ITM_TCR & 1) == 0) { 130 | return 0; 131 | } 132 | 133 | // Check that tracing is enabled for the given port. 134 | if ((ITM_TER & (1 << port)) == 0) { 135 | return 0; 136 | } 137 | 138 | while (ITM_Port8(port) == 0); 139 | 140 | ITM_Port8(port) = (int)ch; 141 | 142 | return ch; 143 | } 144 | 145 | void swo_puts(stimulus_port_t port, const char *string) { 146 | while (*string) { 147 | swo_putchar(port, *string++); 148 | } 149 | } 150 | 151 | #ifdef OVERRIDE_PRINTF 152 | 153 | int putchar(int ch) { 154 | return swo_putchar(STIMULUS_PORT_0, ch); 155 | } 156 | 157 | int fputc(int ch, FILE *f) { 158 | if (f) { 159 | return swo_putchar(f->port, ch); 160 | } 161 | return swo_putchar(STIMULUS_PORT_0, ch); 162 | } 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-etm/src/swo.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: swo.h 3 | * 4 | * Copyright (c) 2016 Square, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Author: Ford Peprah 19 | * 20 | * Created: September 14th, 2016 21 | * Modified: September 14th, 2016 22 | *****************************************************************************/ 23 | #ifndef __SWO_H__ 24 | #define __SWO_H__ 25 | 26 | #define SWO_Init swo_init 27 | #define SWO_Putchar swo_putchar 28 | #define SWO_Puts swo_puts 29 | 30 | /** 31 | * ITM Stimulus Ports 32 | * 33 | * There are 32 stimulus ports (indexed `0 - 31`). Each port has its own 34 | * address which is calculated by multiplying the index by `4` and adding it to 35 | * the ITM base address. 36 | * 37 | * Reading from any of these ports will return the FIFO status in the last bit. 38 | * If the FIFO status is `0`, it is full, while `1` is not full. 39 | */ 40 | #define ITM_BASEADDR 0xE0000000 41 | 42 | /** 43 | * ITM Registers 44 | * 45 | * ITM Trace Enable Register (ITM_TER), ITM Trace Privilege Register (ITM_TPR), 46 | * ITM Trace Control Register (ITM_TCR), ITM Lock Access Register (ITM_LAR), 47 | * and the ITM Lock Status Register (ITM_LSR). 48 | */ 49 | #define ITM_TER (*((volatile unsigned *)0xE0000E00)) 50 | #define ITM_TPR (*((volatile unsigned *)0xE0000E40)) 51 | #define ITM_TCR (*((volatile unsigned *)0xE0000E80)) 52 | #define ITM_LAR (*((volatile unsigned *)0xE0000FB0)) 53 | #define ITM_LSR (*((volatile unsigned *)0xE0000FB4)) 54 | 55 | /** 56 | * Stimulus Port Indices 57 | */ 58 | typedef enum stimulus_port_t { 59 | STIMULUS_PORT_0 = 0, 60 | STIMULUS_PORT_1, 61 | STIMULUS_PORT_2, 62 | STIMULUS_PORT_3, 63 | STIMULUS_PORT_4, 64 | STIMULUS_PORT_5, 65 | STIMULUS_PORT_6, 66 | STIMULUS_PORT_7, 67 | STIMULUS_PORT_8, 68 | STIMULUS_PORT_9, 69 | STIMULUS_PORT_10, 70 | STIMULUS_PORT_11, 71 | STIMULUS_PORT_12, 72 | STIMULUS_PORT_13, 73 | STIMULUS_PORT_14, 74 | STIMULUS_PORT_15, 75 | STIMULUS_PORT_16, 76 | STIMULUS_PORT_17, 77 | STIMULUS_PORT_18, 78 | STIMULUS_PORT_19, 79 | STIMULUS_PORT_20, 80 | STIMULUS_PORT_21, 81 | STIMULUS_PORT_22, 82 | STIMULUS_PORT_23, 83 | STIMULUS_PORT_24, 84 | STIMULUS_PORT_25, 85 | STIMULUS_PORT_26, 86 | STIMULUS_PORT_27, 87 | STIMULUS_PORT_28, 88 | STIMULUS_PORT_29, 89 | STIMULUS_PORT_30, 90 | STIMULUS_PORT_31, 91 | NUM_STIMULUS_PORTS 92 | } stimulus_port_t; 93 | 94 | #ifdef OVERRIDE_PRINTF 95 | 96 | struct __FILE { 97 | stimulus_port_t port; 98 | }; 99 | 100 | typedef struct __FILE FILE; 101 | 102 | #endif 103 | 104 | /** 105 | * swo_init: 106 | * Performs necessary setup in order to send data over SWO using the ITM. 107 | * 108 | * This is a blocking call. 109 | */ 110 | void swo_init(unsigned int cpu_speed, unsigned int swo_speed, unsigned int port_mask); 111 | 112 | /** 113 | * swo_putchar: 114 | * Puts a character to the given stimulus port. 115 | * 116 | * Returns the character written on success, otherwise `0`. 117 | * 118 | * This is a blocking call. 119 | */ 120 | int swo_putchar(stimulus_port_t port, char ch); 121 | 122 | /** 123 | * swo_puts: 124 | * Puts a string to the given stimulus port one character at a time. 125 | * 126 | * This is a blocking call. 127 | */ 128 | void swo_puts(stimulus_port_t port, const char *string); 129 | 130 | #endif /* __SWO_H__ */ 131 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-loop/.gdbinit: -------------------------------------------------------------------------------- 1 | target remote :2331 2 | monitor speed auto 3 | monitor endian little 4 | monitor flash device $DEVICE 5 | monitor flash breakpoints = 1 6 | monitor semihosting enable 7 | monitor semihosting IOClient = 2 8 | monitor reset 9 | load build/firmware.elf 10 | file build/firmware.elf 11 | monitor reset 12 | monitor reset 13 | c 14 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-loop/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Square, Inc. 2 | 3 | # Commands 4 | TARGET_PREFIX = arm-none-eabi- 5 | AS = $(TARGET_PREFIX)as 6 | LD = $(TARGET_PREFIX)ld 7 | CC = $(TARGET_PREFIX)gcc 8 | CPP = $(TARGET_PREFIX)g++ 9 | OBJCOPY = $(TARGET_PREFIX)objcopy 10 | CP = cp 11 | MKDIR = mkdir 12 | 13 | # Directories 14 | BUILDDIR = build 15 | ASMDIR = asm 16 | SRCDIR = src 17 | 18 | # Flags 19 | ASFLAGS = -g -mthumb -mcpu=cortex-m4 20 | LDFLAGS = -T$(ASMDIR)/gcc.ld --specs=nosys.specs -mthumb -mcpu=cortex-m4 -nostartfiles 21 | CCFLAGS = -S -Wall -O0 -mcpu=cortex-m4 -mthumb -g 22 | 23 | # Output Files 24 | BIN = $(BUILDDIR)/firmware.bin 25 | ELF = $(BUILDDIR)/firmware.elf 26 | ASOURCES = $(notdir $(wildcard $(ASMDIR)/*.s)) 27 | CSOURCES = $(notdir $(wildcard $(SRCDIR)/*.c)) 28 | OBJS = $(addprefix $(BUILDDIR)/,$(ASOURCES:.s=.o)) $(addprefix $(BUILDDIR)/,$(CSOURCES:.c=.o)) 29 | 30 | .PHONY: all clean 31 | 32 | all: $(BIN) 33 | 34 | clean: 35 | -$(RM) -rf $(BUILDDIR) 36 | 37 | $(ELF): $(OBJS) 38 | @$(MKDIR) -p $(BUILDDIR) 39 | $(CC) $(LDFLAGS) -o $@ $^ 40 | 41 | $(BUILDDIR)/%.o: $(BUILDDIR)/%.s 42 | @$(MKDIR) -p $(BUILDDIR) 43 | $(AS) $(ASFLAGS) -o $@ $< 44 | 45 | $(BUILDDIR)/%.s: $(ASMDIR)/%.s 46 | @$(MKDIR) -p $(BUILDDIR) 47 | $(CP) $< $(BUILDDIR)/ 48 | 49 | $(BUILDDIR)/%.s: $(SRCDIR)/%.c 50 | @$(MKDIR) -p $(BUILDDIR) 51 | $(CC) $(CCFLAGS) -o $@ $< 52 | 53 | %.bin: %.elf 54 | $(OBJCOPY) -O binary $< $@ 55 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-loop/README.md: -------------------------------------------------------------------------------- 1 | # K21 Loop 2 | 3 | This build build implements a simple polling loop. 4 | 5 | ## Bulding the Firmware 6 | 7 | To build the firmware, run `make` from within the directory. This will create 8 | a build directory containing the binary files. 9 | 10 | ## Firmware Overview 11 | 12 | This firmware does the following things on boot: 13 | 14 | 1. Stops the watchdog timer. 15 | 2. Enters a polling loop incrementing a value. 16 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-loop/asm/gcc.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K 4 | RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 64K 5 | } 6 | 7 | /* Linker script to place sections and symbol values. Should be used together 8 | * with other linker script that defines memory regions FLASH and RAM. 9 | * It references following symbols, which must be defined in code: 10 | * Reset_Handler : Entry of reset handler 11 | * 12 | * It defines following symbols, which code can use without definition: 13 | * __exidx_start 14 | * __exidx_end 15 | * __copy_table_start__ 16 | * __copy_table_end__ 17 | * __zero_table_start__ 18 | * __zero_table_end__ 19 | * __etext 20 | * __data_start__ 21 | * __preinit_array_start 22 | * __preinit_array_end 23 | * __init_array_start 24 | * __init_array_end 25 | * __fini_array_start 26 | * __fini_array_end 27 | * __data_end__ 28 | * __bss_start__ 29 | * __bss_end__ 30 | * __end__ 31 | * end 32 | * __HeapLimit 33 | * __StackLimit 34 | * __StackTop 35 | * __stack 36 | */ 37 | ENTRY(Reset_Handler) 38 | 39 | SECTIONS 40 | { 41 | .text : 42 | { 43 | KEEP(*(.isr_vector)) 44 | 45 | /* Flash configuration field; woe be to the one who relocates 46 | * this section. Extremem care should be taken when modifying 47 | * this region. 48 | */ 49 | . = 0x400; 50 | KEEP(*(.fcf)) 51 | 52 | *(.text*) 53 | 54 | KEEP(*(.init)) 55 | KEEP(*(.fini)) 56 | 57 | /* .ctors */ 58 | *crtbegin.o(.ctors) 59 | *crtbegin?.o(.ctors) 60 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) 61 | *(SORT(.ctors.*)) 62 | *(.ctors) 63 | 64 | /* .dtors */ 65 | *crtbegin.o(.dtors) 66 | *crtbegin?.o(.dtors) 67 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) 68 | *(SORT(.dtors.*)) 69 | *(.dtors) 70 | 71 | *(.rodata*) 72 | 73 | KEEP(*(.eh_frame*)) 74 | } > FLASH 75 | 76 | .ARM.extab : 77 | { 78 | *(.ARM.extab* .gnu.linkonce.armextab.*) 79 | } > FLASH 80 | 81 | __exidx_start = .; 82 | .ARM.exidx : 83 | { 84 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 85 | } > FLASH 86 | __exidx_end = .; 87 | 88 | __etext = .; 89 | 90 | .data : AT (__etext) 91 | { 92 | __data_start__ = .; 93 | *(vtable) 94 | *(.data*) 95 | 96 | . = ALIGN(4); 97 | /* preinit data */ 98 | PROVIDE_HIDDEN (__preinit_array_start = .); 99 | KEEP(*(.preinit_array)) 100 | PROVIDE_HIDDEN (__preinit_array_end = .); 101 | 102 | . = ALIGN(4); 103 | /* init data */ 104 | PROVIDE_HIDDEN (__init_array_start = .); 105 | KEEP(*(SORT(.init_array.*))) 106 | KEEP(*(.init_array)) 107 | PROVIDE_HIDDEN (__init_array_end = .); 108 | 109 | 110 | . = ALIGN(4); 111 | /* finit data */ 112 | PROVIDE_HIDDEN (__fini_array_start = .); 113 | KEEP(*(SORT(.fini_array.*))) 114 | KEEP(*(.fini_array)) 115 | PROVIDE_HIDDEN (__fini_array_end = .); 116 | 117 | KEEP(*(.jcr*)) 118 | . = ALIGN(4); 119 | /* All data end */ 120 | __data_end__ = .; 121 | 122 | } > RAM 123 | 124 | .bss : 125 | { 126 | . = ALIGN(4); 127 | __bss_start__ = .; 128 | *(.bss*) 129 | *(COMMON) 130 | . = ALIGN(4); 131 | __bss_end__ = .; 132 | } > RAM 133 | 134 | .heap (COPY): 135 | { 136 | __end__ = .; 137 | PROVIDE(end = .); 138 | *(.heap*) 139 | __HeapLimit = .; 140 | } > RAM 141 | 142 | /* .stack_dummy section doesn't contains any symbols. It is only 143 | * used for linker to calculate size of stack sections, and assign 144 | * values to stack symbols later */ 145 | .stack_dummy (COPY): 146 | { 147 | *(.stack*) 148 | } > RAM 149 | 150 | /* Set stack top to end of RAM, and stack limit move down by 151 | * size of stack_dummy section */ 152 | __StackTop = ORIGIN(RAM) + LENGTH(RAM); 153 | __StackLimit = __StackTop - SIZEOF(.stack_dummy); 154 | PROVIDE(__stack = __StackTop); 155 | 156 | /* Check if data + heap + stack exceeds RAM limit */ 157 | ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") 158 | } 159 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-loop/src/main.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: main.c 3 | * 4 | * Copyright (c) 2016 Square, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Author: Ford Peprah 19 | * 20 | * Created: November 10th, 2016 21 | * Modified: November 10th, 2016 22 | *****************************************************************************/ 23 | #include 24 | #include 25 | #define FOREVER for(;;) 26 | 27 | static unsigned int s_counter = 0; 28 | 29 | static unsigned int increment_counter(void) { 30 | s_counter++; 31 | return s_counter; 32 | } 33 | 34 | int main(void) { 35 | FOREVER { 36 | increment_counter(); 37 | } 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-rtt/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Square, Inc. 2 | 3 | # Commands 4 | TARGET_PREFIX = arm-none-eabi- 5 | AS = $(TARGET_PREFIX)as 6 | LD = $(TARGET_PREFIX)ld 7 | CC = $(TARGET_PREFIX)gcc 8 | CPP = $(TARGET_PREFIX)g++ 9 | OBJCOPY = $(TARGET_PREFIX)objcopy 10 | CP = cp 11 | MKDIR = mkdir 12 | 13 | # Directories 14 | BUILDDIR = build 15 | ASMDIR = asm 16 | SRCDIR = src 17 | VENDDIR = vendor 18 | 19 | # Flags 20 | ASFLAGS = -g -mthumb -mcpu=cortex-m4 21 | LDFLAGS = -T$(ASMDIR)/gcc.ld --specs=nosys.specs -mthumb -mcpu=cortex-m4 -nostartfiles 22 | CCFLAGS = -S -Wall -O0 -mcpu=cortex-m4 -mthumb -g -Ivendor 23 | 24 | # Output Files 25 | BIN = $(BUILDDIR)/firmware.bin 26 | ELF = $(BUILDDIR)/firmware.elf 27 | ASOURCES = $(notdir $(wildcard $(ASMDIR)/*.s)) 28 | CSOURCES = $(notdir $(wildcard $(SRCDIR)/*.c)) $(notdir $(wildcard $(VENDDIR)/*.c)) 29 | OBJS = $(addprefix $(BUILDDIR)/,$(ASOURCES:.s=.o)) $(addprefix $(BUILDDIR)/,$(CSOURCES:.c=.o)) 30 | 31 | .PHONY: all clean 32 | 33 | all: $(BIN) 34 | 35 | clean: 36 | -$(RM) -rf $(BUILDDIR) 37 | 38 | $(ELF): $(OBJS) 39 | @$(MKDIR) -p $(BUILDDIR) 40 | $(CC) $(LDFLAGS) -o $@ $^ 41 | 42 | $(BUILDDIR)/%.o: $(BUILDDIR)/%.s 43 | @$(MKDIR) -p $(BUILDDIR) 44 | $(AS) $(ASFLAGS) -o $@ $< 45 | 46 | $(BUILDDIR)/%.s: $(ASMDIR)/%.s 47 | @$(MKDIR) -p $(BUILDDIR) 48 | $(CP) $< $(BUILDDIR)/ 49 | 50 | $(BUILDDIR)/%.s: $(SRCDIR)/%.c 51 | @$(MKDIR) -p $(BUILDDIR) 52 | $(CC) $(CCFLAGS) -o $@ $< 53 | 54 | $(BUILDDIR)/%.s: $(VENDDIR)/%.c 55 | @$(MKDIR) -p $(BUILDDIR) 56 | $(CC) $(CCFLAGS) -o $@ $< 57 | 58 | %.bin: %.elf 59 | $(OBJCOPY) -O binary $< $@ 60 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-rtt/README.md: -------------------------------------------------------------------------------- 1 | # K21 RTT 2 | 3 | This firmware build demonstrates using Real-Time Transfer (RTT) to send and 4 | receive data on a K21. This firmware is known to work on the `K21F120M` 5 | evaluation board. 6 | 7 | ## Building the Firmware 8 | 9 | To build the firmware, run `make` from within the directory. This will create 10 | a build directory containing the binary files. 11 | 12 | ## Firmware Overview 13 | 14 | This firmware does the following things on boot: 15 | 16 | 1. Initializes the RTT control block. 17 | 2. Sets names for each of the 3 up and down buffers. 18 | 3. Reads a single character from RTT channel 0. 19 | 4. Writes the read character from step three to RTT channel 0. 20 | 5. Repeats again from step 3. 21 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-rtt/asm/gcc.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K 4 | RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 64K 5 | } 6 | 7 | /* Linker script to place sections and symbol values. Should be used together 8 | * with other linker script that defines memory regions FLASH and RAM. 9 | * It references following symbols, which must be defined in code: 10 | * Reset_Handler : Entry of reset handler 11 | * 12 | * It defines following symbols, which code can use without definition: 13 | * __exidx_start 14 | * __exidx_end 15 | * __copy_table_start__ 16 | * __copy_table_end__ 17 | * __zero_table_start__ 18 | * __zero_table_end__ 19 | * __etext 20 | * __data_start__ 21 | * __preinit_array_start 22 | * __preinit_array_end 23 | * __init_array_start 24 | * __init_array_end 25 | * __fini_array_start 26 | * __fini_array_end 27 | * __data_end__ 28 | * __bss_start__ 29 | * __bss_end__ 30 | * __end__ 31 | * end 32 | * __HeapLimit 33 | * __StackLimit 34 | * __StackTop 35 | * __stack 36 | */ 37 | ENTRY(Reset_Handler) 38 | 39 | SECTIONS 40 | { 41 | .text : 42 | { 43 | KEEP(*(.isr_vector)) 44 | 45 | /* Flash configuration field; woe be to the one who relocates 46 | * this section. Extremem care should be taken when modifying 47 | * this region. 48 | */ 49 | . = 0x400; 50 | KEEP(*(.fcf)) 51 | 52 | *(.text*) 53 | 54 | KEEP(*(.init)) 55 | KEEP(*(.fini)) 56 | 57 | /* .ctors */ 58 | *crtbegin.o(.ctors) 59 | *crtbegin?.o(.ctors) 60 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) 61 | *(SORT(.ctors.*)) 62 | *(.ctors) 63 | 64 | /* .dtors */ 65 | *crtbegin.o(.dtors) 66 | *crtbegin?.o(.dtors) 67 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) 68 | *(SORT(.dtors.*)) 69 | *(.dtors) 70 | 71 | *(.rodata*) 72 | 73 | KEEP(*(.eh_frame*)) 74 | } > FLASH 75 | 76 | .ARM.extab : 77 | { 78 | *(.ARM.extab* .gnu.linkonce.armextab.*) 79 | } > FLASH 80 | 81 | __exidx_start = .; 82 | .ARM.exidx : 83 | { 84 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 85 | } > FLASH 86 | __exidx_end = .; 87 | 88 | __etext = .; 89 | 90 | .data : AT (__etext) 91 | { 92 | __data_start__ = .; 93 | *(vtable) 94 | *(.data*) 95 | 96 | . = ALIGN(4); 97 | /* preinit data */ 98 | PROVIDE_HIDDEN (__preinit_array_start = .); 99 | KEEP(*(.preinit_array)) 100 | PROVIDE_HIDDEN (__preinit_array_end = .); 101 | 102 | . = ALIGN(4); 103 | /* init data */ 104 | PROVIDE_HIDDEN (__init_array_start = .); 105 | KEEP(*(SORT(.init_array.*))) 106 | KEEP(*(.init_array)) 107 | PROVIDE_HIDDEN (__init_array_end = .); 108 | 109 | 110 | . = ALIGN(4); 111 | /* finit data */ 112 | PROVIDE_HIDDEN (__fini_array_start = .); 113 | KEEP(*(SORT(.fini_array.*))) 114 | KEEP(*(.fini_array)) 115 | PROVIDE_HIDDEN (__fini_array_end = .); 116 | 117 | KEEP(*(.jcr*)) 118 | . = ALIGN(4); 119 | /* All data end */ 120 | __data_end__ = .; 121 | 122 | } > RAM 123 | 124 | .bss : 125 | { 126 | . = ALIGN(4); 127 | __bss_start__ = .; 128 | *(.bss*) 129 | *(COMMON) 130 | . = ALIGN(4); 131 | __bss_end__ = .; 132 | } > RAM 133 | 134 | .heap (COPY): 135 | { 136 | __end__ = .; 137 | PROVIDE(end = .); 138 | *(.heap*) 139 | __HeapLimit = .; 140 | } > RAM 141 | 142 | /* .stack_dummy section doesn't contains any symbols. It is only 143 | * used for linker to calculate size of stack sections, and assign 144 | * values to stack symbols later */ 145 | .stack_dummy (COPY): 146 | { 147 | *(.stack*) 148 | } > RAM 149 | 150 | /* Set stack top to end of RAM, and stack limit move down by 151 | * size of stack_dummy section */ 152 | __StackTop = ORIGIN(RAM) + LENGTH(RAM); 153 | __StackLimit = __StackTop - SIZEOF(.stack_dummy); 154 | PROVIDE(__stack = __StackTop); 155 | 156 | /* Check if data + heap + stack exceeds RAM limit */ 157 | ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") 158 | } 159 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-rtt/src/main.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: main.c 3 | * 4 | * Copyright (c) 2019 Square, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Author: Ford Peprah 19 | * 20 | * Created: March 12th, 2019 21 | * Modified: March 12th, 2019 22 | *****************************************************************************/ 23 | 24 | #include 25 | 26 | #include 27 | 28 | #define FOREVER for(;;) 29 | 30 | 31 | int main(void) { 32 | char up_buf[2][1024] = {{0}}; 33 | char down_buf[2][1024] = {{0}}; 34 | char input; 35 | 36 | SEGGER_RTT_Init(); 37 | 38 | // Up Buffer 0 is configured at compile-time; can only change name. 39 | SEGGER_RTT_SetNameUpBuffer(0, "PuTTY"); 40 | SEGGER_RTT_ConfigUpBuffer(1, "RUMBA", up_buf[0], sizeof(up_buf[0]), 0x0); 41 | SEGGER_RTT_ConfigUpBuffer(2, "ZOC", up_buf[1], sizeof(up_buf[1]), 0x0); 42 | 43 | // Down Buffer 0 is configured at compile-time; can only change name. 44 | SEGGER_RTT_SetNameDownBuffer(0, "iTerm2"); 45 | SEGGER_RTT_ConfigDownBuffer(1, "ZTerm", down_buf[0], sizeof(down_buf[0]), 0x0); 46 | SEGGER_RTT_ConfigDownBuffer(2, "xterm", down_buf[1], sizeof(down_buf[1]), 0x0); 47 | 48 | FOREVER { 49 | input = (char)0; 50 | while (!input) { 51 | SEGGER_RTT_Read(0, &input, 1); 52 | } 53 | SEGGER_RTT_PutChar(0, input); 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-swd/.gdbinit: -------------------------------------------------------------------------------- 1 | target remote :2331 2 | monitor speed auto 3 | monitor endian little 4 | monitor flash device $DEVICE 5 | monitor flash breakpoints = 1 6 | monitor semihosting enable 7 | monitor semihosting IOClient = 2 8 | monitor reset 6 9 | load build/firmware.elf 10 | file build/firmware.elf 11 | b main 12 | monitor reset 6 13 | monitor reset 6 14 | 15 | # Continue 16 | c 17 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-swd/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Square, Inc. 2 | 3 | # Commands 4 | TARGET_PREFIX = arm-none-eabi- 5 | AS = $(TARGET_PREFIX)as 6 | LD = $(TARGET_PREFIX)ld 7 | CC = $(TARGET_PREFIX)gcc 8 | CPP = $(TARGET_PREFIX)g++ 9 | OBJCOPY = $(TARGET_PREFIX)objcopy 10 | CP = cp 11 | MKDIR = mkdir 12 | 13 | # Directories 14 | BUILDDIR = build 15 | ASMDIR = asm 16 | SRCDIR = src 17 | 18 | # Flags 19 | ASFLAGS = -g -mthumb -mcpu=cortex-m4 20 | LDFLAGS = -T$(ASMDIR)/gcc.ld --specs=nosys.specs -mthumb -mcpu=cortex-m4 -nostartfiles 21 | CCFLAGS = -S -Wall -O0 -mcpu=cortex-m4 -mthumb -g 22 | 23 | # Output Files 24 | BIN = $(BUILDDIR)/firmware.bin 25 | ELF = $(BUILDDIR)/firmware.elf 26 | ASOURCES = $(notdir $(wildcard $(ASMDIR)/*.s)) 27 | CSOURCES = $(notdir $(wildcard $(SRCDIR)/*.c)) 28 | OBJS = $(addprefix $(BUILDDIR)/,$(ASOURCES:.s=.o)) $(addprefix $(BUILDDIR)/,$(CSOURCES:.c=.o)) 29 | 30 | .PHONY: all clean 31 | 32 | all: $(BIN) 33 | 34 | clean: 35 | -$(RM) -rf $(BUILDDIR) 36 | 37 | $(ELF): $(OBJS) 38 | @$(MKDIR) -p $(BUILDDIR) 39 | $(CC) $(LDFLAGS) -o $@ $^ 40 | 41 | $(BUILDDIR)/%.o: $(BUILDDIR)/%.s 42 | @$(MKDIR) -p $(BUILDDIR) 43 | $(AS) $(ASFLAGS) -o $@ $< 44 | 45 | $(BUILDDIR)/%.s: $(ASMDIR)/%.s 46 | @$(MKDIR) -p $(BUILDDIR) 47 | $(CP) $< $(BUILDDIR)/ 48 | 49 | $(BUILDDIR)/%.s: $(SRCDIR)/%.c 50 | @$(MKDIR) -p $(BUILDDIR) 51 | $(CC) $(CCFLAGS) -o $@ $< 52 | 53 | %.bin: %.elf 54 | $(OBJCOPY) -O binary $< $@ 55 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-swd/README.md: -------------------------------------------------------------------------------- 1 | # K21 Serial Wire Debug 2 | 3 | This firmware build demonstrates semihosting and serial wire debug. If the 4 | firmware is successful, we should see a single line printed over serial wire 5 | debug. This firmware is known to work on the `K21F120M` and `K21D50M` 6 | evaluation boards. 7 | 8 | ## Bulding the Firmware 9 | 10 | To build the firmware, run `make` from within the directory. This will create 11 | a build directory containing the binary files. 12 | 13 | ## Firmware Overview 14 | 15 | This firmware does the following things on boot: 16 | 17 | 1. Stops the watchdog timer. 18 | 2. Calls `printf()` to write a message. 19 | 3. Sits in a while-loop forever. 20 | 21 | This behaviour has the effect of triggering a `BKPT` instruction in order to 22 | send a `SYS_WRITE` command for the debugger to grab the contents of the write. 23 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-swd/asm/gcc.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K 4 | RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 64K 5 | } 6 | 7 | /* Linker script to place sections and symbol values. Should be used together 8 | * with other linker script that defines memory regions FLASH and RAM. 9 | * It references following symbols, which must be defined in code: 10 | * Reset_Handler : Entry of reset handler 11 | * 12 | * It defines following symbols, which code can use without definition: 13 | * __exidx_start 14 | * __exidx_end 15 | * __copy_table_start__ 16 | * __copy_table_end__ 17 | * __zero_table_start__ 18 | * __zero_table_end__ 19 | * __etext 20 | * __data_start__ 21 | * __preinit_array_start 22 | * __preinit_array_end 23 | * __init_array_start 24 | * __init_array_end 25 | * __fini_array_start 26 | * __fini_array_end 27 | * __data_end__ 28 | * __bss_start__ 29 | * __bss_end__ 30 | * __end__ 31 | * end 32 | * __HeapLimit 33 | * __StackLimit 34 | * __StackTop 35 | * __stack 36 | */ 37 | ENTRY(Reset_Handler) 38 | 39 | SECTIONS 40 | { 41 | .text : 42 | { 43 | KEEP(*(.isr_vector)) 44 | 45 | /* Flash configuration field; woe be to the one who relocates 46 | * this section. Extremem care should be taken when modifying 47 | * this region. 48 | */ 49 | . = 0x400; 50 | KEEP(*(.fcf)) 51 | 52 | *(.text*) 53 | 54 | KEEP(*(.init)) 55 | KEEP(*(.fini)) 56 | 57 | /* .ctors */ 58 | *crtbegin.o(.ctors) 59 | *crtbegin?.o(.ctors) 60 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) 61 | *(SORT(.ctors.*)) 62 | *(.ctors) 63 | 64 | /* .dtors */ 65 | *crtbegin.o(.dtors) 66 | *crtbegin?.o(.dtors) 67 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) 68 | *(SORT(.dtors.*)) 69 | *(.dtors) 70 | 71 | *(.rodata*) 72 | 73 | KEEP(*(.eh_frame*)) 74 | } > FLASH 75 | 76 | .ARM.extab : 77 | { 78 | *(.ARM.extab* .gnu.linkonce.armextab.*) 79 | } > FLASH 80 | 81 | __exidx_start = .; 82 | .ARM.exidx : 83 | { 84 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 85 | } > FLASH 86 | __exidx_end = .; 87 | 88 | __etext = .; 89 | 90 | .data : AT (__etext) 91 | { 92 | __data_start__ = .; 93 | *(vtable) 94 | *(.data*) 95 | 96 | . = ALIGN(4); 97 | /* preinit data */ 98 | PROVIDE_HIDDEN (__preinit_array_start = .); 99 | KEEP(*(.preinit_array)) 100 | PROVIDE_HIDDEN (__preinit_array_end = .); 101 | 102 | . = ALIGN(4); 103 | /* init data */ 104 | PROVIDE_HIDDEN (__init_array_start = .); 105 | KEEP(*(SORT(.init_array.*))) 106 | KEEP(*(.init_array)) 107 | PROVIDE_HIDDEN (__init_array_end = .); 108 | 109 | 110 | . = ALIGN(4); 111 | /* finit data */ 112 | PROVIDE_HIDDEN (__fini_array_start = .); 113 | KEEP(*(SORT(.fini_array.*))) 114 | KEEP(*(.fini_array)) 115 | PROVIDE_HIDDEN (__fini_array_end = .); 116 | 117 | KEEP(*(.jcr*)) 118 | . = ALIGN(4); 119 | /* All data end */ 120 | __data_end__ = .; 121 | 122 | } > RAM 123 | 124 | .bss : 125 | { 126 | . = ALIGN(4); 127 | __bss_start__ = .; 128 | *(.bss*) 129 | *(COMMON) 130 | . = ALIGN(4); 131 | __bss_end__ = .; 132 | } > RAM 133 | 134 | .heap (COPY): 135 | { 136 | __end__ = .; 137 | PROVIDE(end = .); 138 | *(.heap*) 139 | __HeapLimit = .; 140 | } > RAM 141 | 142 | /* .stack_dummy section doesn't contains any symbols. It is only 143 | * used for linker to calculate size of stack sections, and assign 144 | * values to stack symbols later */ 145 | .stack_dummy (COPY): 146 | { 147 | *(.stack*) 148 | } > RAM 149 | 150 | /* Set stack top to end of RAM, and stack limit move down by 151 | * size of stack_dummy section */ 152 | __StackTop = ORIGIN(RAM) + LENGTH(RAM); 153 | __StackLimit = __StackTop - SIZEOF(.stack_dummy); 154 | PROVIDE(__stack = __StackTop); 155 | 156 | /* Check if data + heap + stack exceeds RAM limit */ 157 | ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") 158 | } 159 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-swd/asm/main.s: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: main.c 3 | * 4 | * Copyright (c) 2016 Square, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Author: Ford Peprah 19 | * 20 | * Created: September 28th, 2016 21 | * Modified: September 28th, 2016 22 | *****************************************************************************/ 23 | sys_write = 0x05 24 | sys_exit = 0x0 25 | 26 | .text 27 | .thumb 28 | .thumb_func 29 | .align 2 30 | .global main 31 | .type main, %function 32 | main: 33 | mov r0, #sys_write 34 | ldr r1, =array 35 | mov r2, r1 36 | 37 | mov r3, #0 38 | str r3, [r2] 39 | 40 | ldr r3, =msg 41 | add r2, r2, #4 42 | str r3, [r2] 43 | 44 | mov r3, #37 45 | add r2, r2, #4 46 | str r3, [r2] 47 | 48 | bkpt sys_write 49 | 50 | mov r0, #0 51 | bkpt sys_exit 52 | 53 | .data 54 | .balign 4 55 | array: 56 | .skip 12 57 | 58 | msg: 59 | .asciz "You must construct additional pylons." 60 | .end 61 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-swo/.gdbinit: -------------------------------------------------------------------------------- 1 | target remote :2331 2 | monitor speed auto 3 | monitor endian little 4 | monitor flash device $DEVICE 5 | monitor flash breakpoints = 1 6 | monitor semihosting enable 7 | monitor semihosting IOClient = 2 8 | monitor reset 6 9 | load build/firmware.elf 10 | file build/firmware.elf 11 | monitor reset 6 12 | monitor reset 6 13 | 14 | # monitor SWO EnableTarget 15 | # If 0 is given for the CPU and SWO frequency, it is determined automatically. 16 | monitor SWO EnableTarget 20958600 0 0xFFFFFFFF 0 17 | 18 | # Continue 19 | c 20 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-swo/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Square, Inc. 2 | 3 | # Commands 4 | TARGET_PREFIX = arm-none-eabi- 5 | AS = $(TARGET_PREFIX)as 6 | LD = $(TARGET_PREFIX)ld 7 | CC = $(TARGET_PREFIX)gcc 8 | CPP = $(TARGET_PREFIX)g++ 9 | OBJCOPY = $(TARGET_PREFIX)objcopy 10 | CP = cp 11 | MKDIR = mkdir 12 | 13 | # Directories 14 | BUILDDIR = build 15 | ASMDIR = asm 16 | SRCDIR = src 17 | 18 | # Flags 19 | ASFLAGS = -g -mthumb -mcpu=cortex-m4 20 | LDFLAGS = -T$(ASMDIR)/gcc.ld --specs=nosys.specs -mthumb -mcpu=cortex-m4 -nostartfiles 21 | CCFLAGS = -S -Wall -O0 -mcpu=cortex-m4 -mthumb -g 22 | 23 | # Output Files 24 | BIN = $(BUILDDIR)/firmware.bin 25 | ELF = $(BUILDDIR)/firmware.elf 26 | ASOURCES = $(notdir $(wildcard $(ASMDIR)/*.s)) 27 | CSOURCES = $(notdir $(wildcard $(SRCDIR)/*.c)) 28 | OBJS = $(addprefix $(BUILDDIR)/,$(ASOURCES:.s=.o)) $(addprefix $(BUILDDIR)/,$(CSOURCES:.c=.o)) 29 | 30 | .PHONY: all clean 31 | 32 | all: $(BIN) 33 | 34 | clean: 35 | -$(RM) -rf $(BUILDDIR) 36 | 37 | $(ELF): $(OBJS) 38 | @$(MKDIR) -p $(BUILDDIR) 39 | $(CC) $(LDFLAGS) -o $@ $^ 40 | 41 | $(BUILDDIR)/%.o: $(BUILDDIR)/%.s 42 | @$(MKDIR) -p $(BUILDDIR) 43 | $(AS) $(ASFLAGS) -o $@ $< 44 | 45 | $(BUILDDIR)/%.s: $(ASMDIR)/%.s 46 | @$(MKDIR) -p $(BUILDDIR) 47 | $(CP) $< $(BUILDDIR)/ 48 | 49 | $(BUILDDIR)/%.s: $(SRCDIR)/%.c 50 | @$(MKDIR) -p $(BUILDDIR) 51 | $(CC) $(CCFLAGS) -o $@ $< 52 | 53 | %.bin: %.elf 54 | $(OBJCOPY) -O binary $< $@ 55 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-swo/README.md: -------------------------------------------------------------------------------- 1 | # K21 SWO 2 | 3 | This firmware build demonstrates using Serial Wire Output (SWO) using the 4 | Instruction Trace Macrocell (ITM) ports on K21. This firmware is known to 5 | work on the `K21F120M` and `K21D50M` evaluation boards. 6 | 7 | ## Building the Firmware 8 | 9 | To build the firmware, run `make` from within the directory. This will create 10 | a build directory containing the binary files. 11 | 12 | ## Firmware Overview 13 | 14 | This firmware does the following things on boot: 15 | 16 | 1. Stops the watchdog timer. 17 | 2. Configures the ITM ports for SWO output. 18 | 3. Outputs a single string via SWO. 19 | 4. Halts. 20 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-swo/asm/gcc.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K 4 | RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 64K 5 | } 6 | 7 | /* Linker script to place sections and symbol values. Should be used together 8 | * with other linker script that defines memory regions FLASH and RAM. 9 | * It references following symbols, which must be defined in code: 10 | * Reset_Handler : Entry of reset handler 11 | * 12 | * It defines following symbols, which code can use without definition: 13 | * __exidx_start 14 | * __exidx_end 15 | * __copy_table_start__ 16 | * __copy_table_end__ 17 | * __zero_table_start__ 18 | * __zero_table_end__ 19 | * __etext 20 | * __data_start__ 21 | * __preinit_array_start 22 | * __preinit_array_end 23 | * __init_array_start 24 | * __init_array_end 25 | * __fini_array_start 26 | * __fini_array_end 27 | * __data_end__ 28 | * __bss_start__ 29 | * __bss_end__ 30 | * __end__ 31 | * end 32 | * __HeapLimit 33 | * __StackLimit 34 | * __StackTop 35 | * __stack 36 | */ 37 | ENTRY(Reset_Handler) 38 | 39 | SECTIONS 40 | { 41 | .text : 42 | { 43 | KEEP(*(.isr_vector)) 44 | 45 | /* Flash configuration field; woe be to the one who relocates 46 | * this section. Extremem care should be taken when modifying 47 | * this region. 48 | */ 49 | . = 0x400; 50 | KEEP(*(.fcf)) 51 | 52 | *(.text*) 53 | 54 | KEEP(*(.init)) 55 | KEEP(*(.fini)) 56 | 57 | /* .ctors */ 58 | *crtbegin.o(.ctors) 59 | *crtbegin?.o(.ctors) 60 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) 61 | *(SORT(.ctors.*)) 62 | *(.ctors) 63 | 64 | /* .dtors */ 65 | *crtbegin.o(.dtors) 66 | *crtbegin?.o(.dtors) 67 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) 68 | *(SORT(.dtors.*)) 69 | *(.dtors) 70 | 71 | *(.rodata*) 72 | 73 | KEEP(*(.eh_frame*)) 74 | } > FLASH 75 | 76 | .ARM.extab : 77 | { 78 | *(.ARM.extab* .gnu.linkonce.armextab.*) 79 | } > FLASH 80 | 81 | __exidx_start = .; 82 | .ARM.exidx : 83 | { 84 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 85 | } > FLASH 86 | __exidx_end = .; 87 | 88 | __etext = .; 89 | 90 | .data : AT (__etext) 91 | { 92 | __data_start__ = .; 93 | *(vtable) 94 | *(.data*) 95 | 96 | . = ALIGN(4); 97 | /* preinit data */ 98 | PROVIDE_HIDDEN (__preinit_array_start = .); 99 | KEEP(*(.preinit_array)) 100 | PROVIDE_HIDDEN (__preinit_array_end = .); 101 | 102 | . = ALIGN(4); 103 | /* init data */ 104 | PROVIDE_HIDDEN (__init_array_start = .); 105 | KEEP(*(SORT(.init_array.*))) 106 | KEEP(*(.init_array)) 107 | PROVIDE_HIDDEN (__init_array_end = .); 108 | 109 | 110 | . = ALIGN(4); 111 | /* finit data */ 112 | PROVIDE_HIDDEN (__fini_array_start = .); 113 | KEEP(*(SORT(.fini_array.*))) 114 | KEEP(*(.fini_array)) 115 | PROVIDE_HIDDEN (__fini_array_end = .); 116 | 117 | KEEP(*(.jcr*)) 118 | . = ALIGN(4); 119 | /* All data end */ 120 | __data_end__ = .; 121 | 122 | } > RAM 123 | 124 | .bss : 125 | { 126 | . = ALIGN(4); 127 | __bss_start__ = .; 128 | *(.bss*) 129 | *(COMMON) 130 | . = ALIGN(4); 131 | __bss_end__ = .; 132 | } > RAM 133 | 134 | .heap (COPY): 135 | { 136 | __end__ = .; 137 | PROVIDE(end = .); 138 | *(.heap*) 139 | __HeapLimit = .; 140 | } > RAM 141 | 142 | /* .stack_dummy section doesn't contains any symbols. It is only 143 | * used for linker to calculate size of stack sections, and assign 144 | * values to stack symbols later */ 145 | .stack_dummy (COPY): 146 | { 147 | *(.stack*) 148 | } > RAM 149 | 150 | /* Set stack top to end of RAM, and stack limit move down by 151 | * size of stack_dummy section */ 152 | __StackTop = ORIGIN(RAM) + LENGTH(RAM); 153 | __StackLimit = __StackTop - SIZEOF(.stack_dummy); 154 | PROVIDE(__stack = __StackTop); 155 | 156 | /* Check if data + heap + stack exceeds RAM limit */ 157 | ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") 158 | } 159 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-swo/src/main.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: main.c 3 | * 4 | * Copyright (c) 2016 Square, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Author: Ford Peprah 19 | * 20 | * Created: September 13th, 2016 21 | * Modified: September 14th, 2016 22 | *****************************************************************************/ 23 | #include "swo.h" 24 | #define CPU_SPEED 21004050 // 21 MHz 25 | #define SWO_SPEED 3000000 // 3 MHz 26 | #define PORT_MASK 0x1 // Enable one port. 27 | #define FOREVER for(;;) 28 | 29 | int main(void) { 30 | SWO_Init(CPU_SPEED, SWO_SPEED, PORT_MASK); 31 | 32 | const char *string = "You must construct additional pylons."; 33 | SWO_Puts(0, string); 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-swo/src/swo.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: swo.c 3 | * 4 | * Copyright (c) 2016 Square, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Author: Ford Peprah 19 | * 20 | * Created: September 14th, 2016 21 | * Modified: September 14th, 2016 22 | *****************************************************************************/ 23 | #include "swo.h" 24 | 25 | /** 26 | * Debug Exception and Monitor Control Register (DEMCR) 27 | * 28 | * This is a read/write register used for vector catching and debug monitor 29 | * control. 30 | */ 31 | #define DEMCR (*((volatile unsigned *)0xE000EDFC)) 32 | #define TRCENA (1 << 24) 33 | 34 | /** 35 | * Selected Pin Protocol Register (TPIU_SPPR) 36 | * 37 | * This is a read/write register that is reset with a value of `0x1`, which 38 | * indicates manchester encoding. This is a trace point unit register which is 39 | * used to select which protocol to use for trace output. 40 | */ 41 | #define TPIU_SPPR (*((volatile unsigned *)0xE00400F0)) 42 | #define MANCHESTER 0x00000001 43 | #define NRZ 0x00000002 44 | 45 | /** 46 | * Asynchronous Clock Prescaler Register (ACPR) 47 | * 48 | * This is a read/write register that is reset with a value of `0`. It is used 49 | * to set a prescaler in order to scale the baud rate of the asynchronous 50 | * output. 51 | */ 52 | #define TPIU_ACPR (*((volatile unsigned *)0xE0040010)) 53 | 54 | /** 55 | * Data Watchpoint and Trace Control Register (DWT_CTRL) 56 | * 57 | * This is a read/write register that has various reset values. This register 58 | * is used to provide information about the data watchpoint. 59 | */ 60 | #define DWT_CTRL (*((volatile unsigned *)0xE0001000)) 61 | 62 | /** 63 | * Trace Port Interface Unit Formatter and Flush Control Register (TPIU_FFCR) 64 | * 65 | * This is a read/write register that is reset with a value of `0x102`. This 66 | * register is used to trigger events, enable and configure formatting, and 67 | * generate flush events. 68 | */ 69 | #define TPIU_FFCR (*((volatile unsigned *)0xE0040304)) 70 | 71 | #define ITM_Port8(n) (*((volatile unsigned char *)(ITM_BASEADDR + 4 * n))) 72 | #define ITM_Port16(n) (*((volatile unsigned short *)(ITM_BASEADDR + 4 * n))) 73 | #define ITM_Port32(n) (*((volatile unsigned int *)(ITM_BASEADDR + 4 * n))) 74 | 75 | void swo_init(unsigned int cpu_speed, unsigned int swo_speed, unsigned int port_mask) { 76 | // Bit [24] Read/write TRCENA. Must be set to `1` to enable use of the 77 | // trace and debug blocks: Data Watchpoint and Trace (DWT), Instrumentation 78 | // Trace Macrocell (ITM), Embedded Trace Macrocell (ETM), and Trace Port 79 | // Interface Unit (TPIU). 80 | DEMCR |= TRCENA; 81 | 82 | // A privileged write of `0xC5ACCE55` enables more write access to Control 83 | // Register `0xE00::0xFFC`. An invalid write removes write access. 84 | ITM_LAR = 0xC5ACCE55; 85 | 86 | // Bits [1:0] read/write select the protocol to use. `0` and `3` are 87 | // reserved, while `01` is SWO using Manchester encoding, and `10` is SWO 88 | // using NRZ encoding. 89 | TPIU_SPPR = NRZ; 90 | 91 | // Prescaler value is computed as the quotient between the cpu speed and 92 | // the SWO speed. We subtract one, as the prescaler is ultimately computed 93 | // by adding `1` to the value written to the ACPR. 94 | unsigned int prescaler = (cpu_speed / swo_speed) - 1; 95 | TPIU_ACPR = prescaler; 96 | 97 | // Bits [3:0] specify which stimulus ports can be accessed and describe the 98 | // ranges from `31-24`, `23-16`, `15-8`, and `7-0` respectively. By 99 | // default, we want to allow access to all. Note that this is different 100 | // from actually enabling writing to them. 101 | ITM_TPR = 0x00000000; 102 | 103 | // DWT Control Register. We enable the exception trace and exception 104 | // overhead. 105 | DWT_CTRL |= 0x400003FE; 106 | 107 | // Bit [0] enables ITM. Bits[4:2] enable SWV behaviour, DWT stimulus, and 108 | // sync packets for TPIU respectively. Bit `16` sets the ATB ID for the 109 | // Coresight System (we set this to `1`). 110 | ITM_TCR = 0x0001001F; 111 | 112 | // Bit [9] indicates that a trigger should be fired on a trigger event. 113 | // This will allow tracing of trigger events. The rest of the events are 114 | // disabled. 115 | TPIU_FFCR = 0x00000100; 116 | 117 | // We set the user specified port mask to enable tracing on the specified 118 | // ITM stimulus ports. One bit per stimulus port. 119 | ITM_TER = port_mask; 120 | } 121 | 122 | int swo_putchar(stimulus_port_t port, char ch) { 123 | // Check that tracing is enabled on the debug monitor. 124 | if ((DEMCR & TRCENA) == 0) { 125 | return 0; 126 | } 127 | 128 | // Check that ITM is enabled. 129 | if ((ITM_TCR & 1) == 0) { 130 | return 0; 131 | } 132 | 133 | // Check that tracing is enabled for the given port. 134 | if ((ITM_TER & (1 << port)) == 0) { 135 | return 0; 136 | } 137 | 138 | while (ITM_Port8(port) == 0); 139 | 140 | ITM_Port8(port) = (int)ch; 141 | 142 | return ch; 143 | } 144 | 145 | void swo_puts(stimulus_port_t port, const char *string) { 146 | while (*string) { 147 | swo_putchar(port, *string++); 148 | } 149 | } 150 | 151 | #ifdef OVERRIDE_PRINTF 152 | 153 | int putchar(int ch) { 154 | return swo_putchar(STIMULUS_PORT_0, ch); 155 | } 156 | 157 | int fputc(int ch, FILE *f) { 158 | if (f) { 159 | return swo_putchar(f->port, ch); 160 | } 161 | return swo_putchar(STIMULUS_PORT_0, ch); 162 | } 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /tests/functional/firmware/k21-swo/src/swo.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * File: swo.h 3 | * 4 | * Copyright (c) 2016 Square, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * Author: Ford Peprah 19 | * 20 | * Created: September 14th, 2016 21 | * Modified: September 14th, 2016 22 | *****************************************************************************/ 23 | #ifndef __SWO_H__ 24 | #define __SWO_H__ 25 | 26 | #define SWO_Init swo_init 27 | #define SWO_Putchar swo_putchar 28 | #define SWO_Puts swo_puts 29 | 30 | /** 31 | * ITM Stimulus Ports 32 | * 33 | * There are 32 stimulus ports (indexed `0 - 31`). Each port has its own 34 | * address which is calculated by multiplying the index by `4` and adding it to 35 | * the ITM base address. 36 | * 37 | * Reading from any of these ports will return the FIFO status in the last bit. 38 | * If the FIFO status is `0`, it is full, while `1` is not full. 39 | */ 40 | #define ITM_BASEADDR 0xE0000000 41 | 42 | /** 43 | * ITM Registers 44 | * 45 | * ITM Trace Enable Register (ITM_TER), ITM Trace Privilege Register (ITM_TPR), 46 | * ITM Trace Control Register (ITM_TCR), ITM Lock Access Register (ITM_LAR), 47 | * and the ITM Lock Status Register (ITM_LSR). 48 | */ 49 | #define ITM_TER (*((volatile unsigned *)0xE0000E00)) 50 | #define ITM_TPR (*((volatile unsigned *)0xE0000E40)) 51 | #define ITM_TCR (*((volatile unsigned *)0xE0000E80)) 52 | #define ITM_LAR (*((volatile unsigned *)0xE0000FB0)) 53 | #define ITM_LSR (*((volatile unsigned *)0xE0000FB4)) 54 | 55 | /** 56 | * Stimulus Port Indices 57 | */ 58 | typedef enum stimulus_port_t { 59 | STIMULUS_PORT_0 = 0, 60 | STIMULUS_PORT_1, 61 | STIMULUS_PORT_2, 62 | STIMULUS_PORT_3, 63 | STIMULUS_PORT_4, 64 | STIMULUS_PORT_5, 65 | STIMULUS_PORT_6, 66 | STIMULUS_PORT_7, 67 | STIMULUS_PORT_8, 68 | STIMULUS_PORT_9, 69 | STIMULUS_PORT_10, 70 | STIMULUS_PORT_11, 71 | STIMULUS_PORT_12, 72 | STIMULUS_PORT_13, 73 | STIMULUS_PORT_14, 74 | STIMULUS_PORT_15, 75 | STIMULUS_PORT_16, 76 | STIMULUS_PORT_17, 77 | STIMULUS_PORT_18, 78 | STIMULUS_PORT_19, 79 | STIMULUS_PORT_20, 80 | STIMULUS_PORT_21, 81 | STIMULUS_PORT_22, 82 | STIMULUS_PORT_23, 83 | STIMULUS_PORT_24, 84 | STIMULUS_PORT_25, 85 | STIMULUS_PORT_26, 86 | STIMULUS_PORT_27, 87 | STIMULUS_PORT_28, 88 | STIMULUS_PORT_29, 89 | STIMULUS_PORT_30, 90 | STIMULUS_PORT_31, 91 | NUM_STIMULUS_PORTS 92 | } stimulus_port_t; 93 | 94 | #ifdef OVERRIDE_PRINTF 95 | 96 | struct __FILE { 97 | stimulus_port_t port; 98 | }; 99 | 100 | typedef struct __FILE FILE; 101 | 102 | #endif 103 | 104 | /** 105 | * swo_init: 106 | * Performs necessary setup in order to send data over SWO using the ITM. 107 | * 108 | * This is a blocking call. 109 | */ 110 | void swo_init(unsigned int cpu_speed, unsigned int swo_speed, unsigned int port_mask); 111 | 112 | /** 113 | * swo_putchar: 114 | * Puts a character to the given stimulus port. 115 | * 116 | * Returns the character written on success, otherwise `0`. 117 | * 118 | * This is a blocking call. 119 | */ 120 | int swo_putchar(stimulus_port_t port, char ch); 121 | 122 | /** 123 | * swo_puts: 124 | * Puts a string to the given stimulus port one character at a time. 125 | * 126 | * This is a blocking call. 127 | */ 128 | void swo_puts(stimulus_port_t port, const char *string); 129 | 130 | #endif /* __SWO_H__ */ 131 | -------------------------------------------------------------------------------- /tests/unit/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /tests/unit/protocols/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /tests/unit/test_binpacker.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pylink.binpacker as binpacker 16 | 17 | import unittest 18 | 19 | 20 | class TestBinpacker(unittest.TestCase): 21 | """Unit test class for the `binpacker` submodule.""" 22 | 23 | def setUp(self): 24 | """Called before each test. 25 | 26 | Performs setup. 27 | 28 | Args: 29 | self (TestBinpacker): the `TestBinpacker` instance 30 | 31 | Returns: 32 | `None` 33 | """ 34 | pass 35 | 36 | def tearDown(self): 37 | """Called after each test. 38 | 39 | Performs teardown. 40 | 41 | Args: 42 | self (TestBinpacker): the `TestBinpacker` instance 43 | 44 | Returns: 45 | `None` 46 | """ 47 | pass 48 | 49 | def test_pack_size_valid(self): 50 | """Tests the `pack_size()` method. 51 | 52 | Tests that the `pack_size()` method returns the appropriate number of 53 | bytes based on the value of the integer being passed. 54 | 55 | Args: 56 | self (TestBinpacker): the `TestBinpacker` instance 57 | 58 | Returns: 59 | `None` 60 | """ 61 | self.assertEqual(1, binpacker.pack_size(0)) 62 | self.assertEqual(1, binpacker.pack_size(255)) 63 | self.assertEqual(2, binpacker.pack_size(256)) 64 | self.assertEqual(2, binpacker.pack_size(65535)) 65 | self.assertEqual(3, binpacker.pack_size(65536)) 66 | self.assertEqual(4, binpacker.pack_size(2147483647)) 67 | self.assertEqual(8, binpacker.pack_size(9223372036854775807)) 68 | 69 | def test_pack_size_invalid(self): 70 | """Tests that the `pack_size()` method throws an exception. 71 | 72 | We cannot handle non-strings or negative numbers, so `pack_size()` 73 | should throw an exception. 74 | 75 | Args: 76 | self (TestBinpacker): the `TestBinpacker` instance 77 | 78 | Returns: 79 | `None` 80 | """ 81 | with self.assertRaises(TypeError): 82 | binpacker.pack_size('Bender Bending Rodriguez') 83 | 84 | with self.assertRaises(ValueError): 85 | binpacker.pack_size(-1) 86 | 87 | def test_pack(self): 88 | """Tests that the `pack()` method packs values explicitly. 89 | 90 | Args: 91 | self (TestBinpacker): the `TestBinpacker` instance 92 | 93 | Returns: 94 | `None` 95 | """ 96 | packed = binpacker.pack(255, 1) 97 | self.assertEqual(1, len(packed)) 98 | self.assertEqual(255, int(packed[0])) 99 | 100 | packed = binpacker.pack(255, 8) 101 | self.assertEqual(1, len(packed)) 102 | self.assertEqual(255, int(packed[0])) 103 | 104 | packed = binpacker.pack(255, 16) 105 | self.assertEqual(2, len(packed)) 106 | self.assertEqual(255, int(packed[0])) 107 | self.assertEqual(0, int(packed[1])) 108 | 109 | packed = binpacker.pack(255, 32) 110 | self.assertEqual(4, len(packed)) 111 | self.assertEqual(255, int(packed[0])) 112 | self.assertEqual(0, int(packed[1])) 113 | self.assertEqual(0, int(packed[2])) 114 | self.assertEqual(0, int(packed[3])) 115 | 116 | packed = binpacker.pack(0xFF000000, 32) 117 | self.assertEqual(4, len(packed)) 118 | self.assertEqual(0, int(packed[0])) 119 | self.assertEqual(0, int(packed[1])) 120 | self.assertEqual(0, int(packed[2])) 121 | self.assertEqual(255, int(packed[3])) 122 | 123 | def test_pack_infer_size(self): 124 | """Tests that the `pack()` method can pack with an inferred size. 125 | 126 | Args: 127 | self (TestBinpacker): the `TestBinpacker` instance 128 | 129 | Returns: 130 | `None` 131 | """ 132 | packed = binpacker.pack(255) 133 | self.assertEqual(1, len(packed)) 134 | self.assertEqual(255, int(packed[0])) 135 | 136 | packed = binpacker.pack(256) 137 | self.assertEqual(2, len(packed)) 138 | self.assertEqual(0, int(packed[0])) 139 | self.assertEqual(1, int(packed[1])) 140 | 141 | packed = binpacker.pack(0xFF000000) 142 | self.assertEqual(4, len(packed)) 143 | self.assertEqual(0, int(packed[0])) 144 | self.assertEqual(0, int(packed[1])) 145 | self.assertEqual(0, int(packed[2])) 146 | self.assertEqual(255, int(packed[3])) 147 | 148 | def test_pack_invalid(self): 149 | """Tests that the `pack()` method raises an exception. 150 | 151 | Non-numbers or integers less than or equal to zero are unsupported. 152 | 153 | Args: 154 | self (TestBinPacker): the `TestBinpacker` instance 155 | 156 | Returns: 157 | `None` 158 | """ 159 | with self.assertRaises(TypeError): 160 | binpacker.pack('Phillip J. Fry') 161 | 162 | with self.assertRaises(ValueError): 163 | binpacker.pack(4, 0) 164 | 165 | with self.assertRaises(ValueError): 166 | binpacker.pack(4, -1) 167 | 168 | 169 | if __name__ == '__main__': 170 | unittest.main() 171 | -------------------------------------------------------------------------------- /tests/unit/test_decorators.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pylink.decorators as decorators 16 | 17 | import mock 18 | 19 | import threading 20 | import unittest 21 | 22 | 23 | class TestDecorators(unittest.TestCase): 24 | """Unit test for the `decorators` submodule.""" 25 | 26 | def setUp(self): 27 | """Called before each test. 28 | 29 | Performs setup. 30 | 31 | Args: 32 | self (TestDecorators): the `TestDecorators` instance 33 | 34 | Returns: 35 | `None` 36 | """ 37 | self.callback = mock.Mock() 38 | 39 | def tearDown(self): 40 | """Called after each test. 41 | 42 | Performs teardown. 43 | 44 | Args: 45 | self (TestDecorators): the `TestDecorators` instance 46 | 47 | Returns: 48 | `None` 49 | """ 50 | pass 51 | 52 | def test_async_decorator_invalid(self): 53 | """Tests that the decorator raises an exception on invalid args. 54 | 55 | Args: 56 | self (TestDecorators): the `TestDecorators` instance 57 | 58 | Returns: 59 | `None` 60 | """ 61 | @decorators.async_decorator 62 | def foo(): 63 | return 4 64 | 65 | with self.assertRaises(TypeError): 66 | foo(callback='callback') 67 | 68 | def test_async_decorator_sync_call(self): 69 | """Tests that we can call the decorated method synchronously. 70 | 71 | Args: 72 | self (TestDecorators): the `TestDecorators` instance 73 | 74 | Returns: 75 | `None` 76 | """ 77 | @decorators.async_decorator 78 | def foo(): 79 | return 4 80 | 81 | self.assertEqual(4, foo()) 82 | 83 | def test_async_decorator_join(self): 84 | """Tests that the returned object is a thread that can be joined and 85 | waited for termination. 86 | 87 | Args: 88 | self (TestDecorators): the `TestDecorators` instance 89 | 90 | Returns: 91 | `None` 92 | """ 93 | @decorators.async_decorator 94 | def foo(): 95 | return 4 96 | 97 | def callback(exception, result): 98 | return result 99 | 100 | thread = foo(callback=self.callback) 101 | self.assertTrue(isinstance(thread, threading.Thread)) 102 | 103 | result = thread.join() 104 | self.assertTrue(isinstance(result, mock.Mock)) 105 | self.callback.assert_called_with(None, 4) 106 | 107 | thread = foo(callback=callback) 108 | self.assertTrue(isinstance(thread, threading.Thread)) 109 | 110 | result = thread.join() 111 | self.assertEqual(4, result) 112 | 113 | def test_async_decorator_exception(self): 114 | """Tests that exceptions raised in the async call are passed to the 115 | callback. 116 | 117 | Args: 118 | self (TestDecorators): the `TestDecorators` instance 119 | 120 | Returns: 121 | `None` 122 | """ 123 | @decorators.async_decorator 124 | def failure(): 125 | raise Exception('I HAVE FAILED!') 126 | 127 | thread = failure(callback=self.callback) 128 | thread.join() 129 | 130 | self.assertEqual(1, len(self.callback.call_args_list)) 131 | self.assertTrue(self.callback.call_args is not None) 132 | 133 | exception = self.callback.call_args[0][0] 134 | self.assertTrue(isinstance(exception, BaseException)) 135 | self.assertEqual('I HAVE FAILED!', str(exception)) 136 | 137 | res = self.callback.call_args[0][1] 138 | self.assertEqual(None, res) 139 | 140 | 141 | if __name__ == '__main__': 142 | unittest.main() 143 | -------------------------------------------------------------------------------- /tests/unit/test_enums.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pylink.enums as enums 16 | 17 | import unittest 18 | 19 | 20 | class TestEnums(unittest.TestCase): 21 | """Unit test for the `enums` submodule.""" 22 | 23 | def setUp(self): 24 | """Called before each test. 25 | 26 | Performs setup. 27 | 28 | Args: 29 | self (TestEnums): the ``TestEnums`` instance 30 | 31 | Returns: 32 | ``None`` 33 | """ 34 | pass 35 | 36 | def tearDown(self): 37 | """Called after each test. 38 | 39 | Performs teardown. 40 | 41 | Args: 42 | self (TestEnums): the ``TestEnums`` instance 43 | 44 | Returns: 45 | ``None`` 46 | """ 47 | pass 48 | 49 | def test_jlink_global_errors(self): 50 | """Tests the global errors. 51 | 52 | The J-Link DLL defines a set of global error codes, which start at -256 53 | and run until -274. 54 | 55 | Values from -1 to -255 are reserved for function specific error codes. 56 | 57 | This test checks that an error message is defined for those from -256 58 | to -274, and not for -1 to -255. 59 | 60 | Args: 61 | self (TestEnums): the ``TestEnums`` instance 62 | 63 | Returns: 64 | ``None`` 65 | """ 66 | for i in range(-255, -1): 67 | with self.assertRaises(ValueError): 68 | enums.JLinkGlobalErrors.to_string(i) 69 | 70 | for i in range(-274, -255): 71 | error_message = enums.JLinkGlobalErrors.to_string(i) 72 | self.assertTrue(isinstance(error_message, str)) 73 | 74 | def test_jlink_global_errors_unspecified(self): 75 | """Tests the unspecified error case. 76 | 77 | Args: 78 | self (TestEnums): the ``TestEnums`` instance 79 | 80 | Returns: 81 | ``None`` 82 | """ 83 | error_message = enums.JLinkGlobalErrors.to_string(-1) 84 | self.assertEqual('Unspecified error.', error_message) 85 | 86 | def test_jlink_write_errors(self): 87 | """Tests write specific errors. 88 | 89 | Args: 90 | self (TestEnums): the ``TestEnums`` instance 91 | 92 | Returns: 93 | ``None`` 94 | """ 95 | error_message = enums.JLinkWriteErrors.to_string(-5) 96 | self.assertTrue(isinstance(error_message, str)) 97 | 98 | error_message = enums.JLinkWriteErrors.to_string(-1) 99 | self.assertEqual('Unspecified error.', error_message) 100 | 101 | def test_jlink_read_errors(self): 102 | """Tests read specific errors. 103 | 104 | Args: 105 | self (TestEnums): the ``TestEnums`` instance 106 | 107 | Returns: 108 | ``None`` 109 | """ 110 | error_message = enums.JLinkReadErrors.to_string(-5) 111 | self.assertTrue(isinstance(error_message, str)) 112 | 113 | error_message = enums.JLinkReadErrors.to_string(-1) 114 | self.assertEqual('Unspecified error.', error_message) 115 | 116 | def test_jlink_data_event_errors(self): 117 | """Tests the data event errors. 118 | 119 | Args: 120 | self (TestEnums): the ``TestEnums`` instance 121 | 122 | Returns: 123 | ``None`` 124 | """ 125 | error_codes = [ 126 | 0x80000000, 0x80000001, 0x80000002, 0x80000004, 0x80000020, 127 | 0x80000040, 0x80000080 128 | ] 129 | 130 | for error_code in error_codes: 131 | error_message = enums.JLinkDataErrors.to_string(error_code) 132 | self.assertTrue(isinstance(error_message, str)) 133 | 134 | error_message = enums.JLinkDataErrors.to_string(-1) 135 | self.assertEqual('Unspecified error.', error_message) 136 | 137 | def test_jlink_flash_errors(self): 138 | """Tests flash specific errors. 139 | 140 | Args: 141 | self (TestEnums): the ``TestEnums`` instance 142 | 143 | Returns: 144 | ``None`` 145 | """ 146 | for i in range(-4, -1): 147 | error_message = enums.JLinkFlashErrors.to_string(i) 148 | self.assertTrue(isinstance(error_message, str)) 149 | 150 | error_message = enums.JLinkFlashErrors.to_string(-1) 151 | self.assertEqual('Unspecified error.', error_message) 152 | 153 | def test_jlink_erase_errors(self): 154 | """Tests erase specific errors. 155 | 156 | Args: 157 | self (TestEnums): the ``TestEnums`` instance 158 | 159 | Returns: 160 | ``None`` 161 | """ 162 | for i in range(-5, -4): 163 | error_message = enums.JLinkEraseErrors.to_string(i) 164 | self.assertTrue(isinstance(error_message, str)) 165 | 166 | error_message = enums.JLinkEraseErrors.to_string(-1) 167 | self.assertEqual('Unspecified error.', error_message) 168 | 169 | 170 | if __name__ == '__main__': 171 | unittest.main() 172 | -------------------------------------------------------------------------------- /tests/unit/test_errors.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pylink.errors as errors 16 | 17 | import unittest 18 | 19 | 20 | class TestErrors(unittest.TestCase): 21 | """Unit test for the `errors` submodule.""" 22 | 23 | def setUp(self): 24 | """Called before each test. 25 | 26 | Performs setup. 27 | 28 | Args: 29 | self (TestErrors): the `TestErrors` instance 30 | 31 | Returns: 32 | `None` 33 | """ 34 | pass 35 | 36 | def tearDown(self): 37 | """Called after each test. 38 | 39 | Performs teardown. 40 | 41 | Args: 42 | self (TestErrors): the `TestErrors` instance 43 | 44 | Returns: 45 | `None` 46 | """ 47 | pass 48 | 49 | def test_jlink_exception_with_message(self): 50 | """Tests that a `JLinkException` can be created with a message. 51 | 52 | Args: 53 | self (TestErrors): the `TestErrors` instance 54 | 55 | Returns: 56 | `None` 57 | """ 58 | message = 'message' 59 | exception = errors.JLinkException(message) 60 | self.assertTrue(isinstance(exception.message, str)) 61 | self.assertEqual(message, exception.message) 62 | self.assertEqual(None, getattr(exception, 'code', None)) 63 | 64 | def test_jlink_exception_with_code(self): 65 | """Tests that a `JLinkException` can be created with a numeric code. 66 | 67 | Args: 68 | self (TestErrors): the `TestErrors` instance 69 | 70 | Returns: 71 | `None` 72 | """ 73 | code = -1 74 | exception = errors.JLinkException(code) 75 | self.assertTrue(isinstance(exception.message, str)) 76 | self.assertEqual('Unspecified error.', exception.message) 77 | self.assertEqual(code, getattr(exception, 'code', None)) 78 | 79 | 80 | if __name__ == '__main__': 81 | unittest.main() 82 | -------------------------------------------------------------------------------- /tests/unit/test_threads.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pylink.threads as threads 16 | 17 | import unittest 18 | 19 | 20 | class TestThreads(unittest.TestCase): 21 | """Unit test for the `threads` submodule.""" 22 | 23 | def setUp(self): 24 | """Called before each test. 25 | 26 | Performs setup. 27 | 28 | Args: 29 | self (TestThreads): the `TestThreads` instance 30 | 31 | Returns: 32 | `None` 33 | """ 34 | pass 35 | 36 | def tearDown(self): 37 | """Called after each test. 38 | 39 | Performs teardown. 40 | 41 | Args: 42 | self (TestThreads): the `TestThreads` instance 43 | 44 | Returns: 45 | `None` 46 | """ 47 | pass 48 | 49 | def test_thread(self): 50 | """Tests that a thread can be created and joined for a return value. 51 | 52 | Args: 53 | self (TestThreads): the `TestThreads` instance 54 | 55 | Returns: 56 | `None` 57 | """ 58 | def thread_func(): 59 | return 4 60 | 61 | def thread_func_with_args(x, y): 62 | return (x + y) 63 | 64 | thread = threads.ThreadReturn(target=thread_func) 65 | thread.start() 66 | self.assertEqual(4, thread.join()) 67 | 68 | thread = threads.ThreadReturn(target=thread_func_with_args, args=(2, 3)) 69 | thread.start() 70 | self.assertEqual(5, thread.join()) 71 | 72 | 73 | if __name__ == '__main__': 74 | unittest.main() 75 | -------------------------------------------------------------------------------- /tests/unit/unlockers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /tests/unit/unlockers/test_unlock.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Square, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pylink.unlockers as unlock 16 | 17 | import mock 18 | 19 | import unittest 20 | 21 | 22 | class TestUnlock(unittest.TestCase): 23 | """Tests the `unlockers` submodule.""" 24 | 25 | def setUp(self): 26 | """Called before each test. 27 | 28 | Performs setup. 29 | 30 | Args: 31 | self (TestUnlock): the `TestUnlock` instance 32 | 33 | Returns: 34 | `None` 35 | """ 36 | pass 37 | 38 | def tearDown(self): 39 | """Called after each test. 40 | 41 | Performs teardown. 42 | 43 | Args: 44 | self (TestUnlock): the `TestUnlock` instance 45 | 46 | Returns: 47 | `None` 48 | """ 49 | pass 50 | 51 | def test_unlock_unsupported(self): 52 | """Tests calling `unlock()` for an unsupported MCU. 53 | 54 | Args: 55 | self (TestUnlock): the `TestUnlock` instance 56 | 57 | Returns: 58 | `None` 59 | """ 60 | jlink = mock.Mock() 61 | with self.assertRaises(NotImplementedError): 62 | unlock.unlock(jlink, 'kinetisf') 63 | 64 | with self.assertRaises(NotImplementedError): 65 | unlock.unlock(jlink, 'dsafdsafdas') 66 | 67 | @mock.patch('pylink.unlockers.unlock_kinetis') 68 | def test_unlock_supported(self, mock_unlock): 69 | """Tests calling `unlock()` with a supported MCU. 70 | 71 | Args: 72 | self (TestUnlock): the `TestUnlock` instance 73 | mock_unlock (function): the mocked unlock function 74 | 75 | Returns: 76 | `None` 77 | """ 78 | jlink = mock.Mock() 79 | supported = ['Kinetis', 'kinetis', 'NXP'] 80 | mock_unlock.return_value = True 81 | for mcu in supported: 82 | self.assertTrue(unlock.unlock(jlink, mcu)) 83 | 84 | 85 | if __name__ == '__main__': 86 | unittest.main() 87 | --------------------------------------------------------------------------------