├── nordicsemi ├── lister │ ├── unix │ │ ├── __init__.py │ │ └── unix_lister.py │ ├── windows │ │ ├── __init__.py │ │ ├── constants.py │ │ └── structures.py │ ├── __init__.py │ ├── lister_backend.py │ ├── enumerated_device.py │ └── device_lister.py ├── zigbee │ ├── tests │ │ ├── configs │ │ │ ├── empty.yaml │ │ │ ├── install.yaml │ │ │ ├── install_ieee.yaml │ │ │ ├── corrupt.yaml │ │ │ ├── install_ieee_power.yaml │ │ │ └── channel_install_ieee_power.yaml │ │ ├── golden_data │ │ │ ├── install.hex │ │ │ ├── install_ieee.hex │ │ │ ├── install_ieee_power.hex │ │ │ └── channel_install_ieee_power.hex │ │ ├── __init__.py │ │ └── test_prod_config.py │ ├── __init__.py │ ├── ota_flasher.py │ ├── prod_config.py │ └── ota_file.py ├── dfu │ ├── tests │ │ ├── firmwares │ │ │ ├── .gitignore │ │ │ ├── bar_wanted.bin │ │ │ ├── foo_wanted.bin │ │ │ ├── foobar_wanted.bin │ │ │ ├── pca10028_nrf51422_xxac_blinky.bin │ │ │ ├── bl_settings_v1_nrf52.hex │ │ │ └── bl_settings_v2_nrf52.hex │ │ ├── key.pem │ │ ├── __init__.py │ │ ├── test_signing.py │ │ ├── test_nrfhex.py │ │ ├── test_init_packet_pb.py │ │ ├── test_manifest.py │ │ └── test_package.py │ ├── dfu-cc.options │ ├── __init__.py │ ├── dfu-cc.proto │ ├── model.py │ ├── crc16.py │ ├── dfu.py │ ├── nrfhex.py │ ├── init_packet_pb.py │ ├── dfu_transport.py │ └── manifest.py ├── utility │ ├── tests │ │ ├── test_targets.json │ │ ├── __init__.py │ │ └── test_target_registry.py │ ├── __init__.py │ └── target_registry.py ├── __init__.py ├── version.py └── thread │ ├── __init__.py │ ├── ncp_flasher.py │ └── dfu_thread.py ├── requirements-dev.txt ├── screenshot.gif ├── tests ├── resources │ ├── dfu_test_softdevice_b.hex │ ├── blinky.bin │ ├── test_package.zip │ ├── blinky_mbr_sdk160.zip │ ├── hrs_application_s140_sdk160.zip │ ├── test.pem │ └── dfu_test_bootloader_b.hex ├── bdd │ ├── README.md │ ├── help_information.feature │ ├── environment.py │ ├── dfu.feature │ └── steps │ │ ├── util.py │ │ ├── help_information_steps.py │ │ └── common_steps.py ├── test_cli.py └── protobuf │ └── __main__.py ├── libusb ├── x64 │ ├── libusb-1.0.dll │ └── libusb-1.0.dylib └── x86 │ └── libusb-1.0.dll ├── .github └── ISSUE_TEMPLATE.md ├── requirements.txt ├── requirements-frozen.txt ├── .gitignore ├── README.md ├── LICENSE ├── nrfutil.spec ├── setup.py └── azure-pipelines.yml /nordicsemi/lister/unix/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /nordicsemi/lister/windows/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /nordicsemi/zigbee/tests/configs/empty.yaml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | -r requirements.txt 2 | behave 3 | nose 4 | pyinstaller 5 | -------------------------------------------------------------------------------- /nordicsemi/zigbee/tests/configs/install.yaml: -------------------------------------------------------------------------------- 1 | install_code: 83FED3407A939723A5C639B26916D505 2 | -------------------------------------------------------------------------------- /screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NordicSemiconductor/pc-nrfutil/HEAD/screenshot.gif -------------------------------------------------------------------------------- /tests/resources/dfu_test_softdevice_b.hex: -------------------------------------------------------------------------------- 1 | :020000040000FA 2 | :0869100000000000000000007F 3 | :00000001FF 4 | -------------------------------------------------------------------------------- /libusb/x64/libusb-1.0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NordicSemiconductor/pc-nrfutil/HEAD/libusb/x64/libusb-1.0.dll -------------------------------------------------------------------------------- /libusb/x86/libusb-1.0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NordicSemiconductor/pc-nrfutil/HEAD/libusb/x86/libusb-1.0.dll -------------------------------------------------------------------------------- /tests/resources/blinky.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NordicSemiconductor/pc-nrfutil/HEAD/tests/resources/blinky.bin -------------------------------------------------------------------------------- /libusb/x64/libusb-1.0.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NordicSemiconductor/pc-nrfutil/HEAD/libusb/x64/libusb-1.0.dylib -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/firmwares/.gitignore: -------------------------------------------------------------------------------- 1 | # Artefacts generated during test run 2 | /bar.bin 3 | /foobar.bin 4 | /foo.bin 5 | -------------------------------------------------------------------------------- /tests/resources/test_package.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NordicSemiconductor/pc-nrfutil/HEAD/tests/resources/test_package.zip -------------------------------------------------------------------------------- /nordicsemi/zigbee/tests/configs/install_ieee.yaml: -------------------------------------------------------------------------------- 1 | install_code: 83FED3407A939723A5C639B26916D505 2 | extended_address: AABBCCDDEEFF0011 3 | -------------------------------------------------------------------------------- /tests/resources/blinky_mbr_sdk160.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NordicSemiconductor/pc-nrfutil/HEAD/tests/resources/blinky_mbr_sdk160.zip -------------------------------------------------------------------------------- /nordicsemi/zigbee/tests/configs/corrupt.yaml: -------------------------------------------------------------------------------- 1 | channel_mask: whatever 2 | install_code: whatever 3 | extended_address: whatever 4 | tx_power: very high 5 | -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/firmwares/bar_wanted.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NordicSemiconductor/pc-nrfutil/HEAD/nordicsemi/dfu/tests/firmwares/bar_wanted.bin -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/firmwares/foo_wanted.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NordicSemiconductor/pc-nrfutil/HEAD/nordicsemi/dfu/tests/firmwares/foo_wanted.bin -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/firmwares/foobar_wanted.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NordicSemiconductor/pc-nrfutil/HEAD/nordicsemi/dfu/tests/firmwares/foobar_wanted.bin -------------------------------------------------------------------------------- /nordicsemi/zigbee/tests/configs/install_ieee_power.yaml: -------------------------------------------------------------------------------- 1 | install_code: 83FED3407A939723A5C639B26916D505 2 | extended_address: AABBCCDDEEFF0011 3 | tx_power: 9 4 | -------------------------------------------------------------------------------- /tests/resources/hrs_application_s140_sdk160.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NordicSemiconductor/pc-nrfutil/HEAD/tests/resources/hrs_application_s140_sdk160.zip -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/firmwares/pca10028_nrf51422_xxac_blinky.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NordicSemiconductor/pc-nrfutil/HEAD/nordicsemi/dfu/tests/firmwares/pca10028_nrf51422_xxac_blinky.bin -------------------------------------------------------------------------------- /nordicsemi/zigbee/tests/configs/channel_install_ieee_power.yaml: -------------------------------------------------------------------------------- 1 | channel_mask: 0x00100000 2 | install_code: 83FED3407A939723A5C639B26916D505 3 | extended_address: AABBCCDDEEFF0011 4 | tx_power: 9 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please use the [Nordic DevZone](https://devzone.nordicsemi.com) portal to report bugs, questions or feedback in general. If you would like to suggest code changes, feel free to submit a pull request. 2 | -------------------------------------------------------------------------------- /nordicsemi/dfu/dfu-cc.options: -------------------------------------------------------------------------------- 1 | dfu.Hash.hash max_size:32 2 | dfu.SignedCommand.signature max_size:64 3 | dfu.InitCommand.sd_req max_count:4 4 | dfu.InitCommand.boot_validation max_count:3 5 | dfu.BootValidation.bytes max_size:64 6 | -------------------------------------------------------------------------------- /nordicsemi/zigbee/tests/golden_data/install.hex: -------------------------------------------------------------------------------- 1 | :02000004000FEB 2 | :10C00000E737DDF6D1F365A73600010000F8FF073A 3 | :10C010000000000000000000000000000000000020 4 | :10C02000000000000000000083FED3407A939723B5 5 | :0AC03000A5C639B26916D505C3B5DF 6 | :00000001FF 7 | -------------------------------------------------------------------------------- /nordicsemi/zigbee/tests/golden_data/install_ieee.hex: -------------------------------------------------------------------------------- 1 | :02000004000FEB 2 | :10C00000E737DDF6342E18093600010000F8FF0787 3 | :10C010001100FFEEDDCCBBAA000000000000000014 4 | :10C02000000000000000000083FED3407A939723B5 5 | :0AC03000A5C639B26916D505C3B5DF 6 | :00000001FF 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | antlib >= 1.1b0; sys_platform == 'win32' 2 | click 3 | crcmod 4 | ecdsa 5 | intelhex 6 | libusb1==1.9.3 7 | pc_ble_driver_py >= 0.16.4 8 | piccata 9 | protobuf >=3.17.3, < 4.0.0 10 | pyserial 11 | pyspinel >= 1.0.0a3 12 | pyyaml 13 | tqdm 14 | -------------------------------------------------------------------------------- /tests/resources/test.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEID2WUBCe/4kLhl5ekJ+O8PtprcahUNFE3RIm5htQzDedoAoGCCqGSM49 3 | AwEHoUQDQgAEZY2i7duYH2l9rnIg1oIXq+0/uHAF7IoFubVru6oX9GCQm67NrXIm 4 | wgS2ErZi/0/MvRsMkIQQkNg6Wc2tbJgdTA== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEID2WUBCe/4kLhl5ekJ+O8PtprcahUNFE3RIm5htQzDedoAoGCCqGSM49 3 | AwEHoUQDQgAEZY2i7duYH2l9rnIg1oIXq+0/uHAF7IoFubVru6oX9GCQm67NrXIm 4 | wgS2ErZi/0/MvRsMkIQQkNg6Wc2tbJgdTA== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /nordicsemi/zigbee/tests/golden_data/install_ieee_power.hex: -------------------------------------------------------------------------------- 1 | :02000004000FEB 2 | :10C00000E737DDF6A04CD67E3600010000F8FF07CA 3 | :10C010001100FFEEDDCCBBAA0909090909090909CC 4 | :10C02000090909090909090983FED3407A9397236D 5 | :0AC03000A5C639B26916D505C3B5DF 6 | :00000001FF 7 | -------------------------------------------------------------------------------- /nordicsemi/zigbee/tests/golden_data/channel_install_ieee_power.hex: -------------------------------------------------------------------------------- 1 | :02000004000FEB 2 | :10C00000E737DDF6452B62573600010000001000CF 3 | :10C010001100FFEEDDCCBBAA0909090909090909CC 4 | :10C02000090909090909090983FED3407A9397236D 5 | :0AC03000A5C639B26916D505C3B5DF 6 | :00000001FF 7 | -------------------------------------------------------------------------------- /requirements-frozen.txt: -------------------------------------------------------------------------------- 1 | antlib==1.1b1 2 | click==8.0.1 3 | crcmod==1.7 4 | ecdsa==0.17.0 5 | intelhex==2.3.0 6 | libusb1==1.9.3 7 | pc-ble-driver-py==0.17.0 8 | piccata==2.0.1 9 | protobuf==3.17.3 10 | pyserial==3.5 11 | pyspinel==1.0.3 12 | PyYAML==5.4.1 13 | tqdm==4.62.0 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.py.bak 3 | 4 | # Virtualenv 5 | venv/ 6 | 7 | # Build 8 | build/ 9 | dist/ 10 | nrfutil.egg-info/ 11 | 12 | # Test artefacts 13 | /nordicsemi/dfu/tests/mypackage.zip 14 | /tests/test.zip 15 | .eggs/ 16 | unittests.xml 17 | 18 | 19 | # Ignore vscode settings and debug-options 20 | .vscode/ -------------------------------------------------------------------------------- /tests/resources/dfu_test_bootloader_b.hex: -------------------------------------------------------------------------------- 1 | :020000040003F7 2 | :10C00000103C0020C9EE0300E3EE0300E5EE030060 3 | :10C010000000000000000000000000000000000020 4 | :10C02000000000000000000000000000D5C0030078 5 | :10C030000000000000000000E9EE0300EBEE03004A 6 | :10C04000EDEE0300EDEE0300EDEE0300EDEE030078 7 | :10C05000EDEE030000000000EDEE0300EDEE030046 8 | :00000001FF 9 | -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/firmwares/bl_settings_v1_nrf52.hex: -------------------------------------------------------------------------------- 1 | :020000040007F3 2 | :10F00000514874F6010000000300000003000000F6 3 | :10F01000000000000000000060C10200813FC862E3 4 | :10F0200001000000000000000000000000000000DF 5 | :10F0300000000000000000000000000000000000D0 6 | :10F0400000000000000000000000000000000000C0 7 | :0CF05000000000000000000000000000B4 8 | :00000001FF 9 | -------------------------------------------------------------------------------- /nordicsemi/utility/tests/test_targets.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": 3 | [{ 4 | "id": 1, 5 | "drive": "d:\\", 6 | "serial_port": "COM7", 7 | "pca": "PCA10028", 8 | "segger_sn": "123123123123" 9 | }, 10 | { 11 | "id": 2, 12 | "drive": "e:\\", 13 | "serial_port": "COM8", 14 | "pca": "PCA10028", 15 | "segger_sn": "321321321312" 16 | }] 17 | } -------------------------------------------------------------------------------- /tests/bdd/README.md: -------------------------------------------------------------------------------- 1 | # bdd-tests 2 | 3 | ## dfu.feature 4 | 5 | The following environment variables can be exported to run the dfu.feature tests: 6 | 7 | * `PCA10056_0` and `PCA10056_1`: Serial number of Jlink devices. 8 | * `PCA10056_0`: Board used by `dfu usb-serial`, `dfu serial` and `dfu ble` tests. 9 | * `PCA10056_1`: Board used by `dfu ble` test. 10 | * `PCA10059`: Serial number of usb interface. 11 | * Used by trigger interface test. 12 | * `NRFUTIL`: Path to nrfutil. 13 | * Used to program the devices. 14 | 15 | If no devices are exported the first devices found will be used. 16 | If no nrfutil is exported the nrfutil installed will be used. 17 | -------------------------------------------------------------------------------- /tests/bdd/help_information.feature: -------------------------------------------------------------------------------- 1 | Feature: Help information 2 | Scenario: User types pkg generate --help 3 | Given user types 'nrfutil pkg generate --help' 4 | When user press enter 5 | Then output contains 'Generate a zip package for distribution to apps that support Nordic DFU' and exit code is 0 6 | 7 | Scenario: User does not type mandatory arguments 8 | Given user types 'nrfutil pkg generate' 9 | When user press enter 10 | Then output contains 'Error: Missing argument 'ZIPFILE'.' and exit code is 2 11 | 12 | Scenario: User types --help 13 | Given user types 'nrfutil --help' 14 | When user press enter 15 | Then output contains 'Show this message and exit.' and exit code is 0 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nRF Util 2 | 3 | [![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) 4 | [![Latest version](https://img.shields.io/pypi/v/nrfutil.svg)](https://pypi.python.org/pypi/nrfutil) 5 | [![License](https://img.shields.io/pypi/l/nrfutil.svg)](https://pypi.python.org/pypi/nrfutil) 6 | 7 | ## DEPRECATION NOTICE 8 | This tool is deprecated. The feature set in this tool is available through a new tool with the same name. 9 | If you need the feature set in this version, please install the new nrfutil from the [official page](https://www.nordicsemi.com/Products/Development-tools/nrf-util). 10 | 11 | 12 | ## Intro 13 | nRF Util is a Python package and command-line utility that supports Device Firmware Updates (DFU) and cryptographic functionality. 14 | 15 | ![screenshot](screenshot.gif) 16 | 17 | ## Documentation 18 | 19 | See the [InfoCenter](https://infocenter.nordicsemi.com/topic/ug_nrfutil/UG/nrfutil/nrfutil_intro.html) pages for information on how to install and use nRF Util. 20 | 21 | ## Feedback 22 | 23 | Please report issues on the [DevZone](https://devzone.nordicsemi.com) portal. 24 | 25 | ## Contributing 26 | 27 | Feel free to propose changes by creating a pull request. 28 | 29 | If you plan to make any non-trivial changes, please start out small and ask seek an agreement before putting too much work in it. A pull request can be declined if it does not fit well within the current product roadmap. 30 | 31 | In order to accept your pull request, we need you to sign our Contributor License Agreement (CLA). You will see instructions for doing this after having submitted your first pull request. 32 | 33 | ## License 34 | 35 | See the [LICENSE](LICENSE) file for details. 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2016 Nordic Semiconductor ASA 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | contributors to this software may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | 4. This software must only be used in or with a processor manufactured by Nordic 20 | Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | is used in combination with a processor manufactured by Nordic Semiconductor. 22 | 23 | 5. Any software provided in binary or object form under this license must not be 24 | reverse engineered, decompiled, modified and/or disassembled. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | 37 | -------------------------------------------------------------------------------- /nrfutil.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | 3 | import importlib 4 | import os 5 | import sys 6 | 7 | block_cipher = None 8 | 9 | module = importlib.import_module("pc_ble_driver_py") 10 | mod_dir = os.path.dirname(module.__file__) 11 | shlib_dir = os.path.join(os.path.abspath(mod_dir), 'lib') 12 | hex_dir = os.path.join(os.path.abspath(mod_dir), 'hex') 13 | 14 | datas = [(shlib_dir, 'lib'), (hex_dir, 'pc_ble_driver_py/hex')] 15 | # ant is relevant for windows only 16 | if (sys.platform == "win32"): 17 | module_ant = importlib.import_module('antlib') 18 | mod_dir_ant = os.path.dirname(module_ant.__file__) 19 | shlib_dir_ant = os.path.abspath(mod_dir_ant) 20 | datas.append((shlib_dir_ant, 'antlib')) 21 | 22 | nrfutil_path = os.path.dirname(os.path.abspath(SPEC)) 23 | datas.append((os.path.join(nrfutil_path, "libusb", "x64", "libusb-1.0.dylib"), os.path.join("libusb", "x64"))) 24 | datas.append((os.path.join(nrfutil_path, "libusb", "x86", "libusb-1.0.dll"), os.path.join("libusb", "x86"))) 25 | datas.append((os.path.join(nrfutil_path, "libusb", "x64", "libusb-1.0.dll"), os.path.join("libusb", "x64"))) 26 | datas.append((os.path.join(nrfutil_path, "nordicsemi", "zigbee", "hex", "ota.hex"), 27 | os.path.join("nordicsemi", "zigbee", "hex"))) 28 | datas.append((os.path.join(nrfutil_path, "nordicsemi", "thread", "hex", "ncp.hex"), 29 | os.path.join("nordicsemi", "thread", "hex"))) 30 | 31 | a = Analysis(['nordicsemi/__main__.py'], 32 | binaries=None, 33 | datas=datas, 34 | hiddenimports=['usb1'], 35 | hookspath=[], 36 | runtime_hooks=[], 37 | excludes=[], 38 | win_no_prefer_redirects=False, 39 | win_private_assemblies=False, 40 | cipher=block_cipher) 41 | 42 | pyz = PYZ(a.pure, a.zipped_data, 43 | cipher=block_cipher) 44 | 45 | exe = EXE(pyz, 46 | a.scripts, 47 | a.binaries, 48 | a.zipfiles, 49 | a.datas, 50 | name='nrfutil', 51 | debug=False, 52 | strip=False, 53 | upx=True, 54 | console=True) 55 | -------------------------------------------------------------------------------- /nordicsemi/dfu/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | """Package marker file.""" 39 | -------------------------------------------------------------------------------- /nordicsemi/dfu/dfu-cc.proto: -------------------------------------------------------------------------------- 1 | package dfu; 2 | 3 | // Version 0.1 4 | 5 | // Definition of enums and types 6 | enum OpCode { 7 | RESET = 0; 8 | INIT = 1; 9 | } 10 | 11 | enum FwType { 12 | APPLICATION = 0; // default, compatible with proto3 13 | SOFTDEVICE = 1; 14 | BOOTLOADER = 2; 15 | SOFTDEVICE_BOOTLOADER = 3; 16 | EXTERNAL_APPLICATION = 4; 17 | } 18 | 19 | enum HashType { 20 | NO_HASH = 0; 21 | CRC = 1; 22 | SHA128 = 2; 23 | SHA256 = 3; 24 | SHA512 = 4; 25 | } 26 | 27 | enum ValidationType { 28 | NO_VALIDATION = 0; 29 | VALIDATE_GENERATED_CRC = 1; 30 | VALIDATE_SHA256 = 2; 31 | VALIDATE_ECDSA_P256_SHA256 = 3; 32 | } 33 | 34 | message Hash { 35 | required HashType hash_type = 1; 36 | required bytes hash = 2; 37 | } 38 | 39 | message BootValidation { 40 | required ValidationType type = 1; 41 | required bytes bytes = 2; 42 | } 43 | 44 | // Commands data 45 | message InitCommand { 46 | optional uint32 fw_version = 1; 47 | optional uint32 hw_version = 2; 48 | repeated uint32 sd_req = 3 [packed = true]; // packed option is default in proto3 49 | optional FwType type = 4; 50 | 51 | optional uint32 sd_size = 5; 52 | optional uint32 bl_size = 6; 53 | optional uint32 app_size = 7; 54 | 55 | optional Hash hash = 8; 56 | 57 | optional bool is_debug = 9 [default = false]; 58 | 59 | repeated BootValidation boot_validation = 10; 60 | } 61 | 62 | message ResetCommand { 63 | required uint32 timeout = 1; 64 | } 65 | 66 | // Command type 67 | message Command { 68 | optional OpCode op_code = 1; 69 | optional InitCommand init = 2; 70 | optional ResetCommand reset = 3; 71 | } 72 | 73 | // Signed command types 74 | enum SignatureType { 75 | ECDSA_P256_SHA256 = 0; 76 | ED25519 = 1; 77 | } 78 | 79 | message SignedCommand { 80 | required Command command = 1; 81 | required SignatureType signature_type = 2; 82 | required bytes signature = 3; 83 | } 84 | 85 | // Parent packet type 86 | message Packet { 87 | optional Command command = 1; 88 | optional SignedCommand signed_command = 2; 89 | } 90 | -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | """Package marker file.""" 39 | -------------------------------------------------------------------------------- /nordicsemi/lister/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | """Package marker file.""" 39 | -------------------------------------------------------------------------------- /nordicsemi/utility/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | """Package marker file.""" 39 | -------------------------------------------------------------------------------- /nordicsemi/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | """Package implementing Zigbee OTA DFU functionality.""" 39 | -------------------------------------------------------------------------------- /nordicsemi/zigbee/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | """Package with Zigbee OTA file functionality.""" 39 | -------------------------------------------------------------------------------- /nordicsemi/zigbee/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | """ Tests for Zigbee Production Config functionality. """ 39 | -------------------------------------------------------------------------------- /nordicsemi/version.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | """ Version definition for nrfutil. """ 39 | 40 | NRFUTIL_VERSION = "6.1.7" 41 | -------------------------------------------------------------------------------- /nordicsemi/thread/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | """Package marker file.""" 39 | 40 | import sys 41 | from os.path import dirname 42 | 43 | sys.path.append(dirname(__file__)) 44 | -------------------------------------------------------------------------------- /nordicsemi/lister/lister_backend.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019 Nordic Semiconductor ASA 2 | # All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without modification, 5 | # are permitted provided that the following conditions are met: 6 | # 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | # 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 11 | # list of conditions and the following disclaimer in the documentation and/or 12 | # other materials provided with the distribution. 13 | # 14 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 15 | # contributors to this software may be used to endorse or promote products 16 | # derived from this software without specific prior written permission. 17 | # 18 | # 4. This software must only be used in or with a processor manufactured by Nordic 19 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 20 | # is used in combination with a processor manufactured by Nordic Semiconductor. 21 | # 22 | # 5. Any software provided in binary or object form under this license must not be 23 | # reverse engineered, decompiled, modified and/or disassembled. 24 | # 25 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 29 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 32 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | from abc import ABC, abstractmethod 37 | 38 | 39 | class AbstractLister(ABC): 40 | @abstractmethod 41 | def enumerate(self): 42 | """ 43 | Enumerate all usb devices 44 | """ 45 | pass 46 | -------------------------------------------------------------------------------- /tests/bdd/environment.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import logging 39 | 40 | 41 | logging.basicConfig(format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', 42 | datefmt='%m-%d %H:%M:%S ', level=logging.DEBUG) 43 | 44 | 45 | def before_all(context): 46 | pass 47 | -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/firmwares/bl_settings_v2_nrf52.hex: -------------------------------------------------------------------------------- 1 | :020000040007F3 2 | :10F00000A9E4142902000000010000000100000032 3 | :10F010000000000000000000B4480100BFEE72F2E2 4 | :10F0200001000000000000000000000000000000DF 5 | :10F03000000000005041020000000000000000003D 6 | :10F0400000000000000000000000000000000000C0 7 | :10F0500000000000000000000000000000000000B0 8 | :10F0600000000000000000000000000000000000A0 9 | :10F070000000000000000000000000000000000090 10 | :10F080000000000000000000000000000000000080 11 | :10F090000000000000000000000000000000000070 12 | :10F0A0000000000000000000000000000000000060 13 | :10F0B0000000000000000000000000000000000050 14 | :10F0C0000000000000000000000000000000000040 15 | :10F0D0000000000000000000000000000000000030 16 | :10F0E0000000000000000000000000000000000020 17 | :10F0F0000000000000000000000000000000000010 18 | :10F1000000000000000000000000000000000000FF 19 | :10F1100000000000000000000000000000000000EF 20 | :10F1200000000000000000000000000000000000DF 21 | :10F1300000000000000000000000000000000000CF 22 | :10F1400000000000000000000000000000000000BF 23 | :10F1500000000000000000000000000000000000AF 24 | :10F16000000000000000000000000000000000009F 25 | :10F17000000000000000000000000000000000008F 26 | :10F18000000000000000000000000000000000007F 27 | :10F19000000000000000000000000000000000006F 28 | :10F1A000000000000000000000000000000000005F 29 | :10F1B000000000000000000000000000000000004F 30 | :10F1C000000000000000000000000000000000003F 31 | :10F1D000000000000000000000000000000000002F 32 | :10F1E000000000000000000000000000000000001F 33 | :10F1F000000000000000000000000000000000000F 34 | :10F2000000000000000000000000000000000000FE 35 | :10F2100000000000000000000000000000000000EE 36 | :10F2200000000000000000000000000000000000DE 37 | :10F2300000000000000000000000000000000000CE 38 | :10F2400000000000000000000000000000000000BE 39 | :10F2500000000000000000000000000055557B4643 40 | :10F2600001CEBD005B0000000000000000000000B7 41 | :10F27000000000000000000000000000000000008E 42 | :10F28000000000000000000000000000000000007E 43 | :10F29000000000000000000000000000000000006E 44 | :10F2A0000001BFEE72F2000000000000000000004C 45 | :10F2B000000000000000000000000000000000004E 46 | :10F2C000000000000000000000000000000000003E 47 | :10F2D000000000000000000000000000000000002E 48 | :10F2E000000000000000000000000000000000001E 49 | :10F2F000000000000000000000000000000000000E 50 | :10F3000000000000000000000000000000000000FD 51 | :10F3100000000000000000000000000000000000ED 52 | :03F32000000000EA 53 | :00000001FF 54 | -------------------------------------------------------------------------------- /tests/bdd/dfu.feature: -------------------------------------------------------------------------------- 1 | Feature: Perform DFU 2 | Scenario: USB serial DFU completes without error 3 | Given the user wants to perform dfu usb-serial 4 | And using package tests\resources\blinky_mbr_sdk160.zip 5 | And nrfjprog tests\resources\secure_bootloader_usb_mbr_pca10056_debug_sdk160.hex for usb-serial PCA10056_0 6 | Then perform dfu using nrfutil NRFUTIL 7 | 8 | Scenario: Serial DFU completes without error 9 | Given the user wants to perform dfu serial 10 | And using package tests\resources\blinky_mbr_sdk160.zip 11 | And nrfjprog tests\resources\secure_bootloader_uart_mbr_pca10056_debug_sdk160.hex for serial PCA10056_0 12 | Then perform dfu using nrfutil NRFUTIL 13 | 14 | Scenario: BLE DFU completes without error 15 | Given the user wants to perform dfu ble 16 | And using package tests\resources\hrs_application_s140_sdk160.zip 17 | And option --conn-ic-id NRF52 18 | And option --name DfuTarg 19 | And nrfjprog tests\resources\secure_bootloader_ble_s140_pca10056_debug_sdk160.hex for ble PCA10056_0 20 | And nrfjprog connectivity for serial PCA10056_1 21 | Then perform dfu using nrfutil NRFUTIL 22 | 23 | # DFU trigger tests runs twice in case the device was already in bootloader before starting. 24 | # The test will fail if the device is not in bootloader mode or is running an application without trigger interface. 25 | @unstable 26 | Scenario: Enter bootloader and perform DFU using trigger interface 27 | Given the user wants to perform dfu usb-serial 28 | And using package connectivity_usb 29 | And -snr PCA10059 30 | Then perform dfu using nrfutil NRFUTIL 31 | Then perform dfu using nrfutil NRFUTIL 32 | 33 | # TODO : This does currently not work as the PCA10056 through usb does not 34 | # enter bootloader after getting flashed with connectivity software. 35 | # 36 | # -- NB! -- : The above test for PCA10059 is changed to PCA10056 for robustnes. 37 | # DFU trigger tests runs twice in case the device was already in bootloader before starting. 38 | # The test will fail if the device is not in bootloader mode or is running an application without trigger interface. 39 | #Scenario: Enter bootloader and perform DFU using trigger interface 40 | # Given the user wants to perform dfu usb-serial 41 | # And using package connectivity_usb 42 | # And nrfjprog tests\resources\open_bootloader_usb_mbr_pca10059_debug_sdk160.hex for usb-serial PCA10056_0 43 | # Then perform dfu twice with port change 44 | -------------------------------------------------------------------------------- /nordicsemi/dfu/model.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | from enum import Enum 39 | 40 | 41 | class HexType(Enum): 42 | SOFTDEVICE = 1 43 | BOOTLOADER = 2 44 | SD_BL = 3 45 | APPLICATION = 4 46 | EXTERNAL_APPLICATION = 5 47 | 48 | 49 | class FirmwareKeys(Enum): 50 | ENCRYPT = 1 51 | FIRMWARE_FILENAME = 2 52 | BIN_FILENAME = 3 53 | DAT_FILENAME = 4 54 | INIT_PACKET_DATA = 5 55 | SD_SIZE = 6 56 | BL_SIZE = 7 57 | BOOT_VALIDATION_TYPE = 8 58 | -------------------------------------------------------------------------------- /nordicsemi/dfu/crc16.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2019 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | def calc_crc16(binary_data: bytes, crc=0xffff): 39 | """ 40 | Calculates CRC16 on binary_data 41 | 42 | :param int crc: CRC value to start calculation with 43 | :param bytearray binary_data: Array with data to run CRC16 calculation on 44 | :return int: Calculated CRC value of binary_data 45 | """ 46 | 47 | for b in binary_data: 48 | crc = (crc >> 8 & 0x00FF) | (crc << 8 & 0xFF00) 49 | crc ^= ord(b) 50 | crc ^= (crc & 0x00FF) >> 4 51 | crc ^= (crc << 8) << 4 52 | crc ^= ((crc & 0x00FF) << 4) << 1 53 | return crc & 0xFFFF 54 | -------------------------------------------------------------------------------- /tests/bdd/steps/util.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | from random import randint 39 | import time 40 | import sys 41 | import math 42 | 43 | ON_POSIX = 'posix' in sys.builtin_module_names 44 | 45 | 46 | def process_pipe(pipe, queue): 47 | for line in iter(pipe.readline, b''): 48 | queue.put({'type': 'output', 'data': line}) 49 | 50 | pipe.close() 51 | queue.put({'type': 'output_terminated'}) 52 | 53 | 54 | def kill_process(target): 55 | if 'proc' in target: 56 | target['proc'].kill() 57 | 58 | # Close file descriptors 59 | target['proc'].stdin.close() 60 | time.sleep(1) # Let the application terminate before proceeding 61 | 62 | 63 | def kill_processes(context): 64 | targets = context.target_registry.get_all() 65 | 66 | for target in targets: 67 | kill_process(target) 68 | -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | """ 2 | The tests seems to work with `python -m unittest`, but not by being called directly from the CLI 3 | The setUp is called twice, and crashes when being asked to do a `cd ./tests` for a second time 4 | Look into a cleanup function 5 | 6 | The behavior is inconsistent between 3.9 and 3.7 (3.7 fails) 7 | """ 8 | import os 9 | import unittest 10 | from click.testing import CliRunner 11 | from nordicsemi import __main__ 12 | 13 | 14 | class TestManifest(unittest.TestCase): 15 | runner = CliRunner() 16 | cli = __main__.cli 17 | original_path = os.path.abspath(os.path.curdir) 18 | 19 | def setUp(self): 20 | script_abspath = os.path.abspath(__file__) 21 | script_dirname = os.path.dirname(script_abspath) 22 | self.original_path = os.path.abspath(os.path.curdir) # Make it possible to go back 23 | os.chdir(script_dirname) 24 | 25 | def tearDown(self) -> None: 26 | """ 27 | Go back to the old dir 28 | """ 29 | os.chdir(self.original_path) 30 | def test_pkg_gen(self): 31 | result = self.runner.invoke(self.cli, 32 | ['pkg', 'generate', 33 | '--application', 'resources/dfu_test_app_hrm_s130.hex', 34 | '--hw-version', '52', '--sd-req', '0', '--application-version', 35 | '0', '--sd-id', '0x008C', 'test.zip']) 36 | self.assertIsNone(result.exception) 37 | 38 | def test_dfu_ble_address(self): 39 | argumentList = ['dfu', 'ble', '-ic', 'NRF52', '-p', 'port', '-pkg', 40 | 'resources/test_package.zip', '--address'] 41 | 42 | address = 'AABBCC112233' 43 | result = self.runner.invoke(self.cli, argumentList + [address]) 44 | self.assertTrue('Error: Invalid value for address' not in result.output) 45 | self.assertTrue('Board not found' in str(result.exception)) 46 | 47 | address = 'AA:BB:CC:11:22:33' 48 | result = self.runner.invoke(self.cli, argumentList + [address]) 49 | self.assertTrue('Error: Invalid value for address' not in result.output) 50 | self.assertTrue('Board not found' in str(result.exception)) 51 | 52 | address = 'AABBCC11223' 53 | result = self.runner.invoke(self.cli, argumentList + [address]) 54 | self.assertTrue('Error: Invalid value for address' in result.output) 55 | self.assertIsInstance(result.exception, SystemExit) 56 | self.assertEqual(result.exception.code, SystemExit(2).code) 57 | 58 | address = 'AABBCC1122334' 59 | result = self.runner.invoke(self.cli, argumentList + [address]) 60 | self.assertTrue('Error: Invalid value for address' in result.output) 61 | self.assertIsInstance(result.exception, SystemExit) 62 | self.assertEqual(result.exception.code, SystemExit(2).code) 63 | 64 | 65 | if __name__ == '__main__': 66 | unittest.main() 67 | -------------------------------------------------------------------------------- /nordicsemi/thread/ncp_flasher.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | import os 37 | import re 38 | import subprocess 39 | from pc_ble_driver_py.ble_driver import Flasher 40 | 41 | class NCPFlasher(Flasher): 42 | ERROR_CODE_VERIFY_ERROR = 55 43 | 44 | def __init__(self, serial_port = None, snr = None): 45 | super().__init__(serial_port, snr) 46 | 47 | def __get_hex_path(self): 48 | return os.path.join(os.path.dirname(__file__), 'hex', 'ncp.hex') 49 | 50 | def verify(self, path): 51 | args = ['--verify', path] 52 | return self.call_cmd(args) 53 | 54 | def fw_check(self): 55 | try: 56 | result = self.verify(self.__get_hex_path()) 57 | except subprocess.CalledProcessError as e: 58 | if (e.returncode == NCPFlasher.ERROR_CODE_VERIFY_ERROR): 59 | return False 60 | else: 61 | raise 62 | return (re.search(b'^Verified OK.$', result, re.MULTILINE) is not None) 63 | 64 | def fw_flash(self): 65 | self.erase() 66 | self.program(self.__get_hex_path()) 67 | -------------------------------------------------------------------------------- /tests/bdd/steps/help_information_steps.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import logging 39 | import os 40 | 41 | from click.testing import CliRunner 42 | from behave import then, given, when 43 | 44 | from nordicsemi.__main__ import cli, int_as_text_to_int 45 | 46 | 47 | logger = logging.getLogger(__file__) 48 | 49 | STDOUT_TEXT_WAIT_TIME = 50 # Number of seconds to wait for expected output from stdout 50 | 51 | 52 | @given('user types \'{command}\'') 53 | def step_impl(context, command): 54 | args = command.split(' ') 55 | assert args[0] == 'nrfutil' 56 | 57 | exec_args = args[1:] 58 | runner = CliRunner() 59 | context.runner = runner 60 | context.args = exec_args 61 | 62 | 63 | @when('user press enter') 64 | def step_impl(context): 65 | pass 66 | 67 | 68 | @then('output contains \'{stdout_text}\' and exit code is {exit_code}') 69 | def step_impl(context, stdout_text, exit_code): 70 | result = context.runner.invoke(cli, context.args) 71 | logger.debug("exit_code: %s, output: \'%s\'", result.exit_code, result.output) 72 | assert result.exit_code == int_as_text_to_int(exit_code) 73 | assert result.output is not None 74 | assert result.output.find(stdout_text) >= 0 75 | -------------------------------------------------------------------------------- /nordicsemi/lister/enumerated_device.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2019 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import sys 39 | 40 | 41 | class EnumeratedDevice: 42 | def __init__(self, vendor_id, product_id, serial_number, com_ports): 43 | self.vendor_id = vendor_id 44 | self.product_id = product_id 45 | self.serial_number = serial_number 46 | self.com_ports = [] 47 | for port in com_ports: 48 | self.add_com_port(port) 49 | 50 | def add_com_port(self, port): 51 | if sys.platform == 'darwin': 52 | # Ports are sometimes listed under /dev/cu on MacOS, 53 | # but pyserial can only open /dev/tty* ports. 54 | port = port.replace('/dev/cu.', '/dev/tty.') 55 | self.com_ports.append(port) 56 | 57 | def has_com_port(self, checkPort): 58 | for port in self.com_ports: 59 | if port.lower() == checkPort.lower(): 60 | return True 61 | return False 62 | 63 | def get_first_available_com_port(self): 64 | return self.com_ports[0] 65 | 66 | def __repr__(self): 67 | return "{{\nvendor_id: {}\nproduct_id: {}\nserial_number: {}\nCOM: {}\n}}"\ 68 | .format(self.vendor_id, self.product_id, self.serial_number, self.com_ports) 69 | -------------------------------------------------------------------------------- /nordicsemi/lister/windows/constants.py: -------------------------------------------------------------------------------- 1 | """ 2 | MIT License 3 | 4 | Copyright (c) 2016 gwangyi 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | """ 24 | 25 | import enum 26 | from .structures import DevicePropertyKey 27 | 28 | 29 | # noinspection SpellCheckingInspection 30 | class DiOpenDeviceInfo(enum.IntEnum): 31 | """DIOD_xxx constants 32 | """ 33 | InheritClassDrvs = 2 34 | CancelRemove = 4 35 | 36 | 37 | # noinspection SpellCheckingInspection 38 | class DiGetClassDevsFlags(enum.IntEnum): 39 | """DIGCF_xxx constants 40 | """ 41 | Default = 0x00000001 42 | Present = 0x00000002, 43 | AllClasses = 0x00000004, 44 | Profile = 0x00000008, 45 | DeviceInterface = 0x00000010, 46 | 47 | 48 | # noinspection SpellCheckingInspection 49 | class DevicePropertyKeys: 50 | """DEVPKEY_xxx constants""" 51 | NAME = DevicePropertyKey('{b725f130-47ef-101a-a5f1-02608c9eebac}', 10, 'DEVPKEY_NAME') 52 | Numa_Proximity_Domain = DevicePropertyKey('{540b947e-8b40-45bc-a8a2-6a0b894cbda2}', 1, 53 | 'DEVPKEY_Numa_Proximity_Domain') 54 | 55 | # noinspection SpellCheckingInspection 56 | class Device: 57 | """DEVPKEY_Device_xxx constants""" 58 | ContainerId = DevicePropertyKey('{8c7ed206-3f8a-4827-b3ab-ae9e1faefc6c}', 2, 59 | 'DEVPKEY_Device_ContainerId') 60 | DeviceAddress = DevicePropertyKey('{a45c254e-df1c-4efd-8020-67d146a850e0}', 30, 61 | 'DEVPKEY_Device_Address') 62 | 63 | # noinspection SpellCheckingInspection 64 | DIGCF_DEFAULT = DiGetClassDevsFlags.Default 65 | # noinspection SpellCheckingInspection 66 | DIGCF_PRESENT = DiGetClassDevsFlags.Present 67 | # noinspection SpellCheckingInspection 68 | DIGCF_ALLCLASSES = DiGetClassDevsFlags.AllClasses 69 | # noinspection SpellCheckingInspection 70 | DIGCF_PROFILE = DiGetClassDevsFlags.Profile 71 | # noinspection SpellCheckingInspection 72 | DIGCF_DEVICEINTERFACE = DiGetClassDevsFlags.DeviceInterface 73 | 74 | # noinspection SpellCheckingInspection 75 | DIOD_INHERIT_CLASSDRVS = DiOpenDeviceInfo.InheritClassDrvs 76 | # noinspection SpellCheckingInspection 77 | DIOD_CANCEL_REMOVE = DiOpenDeviceInfo.CancelRemove 78 | 79 | # noinspection SpellCheckingInspection 80 | DEVPKEY = DevicePropertyKeys 81 | DEVPKEY_Device_ContainerId = DevicePropertyKeys.Device.ContainerId 82 | -------------------------------------------------------------------------------- /nordicsemi/lister/unix/unix_lister.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2019 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import sys 39 | from nordicsemi.lister.lister_backend import AbstractLister 40 | 41 | if 'linux' in sys.platform or sys.platform == 'darwin': 42 | import serial.tools.list_ports 43 | from nordicsemi.lister.enumerated_device import EnumeratedDevice 44 | 45 | 46 | def create_id_string(sno, PID, VID): 47 | return "{}-{}-{}".format(sno, PID, VID) 48 | 49 | 50 | class UnixLister(AbstractLister): 51 | 52 | def enumerate(self): 53 | device_identities = {} 54 | available_ports = serial.tools.list_ports.comports() 55 | 56 | for port in available_ports: 57 | if port.pid is None or port.vid is None or port.serial_number is None: 58 | continue 59 | 60 | serial_number = port.serial_number 61 | product_id = hex(port.pid).upper()[2:] 62 | vendor_id = hex(port.vid).upper()[2:] 63 | com_port = port.device 64 | 65 | id = create_id_string(serial_number, product_id, vendor_id) 66 | if id in device_identities: 67 | device_identities[id].add_com_port(com_port) 68 | else: 69 | device_identities[id] = EnumeratedDevice(vendor_id, product_id, serial_number, [com_port]) 70 | 71 | return [device for device in list(device_identities.values())] 72 | -------------------------------------------------------------------------------- /nordicsemi/utility/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | # Copyright (c) 2015, Nordic Semiconductor 38 | # All rights reserved. 39 | # 40 | # Redistribution and use in source and binary forms, with or without 41 | # modification, are permitted provided that the following conditions are met: 42 | # 43 | # * Redistributions of source code must retain the above copyright notice, this 44 | # list of conditions and the following disclaimer. 45 | # 46 | # * Redistributions in binary form must reproduce the above copyright notice, 47 | # this list of conditions and the following disclaimer in the documentation 48 | # and/or other materials provided with the distribution. 49 | # 50 | # * Neither the name of Nordic Semiconductor ASA nor the names of its 51 | # contributors may be used to endorse or promote products derived from 52 | # this software without specific prior written permission. 53 | # 54 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 55 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 57 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 58 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 60 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 61 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 62 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 63 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.s 64 | 65 | """Package marker file.""" 66 | -------------------------------------------------------------------------------- /nordicsemi/lister/device_lister.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2019 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import sys 39 | from nordicsemi.lister.windows.lister_win32 import Win32Lister 40 | from nordicsemi.lister.unix.unix_lister import UnixLister 41 | 42 | 43 | class DeviceLister: 44 | def __init__(self): 45 | if sys.platform == 'win32': 46 | self.lister_backend = Win32Lister() 47 | elif 'linux' in sys.platform: 48 | self.lister_backend = UnixLister() 49 | elif sys.platform == 'darwin': 50 | self.lister_backend = UnixLister() 51 | else: 52 | self.lister_backend = None 53 | 54 | def enumerate(self): 55 | if self.lister_backend: 56 | return self.lister_backend.enumerate() 57 | return [] 58 | 59 | def get_device(self, get_all=False, **kwargs): 60 | devices = self.enumerate() 61 | matching_devices = [] 62 | for dev in devices: 63 | if "vendor_id" in kwargs and kwargs["vendor_id"].lower() != dev.vendor_id.lower(): 64 | continue 65 | if "product_id" in kwargs and kwargs["product_id"].lower() != dev.product_id.lower(): 66 | continue 67 | if "serial_number" in kwargs and (kwargs["serial_number"].lower().lstrip('0') != 68 | dev.serial_number.lower().lstrip('0')): 69 | continue 70 | if "com" in kwargs and not dev.has_com_port(kwargs["com"]): 71 | continue 72 | 73 | matching_devices.append(dev) 74 | 75 | if not get_all: 76 | if len(matching_devices) == 0: 77 | return 78 | return matching_devices[0] 79 | return matching_devices 80 | -------------------------------------------------------------------------------- /tests/protobuf/__main__.py: -------------------------------------------------------------------------------- 1 | 2 | import unittest 3 | import os, sys 4 | 5 | sys.path.append( 6 | os.path.normpath( 7 | os.path.join( 8 | os.path.dirname(__file__), '..', '..' 9 | ) 10 | ) 11 | ) 12 | 13 | from nordicsemi.dfu.init_packet_pb import InitPacketPB, HashTypes, DFUType, SigningTypes 14 | 15 | class TestStringMethods(unittest.TestCase): 16 | 17 | def test_construct_from_empty_string(self): 18 | """ 19 | Raises an error when trying to construct a init packet from an 20 | empty buffer 21 | """ 22 | 23 | self.assertRaisesRegex( 24 | RuntimeError, 25 | "app_size is not set. It must be set when type is APPLICATION", 26 | InitPacketPB, 27 | from_bytes = "") 28 | 29 | 30 | def test_construct_from_params(self): 31 | """ 32 | Gracefully constructs an init packet protobuffer from parameters without bytes 33 | """ 34 | 35 | i = InitPacketPB( 36 | from_bytes = None, 37 | 38 | hash_bytes = b"", 39 | hash_type = HashTypes.SHA256, 40 | dfu_type = DFUType.APPLICATION, 41 | is_debug=False, 42 | fw_version=0xffffffff, 43 | hw_version=0xffffffff, 44 | sd_size=0, 45 | app_size=1234, 46 | bl_size=0, 47 | sd_req=[0xffffffff] 48 | ) 49 | 50 | protobuf_bytes = i.get_init_command_bytes() # bytes only for the InitCommand 51 | hex_bytes = protobuf_bytes.encode('hex_codec') 52 | 53 | self.assertEqual(hex_bytes, "08ffffffff0f10ffffffff0f1a05ffffffff0f20002800" 54 | "300038d2094204080312004800") 55 | 56 | 57 | def test_construct_from_params_and_sign(self): 58 | """ 59 | Gracefully constructs an init packet protobuffer from parameters without bytes, 60 | then signs it 61 | """ 62 | 63 | i = InitPacketPB( 64 | from_bytes = None, 65 | 66 | hash_bytes = b"", 67 | hash_type = HashTypes.SHA256, 68 | dfu_type = DFUType.APPLICATION, 69 | is_debug=False, 70 | fw_version=0xffffffff, 71 | hw_version=0xffffffff, 72 | sd_size=0, 73 | app_size=1234, 74 | bl_size=0, 75 | sd_req=[0xffffffff] 76 | ) 77 | 78 | i.set_signature(b"signature bytes go here", SigningTypes.ECDSA_P256_SHA256) 79 | 80 | protobuf_bytes = i.get_init_packet_pb_bytes() # Bytes for the whole Packet 81 | hex_bytes = protobuf_bytes.encode('hex_codec') 82 | 83 | self.assertEqual(hex_bytes, "12450a280801122408ffffffff0f10ffffffff0f1a" 84 | "05ffffffff0f20002800300038d209420408031200480010001a177369676e61747572" 85 | "6520627974657320676f2068657265") 86 | 87 | 88 | def test_construct_from_params_and_not_sign(self): 89 | """ 90 | Gracefully constructs an init packet protobuffer from parameters without bytes, 91 | skipping the signature process 92 | """ 93 | 94 | i = InitPacketPB( 95 | from_bytes = None, 96 | 97 | hash_bytes = b"", 98 | hash_type = HashTypes.SHA256, 99 | dfu_type = DFUType.APPLICATION, 100 | is_debug=False, 101 | fw_version=0xffffffff, 102 | hw_version=0xffffffff, 103 | sd_size=0, 104 | app_size=1234, 105 | bl_size=0, 106 | sd_req=[0xffffffff] 107 | ) 108 | 109 | protobuf_bytes = i.get_init_packet_pb_bytes() # Bytes for the whole Packet 110 | hex_bytes = protobuf_bytes.encode('hex_codec') 111 | 112 | self.assertEqual(hex_bytes, "0a280801122408ffffffff0f10ffffffff0f1a" 113 | "05ffffffff0f20002800300038d2094204080312004800") 114 | 115 | 116 | 117 | if __name__ == '__main__': 118 | unittest.main() 119 | 120 | -------------------------------------------------------------------------------- /tests/bdd/steps/common_steps.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | from queue import Queue 39 | import logging 40 | import os 41 | import subprocess 42 | from threading import Thread 43 | from util import process_pipe, ON_POSIX 44 | 45 | logger = logging.getLogger(__file__) 46 | 47 | 48 | class Exec: 49 | def __init__(self, exec_path): 50 | self.path = exec_path 51 | self.name = os.path.basename(self.path) 52 | self.dir = os.path.dirname(self.path) 53 | self.out_queue = Queue() 54 | self.stdout_thread = None 55 | self.stderr_thread = None 56 | self.process = None 57 | 58 | def execute(self, args, working_directory): 59 | args = args 60 | shell = False 61 | 62 | args.insert(0, self.path) 63 | 64 | self.process = subprocess.Popen(args=args, 65 | bufsize=0, 66 | cwd=working_directory, 67 | executable=self.path, 68 | stdin=subprocess.PIPE, 69 | stdout=subprocess.PIPE, 70 | stderr=subprocess.PIPE, 71 | close_fds=ON_POSIX, 72 | universal_newlines=True, 73 | shell=shell) 74 | 75 | if self.process.poll() is not None: 76 | raise Exception("Error starting {} application {}, return code is {}".format( 77 | self.path, 78 | self.process.poll())) 79 | 80 | self.stdout_thread = Thread(target=process_pipe, args=(self.process.stdout, self.out_queue)) 81 | self.stdout_thread.start() 82 | 83 | self.stderr_thread = Thread(target=process_pipe, args=(self.process.stderr, self.out_queue)) 84 | self.stderr_thread.start() 85 | 86 | def kill(self): 87 | if self.process is not None: 88 | self.process.kill() 89 | self.process.stdin.close() 90 | 91 | 92 | def get_resources_path(): 93 | return os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "resources") 94 | -------------------------------------------------------------------------------- /nordicsemi/thread/dfu_thread.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | import tempfile 38 | import os.path 39 | import logging 40 | import piccata 41 | 42 | from nordicsemi.dfu.package import Package 43 | from nordicsemi.thread.dfu_server import ThreadDfuServer 44 | 45 | logger = logging.getLogger(__name__) 46 | 47 | def _get_manifest_items(manifest): 48 | import inspect 49 | result = [] 50 | 51 | for key, value in inspect.getmembers(manifest): 52 | if (key.startswith('__')): 53 | continue 54 | if not value: 55 | continue 56 | if inspect.ismethod(value) or inspect.isfunction(value): 57 | continue 58 | 59 | result.append((key, value)) 60 | 61 | return result 62 | 63 | def _get_file_names(manifest): 64 | data_attrs = _get_manifest_items(manifest) 65 | if (len(data_attrs) > 1): 66 | raise RuntimeError("More than one image present in manifest") 67 | data_attrs = data_attrs[0] 68 | firmware = data_attrs[1] 69 | logger.info("Image type {} found".format(data_attrs[0])) 70 | return firmware.dat_file, firmware.bin_file 71 | 72 | def create_dfu_server(transport, zip_file_path, opts): 73 | ''' 74 | Create a DFU server instance. 75 | :param transpoort: A transport to be used. 76 | :param zip_file_path: A path to the firmware package. 77 | :param opts: Optional parameters: 78 | mcast_dfu: An information if multicast DFU is enabled. 79 | rate: Multicast block transfer rate, in blocks per second 80 | reset_suppress: A delay before sending multicast reset command (in milliseconds). -1 means that no reset will be sent. 81 | ''' 82 | temp_dir = tempfile.mkdtemp(prefix="nrf_dfu_") 83 | unpacked_zip_path = os.path.join(temp_dir, 'unpacked_zip') 84 | manifest = Package.unpack_package(zip_file_path, unpacked_zip_path) 85 | 86 | protocol = piccata.core.Coap(transport) 87 | transport.register_receiver(protocol) 88 | 89 | init_file, image_file = _get_file_names(manifest) 90 | 91 | with open(os.path.join(unpacked_zip_path, init_file), 'rb') as f: 92 | init_data = f.read() 93 | with open(os.path.join(unpacked_zip_path, image_file), 'rb') as f: 94 | image_data = f.read() 95 | 96 | return ThreadDfuServer(protocol, init_data, image_data, opts) 97 | -------------------------------------------------------------------------------- /nordicsemi/utility/tests/test_target_registry.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import os 39 | import unittest 40 | from nordicsemi.utility.target_registry import TargetRegistry, EnvTargetDatabase 41 | from nordicsemi.utility.target_registry import FileTargetDatabase 42 | 43 | 44 | class TestTargetRegistry(unittest.TestCase): 45 | def setUp(self): 46 | script_abspath = os.path.abspath(__file__) 47 | script_dirname = os.path.dirname(script_abspath) 48 | os.chdir(script_dirname) 49 | 50 | # Setup the environment variables 51 | os.environ["NORDICSEMI_TARGET_1_SERIAL_PORT"] = "COM1" 52 | os.environ["NORDICSEMI_TARGET_1_PCA"] = "PCA10028" 53 | os.environ["NORDICSEMI_TARGET_1_DRIVE"] = "D:\\" 54 | os.environ["NORDICSEMI_TARGET_1_SEGGER_SN"] = "1231233333" 55 | 56 | os.environ["NORDICSEMI_TARGET_2_SERIAL_PORT"] = "COM2" 57 | os.environ["NORDICSEMI_TARGET_2_PCA"] = "PCA10028" 58 | os.environ["NORDICSEMI_TARGET_2_DRIVE"] = "E:\\" 59 | os.environ["NORDICSEMI_TARGET_2_SEGGER_SN"] = "3332222111" 60 | 61 | def test_get_targets_from_file(self): 62 | target_database = FileTargetDatabase("test_targets.json") 63 | target_repository = TargetRegistry(target_db=target_database) 64 | 65 | target = target_repository.find_one(target_id=1) 66 | assert target is not None 67 | assert target["drive"] == "d:\\" 68 | assert target["serial_port"] == "COM7" 69 | assert target["pca"] == "PCA10028" 70 | assert target["segger_sn"] == "123123123123" 71 | 72 | target = target_repository.find_one(target_id=2) 73 | assert target is not None 74 | assert target["drive"] == "e:\\" 75 | assert target["serial_port"] == "COM8" 76 | assert target["pca"] == "PCA10028" 77 | assert target["segger_sn"] == "321321321312" 78 | 79 | def test_get_targets_from_environment(self): 80 | target_database = EnvTargetDatabase() 81 | target_repository = TargetRegistry(target_db=target_database) 82 | 83 | target = target_repository.find_one(target_id=1) 84 | assert target is not None 85 | assert target["drive"] == "D:\\" 86 | assert target["serial_port"] == "COM1" 87 | assert target["pca"] == "PCA10028" 88 | assert target["segger_sn"] == "1231233333" 89 | 90 | target = target_repository.find_one(target_id=2) 91 | assert target is not None 92 | assert target["drive"] == "E:\\" 93 | assert target["serial_port"] == "COM2" 94 | assert target["pca"] == "PCA10028" 95 | assert target["segger_sn"] == "3332222111" 96 | 97 | 98 | if __name__ == '__main__': 99 | unittest.main() 100 | -------------------------------------------------------------------------------- /nordicsemi/utility/target_registry.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 - 2019 Nordic Semiconductor ASA 2 | # All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without modification, 5 | # are permitted provided that the following conditions are met: 6 | # 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | # 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 11 | # list of conditions and the following disclaimer in the documentation and/or 12 | # other materials provided with the distribution. 13 | # 14 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 15 | # contributors to this software may be used to endorse or promote products 16 | # derived from this software without specific prior written permission. 17 | # 18 | # 4. This software must only be used in or with a processor manufactured by Nordic 19 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 20 | # is used in combination with a processor manufactured by Nordic Semiconductor. 21 | # 22 | # 5. Any software provided in binary or object form under this license must not be 23 | # reverse engineered, decompiled, modified and/or disassembled. 24 | # 25 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 29 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 32 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | import re 37 | import os 38 | import json 39 | 40 | from abc import ABC, abstractmethod 41 | 42 | 43 | class TargetDatabase(ABC): 44 | @abstractmethod 45 | def get_targets(self): 46 | pass 47 | 48 | @abstractmethod 49 | def get_target(self, target_id): 50 | pass 51 | 52 | @abstractmethod 53 | def refresh(self): 54 | pass 55 | 56 | @staticmethod 57 | def find_target(targets, target_id): 58 | for target in targets: 59 | if target["id"] == target_id: 60 | return target 61 | 62 | return None 63 | 64 | 65 | class EnvTargetDatabase(TargetDatabase): 66 | def __init__(self): 67 | self.targets = None 68 | 69 | def get_targets(self): 70 | if self.targets is None: 71 | self.targets = [] 72 | 73 | for key, value in os.environ.items(): 74 | match = re.match( 75 | r"NORDICSEMI_TARGET_(?P\d+)_(?P[a-zA-Z_]+)", key 76 | ) 77 | 78 | if match: 79 | key_value = match.groupdict() 80 | if "key" in key_value and "target" in key_value: 81 | target_id = int(key_value["target"]) 82 | 83 | target = self.find_target(self.targets, target_id) 84 | 85 | if target is None: 86 | target = {"id": int(target_id)} 87 | self.targets.append(target) 88 | 89 | target[key_value["key"].lower()] = value 90 | 91 | return self.targets 92 | 93 | def refresh(self): 94 | self.targets = None 95 | 96 | def get_target(self, target_id): 97 | return self.find_target(self.get_targets(), target_id) 98 | 99 | 100 | class FileTargetDatabase(TargetDatabase): 101 | def __init__(self, filename): 102 | self.filename = filename 103 | self.targets = None 104 | 105 | def get_targets(self): 106 | if not self.targets: 107 | with open(self.filename, "r") as f: 108 | self.targets = json.load(f)["targets"] 109 | return self.targets 110 | 111 | def get_target(self, target_id): 112 | return self.find_target(self.get_targets(), target_id) 113 | 114 | def refresh(self): 115 | self.targets = None 116 | 117 | 118 | class TargetRegistry: 119 | def __init__(self, target_db=EnvTargetDatabase()): 120 | self.target_db = target_db 121 | 122 | def find_one(self, target_id=None): 123 | if target_id: 124 | return self.target_db.get_target(target_id) 125 | else: 126 | return None 127 | 128 | def get_all(self): 129 | return self.target_db.get_targets() 130 | -------------------------------------------------------------------------------- /nordicsemi/lister/windows/structures.py: -------------------------------------------------------------------------------- 1 | """ 2 | MIT License 3 | 4 | Copyright (c) 2016 gwangyi 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | """ 24 | 25 | import ctypes 26 | 27 | _ole32 = ctypes.WinDLL('ole32') 28 | 29 | 30 | class _GUID(ctypes.Structure): 31 | _fields_ = [ 32 | ('Data1', ctypes.c_uint32), 33 | ('Data2', ctypes.c_uint16), 34 | ('Data3', ctypes.c_uint16), 35 | ('Data4', ctypes.c_ubyte * 8), 36 | ] 37 | 38 | def __init__(self, guid="{00000000-0000-0000-0000-000000000000}"): 39 | super().__init__() 40 | if isinstance(guid, str): 41 | ret = _ole32.CLSIDFromString(ctypes.create_unicode_buffer(guid), ctypes.byref(self)) 42 | if ret < 0: 43 | err_no = ctypes.GetLastError() 44 | raise WindowsError(err_no, ctypes.FormatError(err_no), guid) 45 | else: 46 | ctypes.memmove(ctypes.byref(self), bytes(guid), ctypes.sizeof(self)) 47 | 48 | def __str__(self): 49 | s = ctypes.c_wchar_p() 50 | ret = _ole32.StringFromCLSID(ctypes.byref(self), ctypes.byref(s)) 51 | if ret < 0: 52 | err_no = ctypes.GetLastError() 53 | raise WindowsError(err_no, ctypes.FormatError(err_no)) 54 | ret = str(s.value) 55 | _ole32.CoTaskMemFree(s) 56 | return ret 57 | 58 | def __repr__(self): 59 | return "".format(str(self)) 60 | 61 | 62 | assert ctypes.sizeof(_GUID) == 16 63 | 64 | 65 | class GUID: 66 | def __init__(self, guid="{00000000-0000-0000-0000-000000000000}"): 67 | self._guid = _GUID(guid) 68 | 69 | def __bytes__(self): 70 | return bytes(self._guid) 71 | 72 | def __str__(self): 73 | return str(self._guid) 74 | 75 | def __repr__(self): 76 | return repr(self._guid) 77 | 78 | 79 | class DevicePropertyKey(ctypes.Structure): 80 | # noinspection SpellCheckingInspection 81 | _fields_ = [ 82 | ('fmtid', _GUID), 83 | ('pid', ctypes.c_ulong) 84 | ] 85 | 86 | def __init__(self, guid, pid, name=None): 87 | super().__init__() 88 | self.fmtid.__init__(guid) 89 | self.pid = pid 90 | self.name = name 91 | self.__doc__ = str(self) 92 | 93 | def __repr__(self): 94 | return "".format(str(self)) 95 | 96 | def __str__(self): 97 | if not hasattr(self, 'name') or self.name is None: 98 | # noinspection SpellCheckingInspection 99 | return "{} {}".format(self.fmtid, self.pid) 100 | else: 101 | # noinspection SpellCheckingInspection 102 | return "{}, {} {}".format(self.name, self.fmtid, self.pid) 103 | 104 | def __eq__(self, key): 105 | if not isinstance(key, DevicePropertyKey): 106 | return False 107 | return bytes(self) == bytes(key) 108 | 109 | 110 | class DeviceInfoData(ctypes.Structure): 111 | _fields_ = [ 112 | ('cbSize', ctypes.c_ulong), 113 | ('ClassGuid', _GUID), 114 | ('DevInst', ctypes.c_ulong), 115 | ('Reserved', ctypes.c_void_p), 116 | ] 117 | 118 | def __init__(self): 119 | super().__init__() 120 | self.cbSize = ctypes.sizeof(self) 121 | 122 | def __str__(self): 123 | return "ClassGuid:{} DevInst:{}".format(self.ClassGuid, self.DevInst) 124 | 125 | 126 | class ctypesInternalGUID: 127 | def __init__(self, bytes): 128 | self._internal = bytes 129 | 130 | def __bytes__(self): 131 | return bytes(self._internal) 132 | 133 | 134 | def ValidHandle(value, func, arguments): 135 | if value == 0: 136 | raise ctypes.WinError() 137 | return value 138 | 139 | 140 | DeviceInfoData.size = DeviceInfoData.cbSize 141 | DeviceInfoData.dev_inst = DeviceInfoData.DevInst 142 | DeviceInfoData.class_guid = DeviceInfoData.ClassGuid 143 | # noinspection SpellCheckingInspection 144 | SP_DEVINFO_DATA = DeviceInfoData 145 | # noinspection SpellCheckingInspection 146 | DEVPROPKEY = DevicePropertyKey 147 | -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/test_signing.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import binascii 39 | import os 40 | import shutil 41 | import tempfile 42 | import unittest 43 | 44 | from nordicsemi.dfu.signing import Signing 45 | 46 | 47 | class TestSigning(unittest.TestCase): 48 | def setUp(self): 49 | script_abspath = os.path.abspath(__file__) 50 | script_dirname = os.path.dirname(script_abspath) 51 | os.chdir(script_dirname) 52 | 53 | def test_gen_key(self): 54 | self.work_directory = tempfile.mkdtemp(prefix="nrf_signing_tests_") 55 | 56 | key_file_name = 'key.pem' 57 | key_file_path = os.path.join(self.work_directory, key_file_name) 58 | 59 | signing = Signing() 60 | signing.gen_key(key_file_path) 61 | 62 | self.assertTrue(os.path.exists(key_file_path)) 63 | 64 | shutil.rmtree(self.work_directory, ignore_errors=True) 65 | 66 | def test_load_key(self): 67 | key_file_name = 'key.pem' 68 | 69 | signing = Signing() 70 | signing.load_key(key_file_name) 71 | 72 | self.assertEqual(64, len(binascii.hexlify(signing.sk.to_string()))) 73 | 74 | def test_get_vk(self): 75 | key_file_name = 'key.pem' 76 | 77 | signing = Signing() 78 | signing.load_key(key_file_name) 79 | 80 | vk_str = signing.get_vk('hex', False) 81 | vk_hex = signing.get_vk_hex() 82 | self.assertEqual(vk_hex, vk_str) 83 | 84 | vk_str = signing.get_vk('code', False) 85 | vk_code = signing.get_vk_code(False) 86 | self.assertEqual(vk_code, vk_str) 87 | 88 | vk_str = signing.get_vk('pem', False) 89 | vk_pem = signing.get_vk_pem() 90 | self.assertEqual(vk_pem, vk_str) 91 | 92 | def test_get_vk_hex(self): 93 | key_file_name = 'key.pem' 94 | expected_vk_hex = "Public (verification) key pk:\n60f417aabb6bb5b9058aec0570b83fedab1782d62072ae7d691f98dbeda28d654c1d98"\ 95 | "6cadcd593ad8901084900c1bbdcc4fff62b612b604c22672adcdae9b90" 96 | 97 | signing = Signing() 98 | signing.load_key(key_file_name) 99 | 100 | vk_hex = signing.get_vk_hex() 101 | 102 | self.assertEqual(expected_vk_hex, vk_hex) 103 | 104 | def test_get_sk_hex(self): 105 | key_file_name = 'key.pem' 106 | expected_vk_hex = "Private (signing) key sk:\n9d37cc501be62612dd44d150a1c6ad69fbf08e9f905e5e860b89ff9e1050963d" 107 | 108 | signing = Signing() 109 | signing.load_key(key_file_name) 110 | 111 | sk_hex = signing.get_sk_hex() 112 | 113 | self.assertEqual(expected_vk_hex, sk_hex) 114 | 115 | def test_get_vk_pem(self): 116 | key_file_name = 'key.pem' 117 | expected_vk_pem = "-----BEGIN PUBLIC KEY-----\n" \ 118 | "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZY2i7duYH2l9rnIg1oIXq+0/uHAF\n" \ 119 | "7IoFubVru6oX9GCQm67NrXImwgS2ErZi/0/MvRsMkIQQkNg6Wc2tbJgdTA==\n" \ 120 | "-----END PUBLIC KEY-----\n" 121 | 122 | signing = Signing() 123 | signing.load_key(key_file_name) 124 | 125 | vk_pem = signing.get_vk_pem() 126 | 127 | self.assertEqual(expected_vk_pem, vk_pem) 128 | -------------------------------------------------------------------------------- /nordicsemi/zigbee/tests/test_prod_config.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import unittest 39 | import tempfile 40 | import shutil 41 | import os 42 | import filecmp 43 | 44 | from nordicsemi.zigbee.prod_config import ProductionConfig, ProductionConfigTooLargeException, ProductionConfigWrongException 45 | 46 | class TestProductionConfig(unittest.TestCase): 47 | PRODUCTION_CONFIG_EXAMPLES_PATH = 'configs' 48 | PRODUCTION_CONFIG_GOLDEN_DATA_PATH = 'golden_data' 49 | 50 | def setUp(self): 51 | ''' Switch to a directory of the file and create a temporary directory to work in. ''' 52 | script_abspath = os.path.abspath(__file__) 53 | script_dirname = os.path.dirname(script_abspath) 54 | os.chdir(script_dirname) 55 | 56 | self.work_directory = tempfile.mkdtemp(prefix="nrf_zigbee_production_config_tests_") 57 | 58 | def tearDown(self): 59 | ''' Remove a temporary directory. ''' 60 | shutil.rmtree(self.work_directory, ignore_errors=True) 61 | 62 | def process_yaml_config(self, name): 63 | ''' Process the YAML config and generate an output hex file. ''' 64 | input = os.path.join(self.PRODUCTION_CONFIG_EXAMPLES_PATH, name + '.yaml') 65 | output = os.path.join(self.work_directory, name + '.hex') 66 | 67 | try: 68 | pc = ProductionConfig(input) 69 | except ProductionConfigWrongException: 70 | self.fail("Error: Input YAML file format wrong.") 71 | 72 | try: 73 | pc.generate(output) 74 | except ProductionConfigTooLargeException as e: 75 | self.fail("Error: Production Config is too large.") 76 | 77 | def compare_hex_with_golden_data(self, name): 78 | ''' Compare the generated hex file with the golden vector. ''' 79 | test = os.path.join(self.work_directory, name + '.hex') 80 | gold = os.path.join(self.PRODUCTION_CONFIG_GOLDEN_DATA_PATH, name + '.hex') 81 | 82 | return filecmp.cmp(test, gold) 83 | 84 | def generate_and_verify_production_config(self, name): 85 | ''' Generate and verify the production config. ''' 86 | self.process_yaml_config(name) 87 | return self.compare_hex_with_golden_data(name) 88 | 89 | def test_channel_install_ieee_power_config(self): 90 | ''' Test config which contains 802.15.4 channel, 91 | install code, IEEE address and maximum Tx power. 92 | ''' 93 | self.assertTrue(self.generate_and_verify_production_config('channel_install_ieee_power')) 94 | 95 | def test_install_ieee_power_config(self): 96 | ''' Test config which contains install code, 97 | IEEE address and maximum Tx power. 98 | ''' 99 | self.assertTrue(self.generate_and_verify_production_config('install_ieee_power')) 100 | 101 | def test_install_ieee_config(self): 102 | self.assertTrue(self.generate_and_verify_production_config('install_ieee')) 103 | 104 | def test_install_config(self): 105 | self.assertTrue(self.generate_and_verify_production_config('install')) 106 | 107 | def test_empty_config(self): 108 | input = os.path.join(self.PRODUCTION_CONFIG_EXAMPLES_PATH, 'empty.yaml') 109 | self.assertRaises(ProductionConfigWrongException, ProductionConfig, input) 110 | 111 | def test_corrupt_config(self): 112 | input = os.path.join(self.PRODUCTION_CONFIG_EXAMPLES_PATH, 'corrupt.yaml') 113 | self.assertRaises(ProductionConfigWrongException, ProductionConfig, input) 114 | 115 | 116 | if __name__ == '__main__': 117 | unittest.main() 118 | -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/test_nrfhex.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import os 39 | 40 | import unittest 41 | import nordicsemi.dfu.nrfhex as nrfhex 42 | import intelhex 43 | 44 | 45 | class TestnRFHex(unittest.TestCase): 46 | def setUp(self): 47 | script_abspath = os.path.abspath(__file__) 48 | script_dirname = os.path.dirname(script_abspath) 49 | os.chdir(script_dirname) 50 | 51 | def comparefiles(self, actual, wanted): 52 | actualfile = intelhex.IntelHex() 53 | actualfile.loadfile(actual, format="bin") 54 | 55 | wantedfile = intelhex.IntelHex() 56 | wantedfile.loadfile(wanted, format="bin") 57 | 58 | self.assertEqual(actualfile.minaddr(), wantedfile.minaddr()) 59 | self.assertEqual(actualfile.maxaddr(), wantedfile.maxaddr()) 60 | 61 | minaddress = actualfile.minaddr() 62 | maxaddress = actualfile.maxaddr() 63 | 64 | length = maxaddress - minaddress 65 | 66 | actualfile_data = actualfile.gets(minaddress, length) 67 | wantedfile_data = wantedfile.gets(minaddress, length) 68 | 69 | self.assertEqual(actualfile_data, wantedfile_data) 70 | 71 | def test_tobinfile_single_file_without_uicr_content(self): 72 | nrf = nrfhex.nRFHex("firmwares/bar.hex") 73 | nrf.tobinfile("firmwares/bar.bin") 74 | 75 | self.comparefiles("firmwares/bar.bin", "firmwares/bar_wanted.bin") 76 | 77 | def test_tobinfile_single_file_with_uicr_content(self): 78 | nrf = nrfhex.nRFHex("firmwares/foo.hex") 79 | nrf.tobinfile("firmwares/foo.bin") 80 | 81 | self.comparefiles("firmwares/foo.bin", "firmwares/foo_wanted.bin") 82 | 83 | def test_tobinfile_single_bin_file(self): 84 | nrf = nrfhex.nRFHex("firmwares/bar_wanted.bin") 85 | nrf.tobinfile("firmwares/bar.bin") 86 | 87 | self.comparefiles("firmwares/bar.bin", "firmwares/bar_wanted.bin") 88 | 89 | def test_tobinfile_two_hex_files(self): 90 | nrf = nrfhex.nRFHex("firmwares/foo.hex", "firmwares/bar.hex") 91 | nrf.tobinfile("firmwares/foobar.bin") 92 | 93 | self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin") 94 | 95 | def test_tobinfile_one_hex_one_bin(self): 96 | nrf = nrfhex.nRFHex("firmwares/foo_wanted.bin", "firmwares/bar.hex") 97 | nrf.tobinfile("firmwares/foobar.bin") 98 | 99 | self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin") 100 | 101 | def test_tobinfile_one_bin_one_hex(self): 102 | nrf = nrfhex.nRFHex("firmwares/foo.hex", "firmwares/bar_wanted.bin") 103 | nrf.tobinfile("firmwares/foobar.bin") 104 | 105 | self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin") 106 | 107 | def test_tobinfile_two_bin(self): 108 | nrf = nrfhex.nRFHex("firmwares/foo_wanted.bin", "firmwares/bar_wanted.bin") 109 | nrf.tobinfile("firmwares/foobar.bin") 110 | 111 | self.comparefiles("firmwares/foobar.bin", "firmwares/foobar_wanted.bin") 112 | 113 | def test_sizes(self): 114 | nrf = nrfhex.nRFHex("firmwares/foo.hex", "firmwares/bar.hex") 115 | 116 | self.assertEqual(nrf.get_mbr_end_address(), 0x1000) 117 | self.assertEqual(nrf.minaddr(), 0x1000) 118 | self.assertEqual(nrf.size(), 73152) 119 | self.assertEqual(nrf.bootloadersize(), 13192) 120 | 121 | nrf = nrfhex.nRFHex("firmwares/s132_nrf52_mini.hex") 122 | 123 | self.assertEqual(nrf.get_mbr_end_address(), 0x3000) 124 | self.assertEqual(nrf.minaddr(), 0x3000) 125 | self.assertEqual(nrf.size(), 12288) 126 | self.assertEqual(nrf.bootloadersize(), 0) 127 | 128 | def test_get_softdevice_variant(self): 129 | nrf = nrfhex.nRFHex("firmwares/foo.hex") 130 | 131 | self.assertEqual(nrf.get_softdevice_variant(), "unknown") 132 | 133 | nrf = nrfhex.nRFHex("firmwares/s130_nrf51_mini.hex") 134 | 135 | self.assertEqual(nrf.get_softdevice_variant(), "s1x0") 136 | 137 | nrf = nrfhex.nRFHex("firmwares/s132_nrf52_mini.hex") 138 | 139 | self.assertEqual(nrf.get_softdevice_variant(), "s132") 140 | 141 | 142 | if __name__ == '__main__': 143 | unittest.main() 144 | -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/test_init_packet_pb.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | import unittest 38 | from nordicsemi.dfu.init_packet_pb import InitPacketPB, DFUType, SigningTypes, HashTypes 39 | import nordicsemi.dfu.dfu_cc_pb2 as pb 40 | 41 | HASH_BYTES_A = b'123123123123' 42 | HASH_BYTES_B = b'434343434343' 43 | HASH_TYPE = HashTypes.SHA256 44 | DFU_TYPE = DFUType.APPLICATION 45 | SIGNATURE_BYTES_A = b'234827364872634876234' 46 | SIGNATURE_TYPE = SigningTypes.ECDSA_P256_SHA256 47 | SD_REQ_A = [1, 2, 3, 4] 48 | FIRMWARE_VERSION_A = 0xaaaa 49 | HARDWARE_VERSION_A = 0xbbbb 50 | ILLEGAL_VERSION = 0xaaaaaaaa1 51 | SD_SIZE = 0x11 52 | APP_SIZE = 0x233 53 | BL_SIZE = 0x324 54 | 55 | 56 | class TestPackage(unittest.TestCase): 57 | def setUp(self): 58 | pass 59 | 60 | def tearDown(self): 61 | pass 62 | 63 | def test_init_command(self): 64 | init_command_serialized = InitPacketPB(hash_bytes=HASH_BYTES_B, hash_type=HASH_TYPE, 65 | dfu_type=DFU_TYPE, sd_req=SD_REQ_A, fw_version=FIRMWARE_VERSION_A, 66 | hw_version=HARDWARE_VERSION_A, sd_size=SD_SIZE, app_size=APP_SIZE, 67 | bl_size=BL_SIZE).get_init_command_bytes() 68 | 69 | init_command = pb.InitCommand() 70 | init_command.ParseFromString(init_command_serialized) 71 | 72 | self.assertEqual(init_command.hash.hash, HASH_BYTES_B) 73 | self.assertEqual(init_command.hash.hash_type, pb.SHA256) 74 | self.assertEqual(init_command.type, pb.APPLICATION) 75 | self.assertEqual(init_command.fw_version, FIRMWARE_VERSION_A) 76 | self.assertEqual(init_command.hw_version, HARDWARE_VERSION_A) 77 | self.assertEqual(init_command.app_size, APP_SIZE) 78 | self.assertEqual(init_command.sd_size, SD_SIZE) 79 | self.assertEqual(init_command.bl_size, BL_SIZE) 80 | self.assertEqual(init_command.sd_req, SD_REQ_A) 81 | 82 | def test_init_command_wrong_size(self): 83 | def test_size(dfu_type, sd_size, app_size, bl_size, expect_failed): 84 | failed = False 85 | try: 86 | InitPacketPB(hash_bytes=HASH_BYTES_B, hash_type=HASH_TYPE, 87 | dfu_type=dfu_type, 88 | sd_size=sd_size, 89 | app_size=app_size, 90 | bl_size=bl_size) 91 | except RuntimeError: 92 | failed = True 93 | 94 | self.assertEqual(failed, expect_failed) 95 | 96 | test_size(DFUType.APPLICATION, sd_size=SD_SIZE, app_size=0, bl_size=BL_SIZE, expect_failed=True) 97 | test_size(DFUType.APPLICATION, sd_size=SD_SIZE, app_size=APP_SIZE, bl_size=BL_SIZE, expect_failed=False) 98 | test_size(DFUType.BOOTLOADER, sd_size=SD_SIZE, app_size=APP_SIZE, bl_size=0, expect_failed=True) 99 | test_size(DFUType.BOOTLOADER, sd_size=SD_SIZE, app_size=APP_SIZE, bl_size=BL_SIZE, expect_failed=False) 100 | test_size(DFUType.SOFTDEVICE, sd_size=0, app_size=APP_SIZE, bl_size=BL_SIZE, expect_failed=True) 101 | test_size(DFUType.SOFTDEVICE, sd_size=SD_SIZE, app_size=APP_SIZE, bl_size=BL_SIZE, expect_failed=False) 102 | test_size(DFUType.SOFTDEVICE_BOOTLOADER, sd_size=0, app_size=APP_SIZE, bl_size=BL_SIZE, expect_failed=True) 103 | test_size(DFUType.SOFTDEVICE_BOOTLOADER, sd_size=SD_SIZE, app_size=APP_SIZE, bl_size=0, expect_failed=True) 104 | test_size(DFUType.SOFTDEVICE_BOOTLOADER, sd_size=SD_SIZE, app_size=APP_SIZE, bl_size=BL_SIZE, 105 | expect_failed=False) 106 | 107 | def test_init_packet(self): 108 | failed = False 109 | init_packet = InitPacketPB(hash_bytes=HASH_BYTES_A, hash_type=HASH_TYPE, dfu_type=DFU_TYPE, app_size=APP_SIZE) 110 | 111 | init_packet.set_signature(signature=SIGNATURE_BYTES_A, signature_type=SIGNATURE_TYPE) 112 | init_packet_serialized = init_packet.get_init_packet_pb_bytes() 113 | 114 | init_packet = pb.Packet() 115 | init_packet.ParseFromString(init_packet_serialized) 116 | self.assertEqual(init_packet.signed_command.command.init.hash.hash, HASH_BYTES_A) 117 | self.assertEqual(init_packet.signed_command.command.op_code, pb.INIT) 118 | 119 | 120 | if __name__ == '__main__': 121 | unittest.main() 122 | -------------------------------------------------------------------------------- /nordicsemi/dfu/dfu.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | # Python standard library 39 | import os 40 | import time 41 | import shutil 42 | import logging 43 | import tempfile 44 | 45 | 46 | # Nordic libraries 47 | from nordicsemi.dfu.package import Package 48 | 49 | logger = logging.getLogger(__name__) 50 | 51 | 52 | class Dfu: 53 | """ Class to handle upload of a new hex image to the device. """ 54 | 55 | def __init__(self, zip_file_path, dfu_transport, connect_delay): 56 | """ 57 | Initializes the dfu upgrade, unpacks zip and registers callbacks. 58 | 59 | @param zip_file_path: Path to the zip file with the firmware to upgrade 60 | @type zip_file_path: str 61 | @param dfu_transport: Transport backend to use to upgrade 62 | @type dfu_transport: nordicsemi.dfu.dfu_transport.DfuTransport 63 | @param connect_delay: Delay in seconds before each connection to the DFU target 64 | @type connect_delay: int 65 | @return 66 | """ 67 | self.temp_dir = tempfile.mkdtemp(prefix="nrf_dfu_") 68 | self.unpacked_zip_path = os.path.join(self.temp_dir, 'unpacked_zip') 69 | self.manifest = Package.unpack_package(zip_file_path, self.unpacked_zip_path) 70 | 71 | self.dfu_transport = dfu_transport 72 | 73 | if connect_delay is not None: 74 | self.connect_delay = connect_delay 75 | else: 76 | self.connect_delay = 3 77 | 78 | def __del__(self): 79 | """ 80 | Destructor removes the temporary directory for the unpacked zip 81 | :return: 82 | """ 83 | shutil.rmtree(self.temp_dir) 84 | 85 | 86 | def _dfu_send_image(self, firmware): 87 | time.sleep(self.connect_delay) 88 | self.dfu_transport.open() 89 | 90 | start_time = time.time() 91 | 92 | logger.info("Sending init packet...") 93 | with open(os.path.join(self.unpacked_zip_path, firmware.dat_file), 'rb') as f: 94 | data = f.read() 95 | self.dfu_transport.send_init_packet(data) 96 | 97 | logger.info("Sending firmware file...") 98 | with open(os.path.join(self.unpacked_zip_path, firmware.bin_file), 'rb') as f: 99 | data = f.read() 100 | self.dfu_transport.send_firmware(data) 101 | 102 | end_time = time.time() 103 | logger.info("Image sent in {0}s".format(end_time - start_time)) 104 | 105 | self.dfu_transport.close() 106 | 107 | 108 | def dfu_send_images(self): 109 | """ 110 | Does DFU for all firmware images in the stored manifest. 111 | :return: 112 | """ 113 | if self.manifest.softdevice_bootloader: 114 | logger.info("Sending SoftDevice+Bootloader image.") 115 | self._dfu_send_image(self.manifest.softdevice_bootloader) 116 | 117 | if self.manifest.softdevice: 118 | logger.info("Sending SoftDevice image...") 119 | self._dfu_send_image(self.manifest.softdevice) 120 | 121 | if self.manifest.bootloader: 122 | logger.info("Sending Bootloader image.") 123 | self._dfu_send_image(self.manifest.bootloader) 124 | 125 | if self.manifest.application: 126 | logger.info("Sending Application image.") 127 | self._dfu_send_image(self.manifest.application) 128 | 129 | 130 | def dfu_get_total_size(self): 131 | total_size = 0 132 | 133 | if self.manifest.softdevice_bootloader: 134 | total_size += os.path.getsize(os.path.join(self.unpacked_zip_path, 135 | self.manifest.softdevice_bootloader.bin_file)) 136 | 137 | if self.manifest.softdevice: 138 | total_size += os.path.getsize(os.path.join(self.unpacked_zip_path, 139 | self.manifest.softdevice.bin_file)) 140 | 141 | if self.manifest.bootloader: 142 | total_size += os.path.getsize(os.path.join(self.unpacked_zip_path, 143 | self.manifest.bootloader.bin_file)) 144 | 145 | if self.manifest.application: 146 | total_size += os.path.getsize(os.path.join(self.unpacked_zip_path, 147 | self.manifest.application.bin_file)) 148 | 149 | return total_size 150 | -------------------------------------------------------------------------------- /nordicsemi/zigbee/ota_flasher.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import os 39 | import re 40 | import subprocess 41 | import time 42 | import uuid 43 | from intelhex import IntelHex 44 | from serial import Serial 45 | from pc_ble_driver_py.ble_driver import Flasher 46 | 47 | class OTAFlasher(Flasher): 48 | ERROR_CODE_VERIFY_ERROR = 55 49 | # Address in flash memory, where the Zigbee image will be placed. This value has to be synced with UPGRADE_IMAGE_OFFSET constant inside Zigbee OTA server source code. 50 | OTA_UPDATE_OFFSET = 0x80000 51 | OTA_EUI64_PREFIX = '07A07A' 52 | 53 | def __init__(self, fw, channel = 16, serial_port = None, snr = None): 54 | ''' 55 | Ininitialises the OTA Flasher class which handles flashing the devboard 56 | with the needed OTA Server firmware and the update file for the OTA Client. 57 | The said devboard shall become the OTA Server which shall propagate the 58 | image on the Zigbee network. 59 | 60 | Keyword arguments: 61 | fw -- path to the update file for the OTA Client 62 | channel -- a 802.15.4 channel number, on which the OTA Server shall operate (default 16) 63 | serial_port -- a serial port of the connected devboard which shall be flashed with OTA Server 64 | snr -- a JLink serial number of the connected devboard which shall be flashed with OTA Server 65 | 66 | Note: only one parameter out of (serial_port, snr) must be provided, since the superclass 67 | constructor shall handle resolving the rest. 68 | 69 | ''' 70 | # Call the superclass constructor 71 | super().__init__(serial_port, snr) 72 | # Create a Intel Hex out of the Zigbee Update file 73 | ih = IntelHex() 74 | update = open(fw, 'rb').read() 75 | ih.puts(OTAFlasher.OTA_UPDATE_OFFSET, update) 76 | self.update_firmware_hex = fw + '.hex' 77 | ih.write_hex_file(self.update_firmware_hex) 78 | # Open the serial channel to the devboard and save the 802.15.4 channel 79 | self.ser = Serial(self.serial_port, 115200) 80 | self.channel = channel 81 | 82 | def __get_hex_path(self): 83 | '''Return the absolute path to the firmware of the OTA Server''' 84 | return os.path.join(os.path.dirname(__file__), 'hex', 'ota.hex') 85 | 86 | def verify(self, path): 87 | '''Run the verify command''' 88 | args = ['--verify', path] 89 | return self.call_cmd(args) 90 | 91 | def _fw_check(self, path_to_file): 92 | '''Check if the path_to_file hexfile was flashed correctly''' 93 | try: 94 | result = self.verify(path_to_file) 95 | except subprocess.CalledProcessError as e: # for pc-ble-driver <= 0.14.2, can be removed when requirements 96 | # will be updated to >= 0.15.0 97 | if e.returncode == OTAFlasher.ERROR_CODE_VERIFY_ERROR: 98 | return False 99 | else: 100 | raise 101 | except RuntimeError: # for pc-ble-driver >= 0.15.0 102 | return False 103 | 104 | return (re.search(b'^Verified OK.$', result, re.MULTILINE) is not None) 105 | 106 | def fw_check(self): 107 | '''Check if all the hex files (OTA Server firmware and Zigbee Update file) were flashed correctly''' 108 | if self._fw_check(self.__get_hex_path()) and self._fw_check(self.update_firmware_hex): 109 | return True 110 | else: 111 | return False 112 | 113 | def fw_flash(self): 114 | '''Flash all the hex files (OTA Server firmware and Zigbee Update file) to the board''' 115 | self.erase() 116 | self.program(self.update_firmware_hex) 117 | self.program(self.__get_hex_path()) 118 | # Remove the generated file 119 | os.remove(self.update_firmware_hex) 120 | 121 | def randomize_eui64(self): 122 | '''Randomize the EUI64 address used by the board''' 123 | random_eui64 = uuid.uuid4().int >> 88 # Generate 128-bit UUID and take 40 upper bits 124 | self.ser.write(f'zdo eui64 {OTAFlasher.OTA_EUI64_PREFIX}{random_eui64:010x}\r\n'.encode()) 125 | 126 | def setup_channel(self): 127 | '''Setup to the channel of the flashed board through the serial CLI; and start the internal stack''' 128 | self.ser.write(f'bdb channel {self.channel}\r\n'.encode()) 129 | time.sleep(1.0) 130 | self.ser.write('bdb start\r\n'.encode()) 131 | -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/test_manifest.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import json 39 | import unittest 40 | 41 | from nordicsemi.dfu.manifest import ManifestGenerator, Manifest 42 | from nordicsemi.dfu.model import HexType 43 | from nordicsemi.dfu.package import FirmwareKeys 44 | 45 | 46 | class TestManifest(unittest.TestCase): 47 | def setUp(self): 48 | self.firmwares_data_a = {} 49 | 50 | self.firmwares_data_a[HexType.APPLICATION] = { 51 | FirmwareKeys.BIN_FILENAME: "app_fw.bin", 52 | FirmwareKeys.DAT_FILENAME: "app_fw.dat", 53 | FirmwareKeys.ENCRYPT: False} 54 | 55 | self.firmwares_data_a[HexType.SD_BL] = { 56 | FirmwareKeys.BIN_FILENAME: "sd_bl_fw.bin", 57 | FirmwareKeys.DAT_FILENAME: "sd_bl_fw.dat", 58 | FirmwareKeys.BL_SIZE: 50, 59 | FirmwareKeys.SD_SIZE: 90 60 | } 61 | 62 | self.firmwares_data_b = {} 63 | 64 | self.firmwares_data_b[HexType.APPLICATION] = { 65 | FirmwareKeys.BIN_FILENAME: "app_fw.bin", 66 | FirmwareKeys.DAT_FILENAME: "app_fw.dat" 67 | } 68 | 69 | self.firmwares_data_b[HexType.BOOTLOADER] = { 70 | FirmwareKeys.BIN_FILENAME: "bootloader_fw.bin", 71 | FirmwareKeys.DAT_FILENAME: "bootloader_fw.dat" 72 | } 73 | 74 | self.firmwares_data_c = {} 75 | 76 | self.firmwares_data_c[HexType.SOFTDEVICE] = { 77 | FirmwareKeys.BIN_FILENAME: "softdevice_fw.bin", 78 | FirmwareKeys.DAT_FILENAME: "softdevice_fw.dat", 79 | } 80 | 81 | def test_generate_manifest(self): 82 | r = ManifestGenerator(self.firmwares_data_a) 83 | 84 | _json = json.loads(r.generate_manifest()) 85 | 86 | # Test for presence of attributes in document 87 | self.assertIn('manifest', _json) 88 | 89 | manifest = _json['manifest'] 90 | self.assertIn('application', manifest) 91 | 92 | application = manifest['application'] 93 | self.assertIn('dat_file', application) 94 | self.assertIn('bin_file', application) 95 | 96 | # Test for values in document 97 | self.assertEqual("app_fw.bin", application['bin_file']) 98 | self.assertEqual("app_fw.dat", application['dat_file']) 99 | 100 | # Test softdevice_bootloader 101 | bl_sd = manifest['softdevice_bootloader'] 102 | self.assertIsNotNone(bl_sd) 103 | self.assertEqual(90, bl_sd['info_read_only_metadata']['sd_size']) 104 | self.assertEqual(50, bl_sd['info_read_only_metadata']['bl_size']) 105 | 106 | # Test for values in document 107 | self.assertEqual("sd_bl_fw.bin", bl_sd['bin_file']) 108 | self.assertEqual("sd_bl_fw.dat", bl_sd['dat_file']) 109 | 110 | def test_manifest_a(self): 111 | r = ManifestGenerator(self.firmwares_data_a) 112 | m = Manifest.from_json(r.generate_manifest()) 113 | self.assertIsNotNone(m) 114 | self.assertIsNotNone(m.application) 115 | self.assertEqual("app_fw.bin", m.application.bin_file) 116 | self.assertEqual("app_fw.dat", m.application.dat_file) 117 | self.assertIsNone(m.bootloader) 118 | self.assertIsNone(m.softdevice) 119 | self.assertIsNotNone(m.softdevice_bootloader) 120 | self.assertEqual(90, m.softdevice_bootloader.info_read_only_metadata.sd_size) 121 | self.assertEqual(50, m.softdevice_bootloader.info_read_only_metadata.bl_size) 122 | self.assertEqual("sd_bl_fw.bin", m.softdevice_bootloader.bin_file) 123 | self.assertEqual("sd_bl_fw.dat", m.softdevice_bootloader.dat_file) 124 | 125 | def test_manifest_b(self): 126 | r = ManifestGenerator(self.firmwares_data_b) 127 | m = Manifest.from_json(r.generate_manifest()) 128 | self.assertIsNotNone(m) 129 | self.assertIsNotNone(m.application) 130 | self.assertEqual("app_fw.bin", m.application.bin_file) 131 | self.assertEqual("app_fw.dat", m.application.dat_file) 132 | self.assertIsNotNone(m.bootloader) 133 | self.assertEqual("bootloader_fw.bin", m.bootloader.bin_file) 134 | self.assertEqual("bootloader_fw.dat", m.bootloader.dat_file) 135 | self.assertIsNone(m.softdevice) 136 | self.assertIsNone(m.softdevice_bootloader) 137 | 138 | 139 | def test_manifest_c(self): 140 | r = ManifestGenerator(self.firmwares_data_c) 141 | m = Manifest.from_json(r.generate_manifest()) 142 | self.assertIsNotNone(m) 143 | self.assertIsNone(m.application) 144 | self.assertIsNone(m.bootloader) 145 | self.assertIsNotNone(m.softdevice) 146 | self.assertEqual('softdevice_fw.bin', m.softdevice.bin_file) 147 | self.assertEqual('softdevice_fw.dat', m.softdevice.dat_file) 148 | self.assertIsNone(m.softdevice_bootloader) 149 | 150 | if __name__ == '__main__': 151 | unittest.main() 152 | -------------------------------------------------------------------------------- /nordicsemi/dfu/nrfhex.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 - 2019 Nordic Semiconductor ASA 2 | # All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without modification, 5 | # are permitted provided that the following conditions are met: 6 | # 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | # 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 11 | # list of conditions and the following disclaimer in the documentation and/or 12 | # other materials provided with the distribution. 13 | # 14 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 15 | # contributors to this software may be used to endorse or promote products 16 | # derived from this software without specific prior written permission. 17 | # 18 | # 4. This software must only be used in or with a processor manufactured by Nordic 19 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 20 | # is used in combination with a processor manufactured by Nordic Semiconductor. 21 | # 22 | # 5. Any software provided in binary or object form under this license must not be 23 | # reverse engineered, decompiled, modified and/or disassembled. 24 | # 25 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 29 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 32 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | import intelhex 37 | from struct import unpack 38 | from enum import Enum 39 | 40 | class nRFArch(Enum): 41 | NRF51 = 1 42 | NRF52 = 2 43 | NRF52840 = 3 44 | 45 | class nRFHex(intelhex.IntelHex): 46 | """ 47 | Converts and merges .hex and .bin files into one .bin file. 48 | """ 49 | 50 | info_struct_address_base = 0x00003000 51 | info_struct_address_offset = 0x1000 52 | 53 | info_struct_magic_number = 0x51B1E5DB 54 | info_struct_magic_number_offset = 0x004 55 | 56 | s1x0_mbr_end_address = 0x1000 57 | s132_mbr_end_address = 0x3000 58 | 59 | def __init__(self, source, bootloader=None, arch=None): 60 | """ 61 | Constructor that requires a firmware file path. 62 | Softdevices can take an optional bootloader file path as parameter. 63 | 64 | :param str source: The file path for the firmware 65 | :param str bootloader: Optional file path to bootloader firmware 66 | :return: None 67 | """ 68 | super().__init__() 69 | self.arch = arch 70 | self.file_format = 'hex' 71 | 72 | if source.endswith('.bin'): 73 | self.file_format = 'bin' 74 | 75 | self.loadfile(source, self.file_format) 76 | 77 | if self.file_format == 'hex': 78 | self._removeuicr() 79 | self._removembr() 80 | 81 | self.bootloaderhex = None 82 | 83 | if bootloader is not None: 84 | self.bootloaderhex = nRFHex(bootloader) 85 | 86 | def _removeuicr(self): 87 | uicr_start_address = 0x10000000 88 | self._buf = {k: v for k, v in self._buf.items() if k < uicr_start_address} 89 | 90 | def _removembr(self): 91 | mbr_end_address = 0x1000 92 | self._buf = {k: v for k, v in self._buf.items() if k >= mbr_end_address} 93 | 94 | def address_has_magic_number(self, address): 95 | try: 96 | potential_magic_number = self.gets(address, 4) 97 | potential_magic_number = unpack('I', potential_magic_number)[0] 98 | return nRFHex.info_struct_magic_number == potential_magic_number 99 | except Exception: 100 | return False 101 | 102 | def get_softdevice_variant(self): 103 | potential_magic_number_address = nRFHex.info_struct_address_base + nRFHex.info_struct_magic_number_offset 104 | 105 | if self.address_has_magic_number(potential_magic_number_address): 106 | return "s1x0" 107 | 108 | for i in range(4): 109 | potential_magic_number_address += nRFHex.info_struct_address_offset 110 | 111 | if self.address_has_magic_number(potential_magic_number_address): 112 | return "s132" 113 | 114 | return "unknown" 115 | 116 | def get_mbr_end_address(self): 117 | softdevice_variant = self.get_softdevice_variant() 118 | 119 | if softdevice_variant == "s132": 120 | return nRFHex.s132_mbr_end_address 121 | else: 122 | return nRFHex.s1x0_mbr_end_address 123 | 124 | def minaddr(self): 125 | min_address = super().minaddr() 126 | 127 | # Lower addresses are reserved for master boot record 128 | if self.file_format != 'bin': 129 | min_address = max(self.get_mbr_end_address(), min_address) 130 | 131 | return min_address 132 | 133 | def size(self): 134 | """ 135 | Returns the size of the source. 136 | :return: int 137 | """ 138 | min_address = self.minaddr() 139 | max_address = self.maxaddr() 140 | 141 | size = max_address - min_address + 1 142 | 143 | # Round up to nearest word 144 | word_size = 4 145 | number_of_words = (size + (word_size - 1)) // word_size 146 | size = number_of_words * word_size 147 | 148 | return size 149 | 150 | def bootloadersize(self): 151 | """ 152 | Returns the size of the bootloader. 153 | :return: int 154 | """ 155 | if self.bootloaderhex is None: 156 | return 0 157 | 158 | return self.bootloaderhex.size() 159 | 160 | def tobinfile(self, fobj, start=None, end=None, pad=None, size=None): 161 | """ 162 | Writes a binary version of source and bootloader respectively to fobj which could be a 163 | file object or a file path. 164 | 165 | :param str fobj: File path or object the function writes to 166 | :return: None 167 | """ 168 | # If there is a bootloader this will make the recursion call use the samme file object. 169 | if getattr(fobj, "write", None) is None: 170 | fobj = open(fobj, "wb") 171 | close_fd = True 172 | else: 173 | close_fd = False 174 | 175 | start_address = self.minaddr() 176 | size = self.size() 177 | super().tobinfile(fobj, start=start_address, size=size) 178 | 179 | if self.bootloaderhex is not None: 180 | self.bootloaderhex.tobinfile(fobj) 181 | 182 | if close_fd: 183 | fobj.close() 184 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2016 Nordic Semiconductor ASA 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without modification, 7 | # are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 13 | # list of conditions and the following disclaimer in the documentation and/or 14 | # other materials provided with the distribution. 15 | # 16 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 17 | # contributors to this software may be used to endorse or promote products 18 | # derived from this software without specific prior written permission. 19 | # 20 | # 4. This software must only be used in or with a processor manufactured by Nordic 21 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 22 | # is used in combination with a processor manufactured by Nordic Semiconductor. 23 | # 24 | # 5. Any software provided in binary or object form under this license must not be 25 | # reverse engineered, decompiled, modified and/or disassembled. 26 | # 27 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 28 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 31 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 32 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 34 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | # 38 | """ 39 | Setup script for nrfutil. 40 | 41 | USAGE: 42 | python setup.py install 43 | 44 | """ 45 | import os 46 | import sys 47 | 48 | from setuptools import setup, find_packages 49 | from setuptools.command.test import test as TestCommand 50 | 51 | from nordicsemi import version 52 | 53 | # Change directory to be able to run python setup.py develop from another directory 54 | os.chdir(os.path.dirname(os.path.realpath(__file__))) 55 | 56 | install_package = True 57 | try: 58 | # If the version that is being installed is older than the one currently installed, suggest 59 | # to use a virtual environment. 60 | 61 | import pkg_resources 62 | installed_packages = [d for d in pkg_resources.working_set] 63 | flat_installed_packages = [package.project_name for package in installed_packages] 64 | package = installed_packages[flat_installed_packages.index('nrfutil')] 65 | installed_versions = [int(i) for i in package.version.split(".")] 66 | new_versions = [int(i) for i in version.NRFUTIL_VERSION.split(".")] 67 | legacy_version = False 68 | for v1, v2 in zip(installed_versions, new_versions): 69 | if v1 == v2: 70 | continue 71 | if v2 < v1: 72 | legacy_version = True 73 | break 74 | 75 | if legacy_version: 76 | valid_response = ["y", "yes"] 77 | msg = ("A newer version of nrfutil may already be installed. Consider using a separate " 78 | "virtual environment when installing legacy versions. \nProceed (y/N)? ") 79 | print(msg) 80 | sys.stdout.flush() 81 | prompt = sys.stdin.readline().strip() 82 | if(prompt.lower() not in valid_response): 83 | install_package = False 84 | 85 | except ImportError: 86 | pass # pkg_resources not available. 87 | except Exception: 88 | pass # Nrfutil is not already installed. 89 | 90 | 91 | # Exit program if user doesn't want to replace newer version. 92 | if(not install_package): 93 | sys.exit(1) 94 | 95 | 96 | excludes = ["Tkconstants", 97 | "Tkinter", 98 | "tcl", 99 | "pickle", 100 | "unittest", 101 | "pyreadline"] 102 | 103 | # DFU component cli interface 104 | includes = ["nordicsemi.dfu.dfu"] 105 | 106 | packages = [] 107 | 108 | dll_excludes = [ 109 | "w9xpopen.exe", 110 | "OLEAUT32.DLL", 111 | "OLE32.DLL", 112 | "USER32.DLL", 113 | "SHELL32.DLL", 114 | "ADVAPI32.DLL", 115 | "KERNEL32.DLL", 116 | "WS2_32.DLL", 117 | "GDI32.DLL"] 118 | 119 | build_dir = os.environ.get("NRFUTIL_BUILD_DIR", "./{}".format(version.NRFUTIL_VERSION)) 120 | description = """A Python package that includes the nrfutil utility and the nordicsemi library""" 121 | 122 | with open("requirements.txt") as reqs_file: 123 | reqs = reqs_file.readlines() 124 | 125 | 126 | class NoseTestCommand(TestCommand): 127 | def finalize_options(self): 128 | TestCommand.finalize_options(self) 129 | self.test_args = [] 130 | self.test_suite = True 131 | 132 | def run_tests(self): 133 | import nose 134 | nose.run_exit(argv=['nosetests', '--with-xunit', '--xunit-file=unittests.xml']) 135 | 136 | 137 | setup( 138 | name="nrfutil", 139 | version=version.NRFUTIL_VERSION, 140 | license="Other/Proprietary License", 141 | author="Nordic Semiconductor ASA", 142 | url="https://github.com/NordicSemiconductor/pc-nrfutil", 143 | description="Nordic Semiconductor nrfutil utility and Python library", 144 | long_description=description, 145 | packages=find_packages(exclude=["tests.*", "tests"]), 146 | package_data={ 147 | '': ['../requirements.txt', 'thread/hex/ncp.hex', 'zigbee/hex/ota.hex', 148 | '../libusb/x86/libusb-1.0.dll', '../libusb/x64/libusb-1.0.dll', 149 | '../libusb/x64/libusb-1.0.dylib', '../libusb/LICENSE'] 150 | }, 151 | python_requires='>=3.7, <3.11', 152 | install_requires=reqs, 153 | zipfile=None, 154 | tests_require=[ 155 | "nose >= 1.3.4", 156 | "behave" 157 | ], 158 | zip_safe=False, 159 | classifiers=[ 160 | 'Development Status :: 4 - Beta', 161 | 162 | 'Intended Audience :: Developers', 163 | 164 | 'Operating System :: MacOS', 165 | 'Operating System :: Microsoft :: Windows', 166 | 'Operating System :: POSIX :: Linux', 167 | 168 | 'Topic :: System :: Networking', 169 | 'Topic :: System :: Hardware :: Hardware Drivers', 170 | 'Topic :: Software Development :: Embedded Systems', 171 | 172 | 'License :: Other/Proprietary License', 173 | 174 | 'Programming Language :: Python :: 3.7', 175 | 'Programming Language :: Python :: 3.8', 176 | 'Programming Language :: Python :: 3.9', 177 | 'Programming Language :: Python :: 3.10', 178 | ], 179 | keywords='nordic nrf51 nrf52 ble bluetooth dfu ota softdevice serialization nrfutil pc-nrfutil', 180 | cmdclass={ 181 | 'test': NoseTestCommand 182 | }, 183 | entry_points=''' 184 | [console_scripts] 185 | nrfutil = nordicsemi.__main__:cli 186 | ''', 187 | console=[{ 188 | "script": "./nordicsemi/__main__.py", 189 | "dest_base": "nrfutil" 190 | }], 191 | ) 192 | -------------------------------------------------------------------------------- /nordicsemi/zigbee/prod_config.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import crcmod.predefined 39 | import struct 40 | import intelhex 41 | import yaml 42 | 43 | 44 | class ProductionConfigWrongException(Exception): 45 | pass 46 | 47 | 48 | class ProductionConfigTooLargeException(Exception): 49 | def __init__(self, length): 50 | self.length = length 51 | 52 | 53 | class ProductionConfig: 54 | SIZE_MAX = 128 55 | MAGIC_NUMBER = 0xF6DD37E7 56 | VERSION = 1 57 | HEADER_FORMAT = '> 8) ^ c)) 140 | return (~crc & 0xFFFFFFFF) 141 | 142 | def generate(self, path, offset=DEFAULT_OFFSET): 143 | # Calculate the CRC-16 of the install code 144 | self._struct = (struct.pack(self.HEADER_FORMAT, 145 | struct.calcsize(self.HEADER_FORMAT) + 4 + self._ad_len, # Plus the CRC-32; plus the app_data 146 | self.VERSION, 147 | self._parsed_values["channel_mask"], 148 | self._parsed_values["extended_address"], 149 | self._parsed_values["tx_power"], 150 | self._parsed_values["install_code"], 151 | self._ic_crc) + 152 | self._parsed_values["app_data"]) 153 | 154 | crc32 = self._custom_crc32(self._struct) 155 | 156 | output = struct.pack(' self.SIZE_MAX + 4: # 4 is for Magic Number 159 | raise ProductionConfigTooLargeException(len(output)) 160 | 161 | ih = intelhex.IntelHex() 162 | ih.puts(offset, output) 163 | ih.write_hex_file(path) 164 | 165 | 166 | def format_offsets(offset_dict: dict): 167 | result = "" 168 | for sdk, boards in offset_dict.items(): 169 | result += f"{sdk}:\n" 170 | for board, offset in boards.items(): 171 | result += f"- {board}: {hex(offset)}\n" 172 | return result 173 | -------------------------------------------------------------------------------- /nordicsemi/dfu/init_packet_pb.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Copyright (c) 2016 Nordic Semiconductor ASA 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without modification, 7 | # are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 13 | # list of conditions and the following disclaimer in the documentation and/or 14 | # other materials provided with the distribution. 15 | # 16 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 17 | # contributors to this software may be used to endorse or promote products 18 | # derived from this software without specific prior written permission. 19 | # 20 | # 4. This software must only be used in or with a processor manufactured by Nordic 21 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 22 | # is used in combination with a processor manufactured by Nordic Semiconductor. 23 | # 24 | # 5. Any software provided in binary or object form under this license must not be 25 | # reverse engineered, decompiled, modified and/or disassembled. 26 | # 27 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 28 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 31 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 32 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 34 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | # 38 | from . import dfu_cc_pb2 as pb 39 | from enum import Enum 40 | 41 | class SigningTypes(Enum): 42 | ECDSA_P256_SHA256 = pb.ECDSA_P256_SHA256 43 | ED25519 = pb.ED25519 44 | 45 | class CommandTypes(Enum): 46 | INIT = pb.INIT 47 | 48 | class HashTypes(Enum): 49 | NONE = pb.NO_HASH 50 | CRC = pb.CRC 51 | SHA128 = pb.SHA128 52 | SHA256 = pb.SHA256 53 | SHA512 = pb.SHA512 54 | 55 | 56 | class DFUType(Enum): 57 | APPLICATION = pb.APPLICATION 58 | SOFTDEVICE = pb.SOFTDEVICE 59 | BOOTLOADER = pb.BOOTLOADER 60 | SOFTDEVICE_BOOTLOADER = pb.SOFTDEVICE_BOOTLOADER 61 | EXTERNAL_APPLICATION = pb.EXTERNAL_APPLICATION 62 | 63 | class ValidationTypes(Enum): 64 | NO_VALIDATION = pb.NO_VALIDATION 65 | VALIDATE_GENERATED_CRC = pb.VALIDATE_GENERATED_CRC 66 | VALIDATE_GENERATED_SHA256 = pb.VALIDATE_SHA256 67 | VALIDATE_ECDSA_P256_SHA256 = pb.VALIDATE_ECDSA_P256_SHA256 68 | 69 | class InitPacketPB: 70 | def __init__(self, 71 | from_bytes = None, 72 | hash_bytes = None, 73 | hash_type = None, 74 | boot_validation_type = [], 75 | boot_validation_bytes = [], 76 | dfu_type = None, 77 | is_debug=False, 78 | fw_version=0xffffffff, 79 | hw_version=0xffffffff, 80 | sd_size=0, 81 | app_size=0, 82 | bl_size=0, 83 | sd_req=None 84 | ): 85 | 86 | if from_bytes is not None: 87 | # construct from a protobuf string/buffer 88 | self.packet = pb.Packet() 89 | self.packet.ParseFromString(from_bytes) 90 | 91 | if self.packet.HasField('signed_command'): 92 | self.init_command = self.packet.signed_command.command.init 93 | else: 94 | self.init_command = self.packet.command.init 95 | 96 | else: 97 | # construct from input variables 98 | if not sd_req: 99 | sd_req = [0xfffe] # Set to default value 100 | self.packet = pb.Packet() 101 | 102 | boot_validation = [] 103 | for i, x in enumerate(boot_validation_type): 104 | boot_validation.append(pb.BootValidation(type=x.value, bytes=boot_validation_bytes[i])) 105 | 106 | # By default, set the packet's command to an unsigned command 107 | # If a signature is set (via set_signature), this will get overwritten 108 | # with an instance of SignedCommand instead. 109 | self.packet.command.op_code = pb.INIT 110 | 111 | self.init_command = pb.InitCommand() 112 | self.init_command.hash.hash_type = hash_type.value 113 | self.init_command.type = dfu_type.value 114 | self.init_command.hash.hash = hash_bytes 115 | self.init_command.is_debug = is_debug 116 | self.init_command.fw_version = fw_version 117 | self.init_command.hw_version = hw_version 118 | self.init_command.sd_req.extend(list(set(sd_req))) 119 | self.init_command.sd_size = sd_size 120 | self.init_command.bl_size = bl_size 121 | self.init_command.app_size = app_size 122 | 123 | self.init_command.boot_validation.extend(boot_validation) 124 | self.packet.command.init.CopyFrom(self.init_command) 125 | 126 | self._validate() 127 | 128 | def _validate(self): 129 | if (self.init_command.type == pb.APPLICATION or self.init_command.type == pb.EXTERNAL_APPLICATION ) and self.init_command.app_size == 0: 130 | raise RuntimeError("app_size is not set. It must be set when type is APPLICATION/EXTERNAL_APPLICATION") 131 | elif self.init_command.type == pb.SOFTDEVICE and self.init_command.sd_size == 0: 132 | raise RuntimeError("sd_size is not set. It must be set when type is SOFTDEVICE") 133 | elif self.init_command.type == pb.BOOTLOADER and self.init_command.bl_size == 0: 134 | raise RuntimeError("bl_size is not set. It must be set when type is BOOTLOADER") 135 | elif self.init_command.type == pb.SOFTDEVICE_BOOTLOADER and \ 136 | (self.init_command.sd_size == 0 or self.init_command.bl_size == 0): 137 | raise RuntimeError("Either sd_size or bl_size is not set. Both must be set when type " 138 | "is SOFTDEVICE_BOOTLOADER") 139 | 140 | if self.init_command.fw_version < 0 or self.init_command.fw_version > 0xffffffff or \ 141 | self.init_command.hw_version < 0 or self.init_command.hw_version > 0xffffffff: 142 | raise RuntimeError("Invalid range of firmware argument. [0 - 0xffffffff] is valid range") 143 | 144 | def _is_valid(self): 145 | try: 146 | self._validate() 147 | except RuntimeError: 148 | return False 149 | 150 | return self.signed_command.signature is not None 151 | 152 | def get_init_packet_pb_bytes(self): 153 | return self.packet.SerializeToString() 154 | 155 | def get_init_command_bytes(self): 156 | return self.init_command.SerializeToString() 157 | 158 | def set_signature(self, signature, signature_type): 159 | new_packet = pb.Packet() 160 | new_packet.signed_command.signature = signature 161 | new_packet.signed_command.signature_type = signature_type.value 162 | new_packet.signed_command.command.CopyFrom(self.packet.command) 163 | 164 | self.packet = new_packet 165 | 166 | def __str__(self): 167 | return str(self.init_command) 168 | -------------------------------------------------------------------------------- /nordicsemi/dfu/dfu_transport.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 - 2019 Nordic Semiconductor ASA 2 | # All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without modification, 5 | # are permitted provided that the following conditions are met: 6 | # 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | # 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 11 | # list of conditions and the following disclaimer in the documentation and/or 12 | # other materials provided with the distribution. 13 | # 14 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 15 | # contributors to this software may be used to endorse or promote products 16 | # derived from this software without specific prior written permission. 17 | # 18 | # 4. This software must only be used in or with a processor manufactured by Nordic 19 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 20 | # is used in combination with a processor manufactured by Nordic Semiconductor. 21 | # 22 | # 5. Any software provided in binary or object form under this license must not be 23 | # reverse engineered, decompiled, modified and/or disassembled. 24 | # 25 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 29 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 32 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | import logging 37 | 38 | from abc import ABC, abstractmethod 39 | 40 | # Nordic Semiconductor imports 41 | 42 | logger = logging.getLogger(__name__) 43 | 44 | 45 | # Custom logging level for logging all transport events, including all bytes 46 | # being transported over the wire or over the air. 47 | # Note that this logging level is more verbose than logging.DEBUG. 48 | TRANSPORT_LOGGING_LEVEL = 5 49 | 50 | 51 | class DfuEvent: 52 | PROGRESS_EVENT = 1 53 | 54 | 55 | class DfuTransport(ABC): 56 | """ 57 | This class as an abstract base class inherited from when implementing transports. 58 | 59 | The class is generic in nature, the underlying implementation may have missing semantic 60 | than this class describes. But the intent is that the implementer shall follow the semantic as 61 | best as she can. 62 | """ 63 | 64 | OP_CODE = { 65 | 'CreateObject' : 0x01, 66 | 'SetPRN' : 0x02, 67 | 'CalcChecSum' : 0x03, 68 | 'Execute' : 0x04, 69 | 'ReadObject' : 0x06, 70 | 'Response' : 0x60, 71 | } 72 | 73 | RES_CODE = { 74 | 'InvalidCode' : 0x00, 75 | 'Success' : 0x01, 76 | 'NotSupported' : 0x02, 77 | 'InvalidParameter' : 0x03, 78 | 'InsufficientResources' : 0x04, 79 | 'InvalidObject' : 0x05, 80 | 'InvalidSignature' : 0x06, 81 | 'UnsupportedType' : 0x07, 82 | 'OperationNotPermitted' : 0x08, 83 | 'OperationFailed' : 0x0A, 84 | 'ExtendedError' : 0x0B, 85 | } 86 | 87 | EXT_ERROR_CODE = [ 88 | "No extended error code has been set. This error indicates an implementation problem.", 89 | "Invalid error code. This error code should never be used outside of development.", 90 | "The format of the command was incorrect. This error code is not used in the current implementation, because @ref NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED and @ref NRF_DFU_RES_CODE_INVALID_PARAMETER cover all possible format errors.", 91 | "The command was successfully parsed, but it is not supported or unknown.", 92 | "The init command is invalid. The init packet either has an invalid update type or it is missing required fields for the update type (for example, the init packet for a SoftDevice update is missing the SoftDevice size field).", 93 | "The firmware version is too low. For an application, the version must be greater than or equal to the current application. For a bootloader, it must be greater than the current version. This requirement prevents downgrade attacks.""", 94 | "The hardware version of the device does not match the required hardware version for the update.", 95 | "The array of supported SoftDevices for the update does not contain the FWID of the current SoftDevice.", 96 | "The init packet does not contain a signature, but this bootloader requires all updates to have one.", 97 | "The hash type that is specified by the init packet is not supported by the DFU bootloader.", 98 | "The hash of the firmware image cannot be calculated.", 99 | "The type of the signature is unknown or not supported by the DFU bootloader.", 100 | "The hash of the received firmware image does not match the hash in the init packet.", 101 | "The available space on the device is insufficient to hold the firmware.", 102 | "The requested firmware to update was already present on the system.", 103 | ] 104 | 105 | @abstractmethod 106 | def __init__(self): 107 | self.callbacks = {} 108 | 109 | 110 | @abstractmethod 111 | def open(self): 112 | """ 113 | Open a port if appropriate for the transport. 114 | :return: 115 | """ 116 | pass 117 | 118 | 119 | @abstractmethod 120 | def close(self): 121 | """ 122 | Close a port if appropriate for the transport. 123 | :return: 124 | """ 125 | pass 126 | 127 | @abstractmethod 128 | def send_init_packet(self, init_packet): 129 | """ 130 | Send init_packet to device. 131 | 132 | This call will block until init_packet is sent and transfer of packet is complete. 133 | 134 | :param init_packet: Init packet as a str. 135 | :return: 136 | """ 137 | pass 138 | 139 | 140 | @abstractmethod 141 | def send_firmware(self, firmware): 142 | """ 143 | Start sending firmware to device. 144 | 145 | This call will block until transfer of firmware is complete. 146 | 147 | :param firmware: 148 | :return: 149 | """ 150 | pass 151 | 152 | 153 | def register_events_callback(self, event_type, callback): 154 | """ 155 | Register a callback. 156 | 157 | :param DfuEvent callback: 158 | :return: None 159 | """ 160 | if event_type not in self.callbacks: 161 | self.callbacks[event_type] = [] 162 | 163 | self.callbacks[event_type].append(callback) 164 | 165 | 166 | def _send_event(self, event_type, **kwargs): 167 | """ 168 | Method for sending events to registered callbacks. 169 | 170 | If callbacks throws exceptions event propagation will stop and this method be part of the track trace. 171 | 172 | :param DfuEvent event_type: 173 | :param kwargs: Arguments to callback function 174 | :return: 175 | """ 176 | if event_type in list(self.callbacks.keys()): 177 | for callback in self.callbacks[event_type]: 178 | callback(**kwargs) 179 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | - test-azure 3 | - master 4 | - release/* 5 | 6 | jobs: 7 | # Linux 8 | - job: Linux 9 | strategy: 10 | matrix: 11 | py36: 12 | python_version: "3.6" 13 | py37: 14 | python_version: "3.7" 15 | py38: 16 | python_version: "3.8" 17 | pool: 18 | vmImage: "ubuntu-18.04" 19 | steps: 20 | - task: UsePythonVersion@0 21 | inputs: 22 | versionSpec: "$(python_version)" 23 | - bash: | 24 | pip install setuptools 25 | pip install -r requirements-frozen.txt 26 | python setup.py sdist 27 | displayName: "Build tar.gz with python $(python_version)" 28 | - bash: | 29 | pip install https://github.com/pyinstaller/pyinstaller/archive/develop.tar.gz 30 | pyinstaller nrfutil.spec 31 | displayName: "Build executable with python $(python_version)" 32 | - bash: | 33 | python setup.py test 34 | displayName: "Regression tests for python $(python_version)" 35 | - bash: | 36 | dist/nrfutil keys generate key-test.txt 37 | dist/nrfutil keys display --key pk --format code key-test.txt 38 | displayName: "Smoke test for python $(python_version)" 39 | - bash: | 40 | mv dist/nrfutil dist/nrfutil-linux 41 | cp -R dist/nrfutil-linux "$(Build.ArtifactStagingDirectory)" 42 | condition: eq(variables['python_version'], '3.7') 43 | displayName: "Copy artifacts" 44 | - task: GitHubRelease@0 45 | inputs: 46 | gitHubConnection: "waylandCI" 47 | repositoryName: "NordicSemiconductor/pc-nrfutil" 48 | action: "edit" 49 | tagSource: "Git tag" 50 | tag: "$(Build.SourceBranchName)" 51 | assetUploadMode: "replace" 52 | isDraft: "true" 53 | addChangeLog: "false" 54 | condition: ne(variables['Build.Reason'], 'PullRequest') 55 | 56 | # macOS 57 | - job: macOS 58 | strategy: 59 | matrix: 60 | py36: 61 | python_version: '3.6.8' 62 | python_bin: '3.6' 63 | py37: 64 | python_version: '3.7.5' 65 | python_bin: '3.7' 66 | py38: 67 | python_version: '3.8.0' 68 | python_bin: '3.8' 69 | pool: 70 | vmImage: "macos-10.15" 71 | steps: 72 | - bash: | 73 | wget https://www.python.org/ftp/python/$(python_version)/python-$(python_version)-macosx10.9.pkg 74 | sudo installer -pkg python-$(python_version)-macosx10.9.pkg -target / 75 | displayName: 'Install python $(python_version)' 76 | - bash: | 77 | pypath=`which python$(python_bin)` 78 | ${pypath} -m pip install setuptools 79 | ${pypath} -m pip install -r requirements-frozen.txt 80 | ${pypath} setup.py sdist 81 | displayName: "Build tar.gz with python $(python_version)" 82 | - bash: | 83 | pypath=`which python$(python_bin)` 84 | ${pypath} -m pip install https://github.com/pyinstaller/pyinstaller/archive/develop.tar.gz 85 | export PATH=/Library/Frameworks/Python.framework/Versions/$(python_bin)/bin:$PATH 86 | pyinstaller nrfutil.spec 87 | displayName: "Build executable with python $(python_version)" 88 | - bash: | 89 | pypath=`which python$(python_bin)` 90 | ${pypath} setup.py test 91 | displayName: "Regression tests for python $(python_version)" 92 | - bash: | 93 | dist/nrfutil keys generate key-test.txt 94 | dist/nrfutil keys display --key pk --format code key-test.txt 95 | displayName: "Smoke test for python $(python_version)" 96 | - bash: | 97 | mv dist/nrfutil dist/nrfutil-mac 98 | cp -R dist/nrfutil-mac "$(Build.ArtifactStagingDirectory)" 99 | condition: eq(variables['python_version'], '3.7.5') 100 | displayName: "Copy artifacts" 101 | - task: GitHubRelease@0 102 | inputs: 103 | gitHubConnection: "waylandCI" 104 | repositoryName: "NordicSemiconductor/pc-nrfutil" 105 | action: "edit" 106 | tagSource: "Git tag" 107 | tag: "$(Build.SourceBranchName)" 108 | assetUploadMode: "replace" 109 | isDraft: "true" 110 | addChangeLog: "false" 111 | condition: ne(variables['Build.Reason'], 'PullRequest') 112 | 113 | 114 | 115 | # Windows 116 | - job: Windows 117 | strategy: 118 | matrix: 119 | py36_win32: 120 | python_version: "3.6" 121 | python_arch: "x86" 122 | py36_win64: 123 | python_version: "3.6" 124 | python_arch: "x64" 125 | py37_win32: 126 | python_version: "3.7" 127 | python_arch: "x86" 128 | py37_win64: 129 | python_version: "3.7" 130 | python_arch: "x64" 131 | py38_win32: 132 | python_version: "3.8" 133 | python_arch: "x86" 134 | py38_win64: 135 | python_version: "3.8" 136 | python_arch: "x64" 137 | pool: 138 | vmImage: "vs2017-win2016" 139 | steps: 140 | - task: UsePythonVersion@0 141 | inputs: 142 | versionSpec: "$(python_version)" 143 | architecture: "$(python_arch)" 144 | - bash: | 145 | pip install -r requirements-frozen.txt 146 | pip install --upgrade setuptools==42.0.0 147 | pip install wheel 148 | python setup.py sdist 149 | displayName: "Build tar.gz with python $(python_version)" 150 | - bash: | 151 | pip install https://github.com/pyinstaller/pyinstaller/archive/develop.tar.gz 152 | pyinstaller nrfutil.spec 153 | displayName: "Build exe with python $(python_version)" 154 | - bash: | 155 | python setup.py test 156 | displayName: "Regression tests for python $(python_version)" 157 | - bash: | 158 | dist/nrfutil keys generate key-test.txt 159 | dist/nrfutil keys display --key pk --format code key-test.txt 160 | displayName: "Smoke test for python $(python_version)" 161 | - bash: | 162 | cp -R dist/*.tar.gz "$(Build.ArtifactStagingDirectory)" 163 | cp -R dist/*.exe "$(Build.ArtifactStagingDirectory)" 164 | condition: and(eq(variables['python_arch'], 'x64'), eq(variables['python_version'], '3.7')) 165 | displayName: "Copy artifacts" 166 | - task: GitHubRelease@0 167 | inputs: 168 | gitHubConnection: "waylandCI" 169 | repositoryName: "NordicSemiconductor/pc-nrfutil" 170 | action: "edit" 171 | tagSource: "Git tag" 172 | tag: "$(Build.SourceBranchName)" 173 | assetUploadMode: "replace" 174 | isDraft: "true" 175 | addChangeLog: "false" 176 | condition: ne(variables['Build.Reason'], 'PullRequest') 177 | 178 | # 179 | - job: TriggerTest 180 | dependsOn: [ 181 | Windows, 182 | Linux, 183 | macOS, 184 | ] 185 | strategy: 186 | matrix: 187 | linux: 188 | osType: 'linux' 189 | mac: 190 | osType: 'mac' 191 | win64: 192 | osType: 'win64' 193 | win32: 194 | osType: 'win32' 195 | pool: server 196 | steps: 197 | - task: InvokeRESTAPI@1 198 | displayName: 'Trigger test (check test result on Jenkins)' 199 | inputs: 200 | connectionType: 'connectedServiceName' 201 | serviceConnection: 'waylandJenkins' 202 | method: 'POST' 203 | urlSuffix: 'view/pc-nrfutil/job/pc-nrfutil-$(osType)/buildWithParameters?BRANCH=$(Build.SourceBranch)&VSTS_URL=$(system.CollectionUri)&TOKEN=$(system.AccessToken)&PROJECT_ID=$(system.teamProjectId)&HUB_NAME=$(system.hostType)&PLAN_ID=$(system.planId)&TASK_ID=$(system.taskInstanceId)&JOB_ID=$(system.jobId)' 204 | waitForCompletion: 'false' 205 | condition: ne(variables['Build.Reason'], 'PullRequest') 206 | -------------------------------------------------------------------------------- /nordicsemi/dfu/tests/test_package.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import json 39 | import os 40 | import tempfile 41 | import unittest 42 | from zipfile import ZipFile 43 | import shutil 44 | 45 | from nordicsemi.dfu.package import Package 46 | from nordicsemi.dfu.signing import Signing 47 | 48 | 49 | class TestPackage(unittest.TestCase): 50 | def setUp(self): 51 | self.work_directory = tempfile.mkdtemp(prefix="nrf_dfu_tests_") 52 | 53 | def tearDown(self): 54 | shutil.rmtree(self.work_directory, ignore_errors=True) 55 | 56 | def test_generate_package_application(self): 57 | signer = Signing() 58 | signer.load_key('key.pem') 59 | 60 | self.p = Package(app_version=100, 61 | sd_req=[0x1000, 0xfffe], 62 | app_fw="firmwares/bar.hex", 63 | signer=signer 64 | ) 65 | 66 | pkg_name = "mypackage.zip" 67 | 68 | self.p.generate_package(pkg_name, preserve_work_dir=False) 69 | expected_zip_content = ["manifest.json", "bar.bin", "bar.dat"] 70 | 71 | with ZipFile(pkg_name, 'r') as pkg: 72 | infolist = pkg.infolist() 73 | 74 | for file_information in infolist: 75 | self.assertTrue(file_information.filename in expected_zip_content) 76 | self.assertGreater(file_information.file_size, 0) 77 | 78 | # Extract all and load json document to see if it is correct regarding to paths 79 | pkg.extractall(self.work_directory) 80 | 81 | with open(os.path.join(self.work_directory, 'manifest.json'), 'r') as f: 82 | _json = json.load(f) 83 | self.assertEqual('bar.bin', _json['manifest']['application']['bin_file']) 84 | self.assertEqual('bar.dat', _json['manifest']['application']['dat_file']) 85 | self.assertTrue('softdevice' not in _json['manifest']) 86 | self.assertTrue('softdevice_bootloader' not in _json['manifest']) 87 | self.assertTrue('bootloader' not in _json['manifest']) 88 | 89 | def test_generate_package_sd_bl(self): 90 | signer = Signing() 91 | signer.load_key('key.pem') 92 | 93 | self.p = Package(app_version=100, 94 | sd_req=[0x1000, 0xfffe], 95 | softdevice_fw="firmwares/foo.hex", 96 | bootloader_fw="firmwares/bar.hex", 97 | signer=signer) 98 | 99 | 100 | pkg_name = "mypackage.zip" 101 | 102 | self.p.generate_package(pkg_name, preserve_work_dir=False) 103 | 104 | expected_zip_content = ["manifest.json", "sd_bl.bin", "sd_bl.dat"] 105 | 106 | with ZipFile(pkg_name, 'r') as pkg: 107 | infolist = pkg.infolist() 108 | 109 | for file_information in infolist: 110 | self.assertTrue(file_information.filename in expected_zip_content) 111 | self.assertGreater(file_information.file_size, 0) 112 | 113 | # Extract all and load json document to see if it is correct regarding to paths 114 | pkg.extractall(self.work_directory) 115 | 116 | with open(os.path.join(self.work_directory, 'manifest.json'), 'r') as f: 117 | _json = json.load(f) 118 | self.assertEqual('sd_bl.bin', _json['manifest']['softdevice_bootloader']['bin_file']) 119 | self.assertEqual('sd_bl.dat', _json['manifest']['softdevice_bootloader']['dat_file']) 120 | 121 | def test_unpack_package_a(self): 122 | signer = Signing() 123 | signer.load_key('key.pem') 124 | 125 | self.p = Package(app_version=100, 126 | sd_req=[0x1000, 0xffff], 127 | softdevice_fw="firmwares/bar.hex", 128 | signer=signer) 129 | pkg_name = os.path.join(self.work_directory, "mypackage.zip") 130 | self.p.generate_package(pkg_name, preserve_work_dir=False) 131 | 132 | unpacked_dir = os.path.join(self.work_directory, "unpacked") 133 | manifest = self.p.unpack_package(os.path.join(self.work_directory, pkg_name), unpacked_dir) 134 | self.assertIsNotNone(manifest) 135 | self.assertEqual('bar.bin', manifest.softdevice.bin_file) 136 | # self.assertEqual(0, manifest.softdevice.init_packet_data.ext_packet_id) 137 | # self.assertIsNotNone(manifest.softdevice.init_packet_data.firmware_crc16) 138 | 139 | def test_unpack_package_b(self): 140 | signer = Signing() 141 | signer.load_key('key.pem') 142 | 143 | self.p = Package(app_version=100, 144 | sd_req=[0x1000, 0xffff], 145 | softdevice_fw="firmwares/bar.hex", 146 | signer=signer) 147 | pkg_name = os.path.join(self.work_directory, "mypackage.zip") 148 | self.p.generate_package(pkg_name, preserve_work_dir=False) 149 | 150 | unpacked_dir = os.path.join(self.work_directory, "unpacked") 151 | manifest = self.p.unpack_package(os.path.join(self.work_directory, pkg_name), unpacked_dir) 152 | self.assertIsNotNone(manifest) 153 | self.assertEqual('bar.bin', manifest.softdevice.bin_file) 154 | 155 | def test_unpack_package_c(self): 156 | signer = Signing() 157 | signer.load_key('key.pem') 158 | 159 | self.p = Package(app_version=100, 160 | sd_req=[0x1000, 0xffff], 161 | softdevice_fw="firmwares/bar.hex", 162 | signer=signer) 163 | pkg_name = os.path.join(self.work_directory, "mypackage.zip") 164 | self.p.generate_package(pkg_name, preserve_work_dir=False) 165 | 166 | unpacked_dir = os.path.join(self.work_directory, "unpacked") 167 | manifest = self.p.unpack_package(os.path.join(self.work_directory, pkg_name), unpacked_dir) 168 | self.assertIsNotNone(manifest) 169 | self.assertEqual('bar.bin', manifest.softdevice.bin_file) 170 | 171 | 172 | if __name__ == '__main__': 173 | unittest.main() 174 | -------------------------------------------------------------------------------- /nordicsemi/dfu/manifest.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | # Python libraries 39 | import json 40 | import os 41 | 42 | # Nordic libraries 43 | from nordicsemi.dfu.model import HexType, FirmwareKeys 44 | 45 | 46 | class ManifestGenerator: 47 | def __init__(self, firmwares_data): 48 | """ 49 | The Manifest Generator constructor. Needs a data structure to generate a manifest from. 50 | 51 | :type dict firmwares_data: The firmwares data structure describing the Nordic DFU package 52 | """ 53 | self.firmwares_data = firmwares_data 54 | self.manifest = None 55 | 56 | def generate_manifest(self): 57 | self.manifest = Manifest() 58 | 59 | for key in self.firmwares_data: 60 | firmware_dict = self.firmwares_data[key] 61 | 62 | if key == HexType.SD_BL: 63 | _firmware = SoftdeviceBootloaderFirmware() 64 | _firmware.info_read_only_metadata = FWMetaData() 65 | _firmware.info_read_only_metadata.bl_size = firmware_dict[FirmwareKeys.BL_SIZE] 66 | _firmware.info_read_only_metadata.sd_size = firmware_dict[FirmwareKeys.SD_SIZE] 67 | else: 68 | _firmware = Firmware() 69 | 70 | 71 | # Strip path, add only filename 72 | _firmware.bin_file = os.path.basename(firmware_dict[FirmwareKeys.BIN_FILENAME]) 73 | _firmware.dat_file = os.path.basename(firmware_dict[FirmwareKeys.DAT_FILENAME]) 74 | 75 | if key == HexType.APPLICATION or key == HexType.EXTERNAL_APPLICATION: 76 | self.manifest.application = _firmware 77 | elif key == HexType.BOOTLOADER: 78 | self.manifest.bootloader = _firmware 79 | elif key == HexType.SOFTDEVICE: 80 | self.manifest.softdevice = _firmware 81 | elif key == HexType.SD_BL: 82 | self.manifest.softdevice_bootloader = _firmware 83 | else: 84 | raise NotImplementedError("Support for firmware type {0} not implemented yet.".format(key)) 85 | 86 | return self.to_json() 87 | 88 | def to_json(self): 89 | def remove_none_entries(d): 90 | if not isinstance(d, dict): 91 | return d 92 | 93 | return dict((k, remove_none_entries(v)) for k, v in d.items() if v is not None) 94 | 95 | return json.dumps({'manifest': self.manifest}, 96 | default=lambda o: remove_none_entries(o.__dict__), 97 | sort_keys=True, indent=4, 98 | separators=(',', ': ')) 99 | 100 | 101 | class FWMetaData: 102 | def __init__(self, 103 | is_debug=None, 104 | hw_version=None, 105 | fw_version=None, 106 | softdevice_req=None, 107 | sd_size=None, 108 | bl_size=None 109 | ): 110 | """ 111 | The FWMetaData data model. 112 | 113 | :param bool is_debug: debug mode on 114 | :param int hw_version: hardware version 115 | :param int fw_version: application or bootloader version 116 | :param list softdevice_req: softdevice requirements 117 | :param int sd_size SoftDevice size 118 | :param int bl_size Bootloader size 119 | :return:FWMetaData 120 | """ 121 | self.is_debug = is_debug 122 | self.hw_version = hw_version 123 | self.fw_version = fw_version 124 | self.softdevice_req = softdevice_req 125 | self.sd_size = sd_size 126 | self.bl_size = bl_size 127 | 128 | 129 | class Firmware: 130 | def __init__(self, 131 | bin_file=None, 132 | dat_file=None, 133 | info_read_only_metadata=None): 134 | """ 135 | The firmware datamodel 136 | 137 | :param str bin_file: Firmware binary file 138 | :param str dat_file: Firmware .dat file (init packet for Nordic DFU) 139 | :param int info_read_only_metadata: The metadata about this firwmare image 140 | :return: 141 | """ 142 | self.dat_file = dat_file 143 | self.bin_file = bin_file 144 | 145 | if info_read_only_metadata: 146 | self.info_read_only_metadata = FWMetaData(**info_read_only_metadata) 147 | else: 148 | self.info_read_only_metadata = None 149 | 150 | 151 | class SoftdeviceBootloaderFirmware(Firmware): 152 | def __init__(self, 153 | bin_file=None, 154 | dat_file=None, 155 | info_read_only_metadata=None): 156 | """ 157 | The SoftdeviceBootloaderFirmware data model 158 | 159 | :param str bin_file: Firmware binary file 160 | :param str dat_file: Firmware .dat file (init packet for Nordic DFU) 161 | :param int info_read_only_metadata: The metadata about this firwmare image 162 | :return: SoftdeviceBootloaderFirmware 163 | """ 164 | super().__init__( 165 | bin_file, 166 | dat_file, 167 | info_read_only_metadata) 168 | 169 | class Manifest: 170 | def __init__(self, 171 | application=None, 172 | bootloader=None, 173 | softdevice=None, 174 | softdevice_bootloader=None): 175 | """ 176 | The Manifest data model. 177 | 178 | :param dict application: Application firmware in package 179 | :param dict bootloader: Bootloader firmware in package 180 | :param dict softdevice: Softdevice firmware in package 181 | :param dict softdevice_bootloader: Combined softdevice and bootloader firmware in package 182 | :return: Manifest 183 | """ 184 | self.softdevice_bootloader = \ 185 | SoftdeviceBootloaderFirmware(**softdevice_bootloader) if softdevice_bootloader else None 186 | 187 | self.softdevice = Firmware(**softdevice) if softdevice else None 188 | self.bootloader = Firmware(**bootloader) if bootloader else None 189 | self.application = Firmware(**application) if application else None 190 | 191 | @staticmethod 192 | def from_json(data): 193 | """ 194 | Parses a manifest according to Nordic DFU package specification. 195 | 196 | :param str data: The manifest in string format 197 | :return: Manifest 198 | """ 199 | kwargs = json.loads(data) 200 | return Manifest(**kwargs['manifest']) 201 | -------------------------------------------------------------------------------- /nordicsemi/zigbee/ota_file.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Nordic Semiconductor ASA 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without modification, 6 | # are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | # list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of Nordic Semiconductor ASA nor the names of other 16 | # contributors to this software may be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # 4. This software must only be used in or with a processor manufactured by Nordic 20 | # Semiconductor ASA, or in or with a processor manufactured by a third party that 21 | # is used in combination with a processor manufactured by Nordic Semiconductor. 22 | # 23 | # 5. Any software provided in binary or object form under this license must not be 24 | # reverse engineered, decompiled, modified and/or disassembled. 25 | # 26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 27 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | # 37 | 38 | import struct 39 | 40 | OTA_UPGRADE_FILE_HEADER_FILE_ID = 0x0BEEF11E 41 | OTA_UPGRADE_FILE_HEADER_FILE_VERSION = 0x0100 42 | OTA_UPGRADE_FILE_HEADER_LENGTH = 4 + 2 + 2 + 2 + 2 + 2 + 4 + 2 + 32 + 4 43 | OTA_UPGRADE_FIELD_CONTROL = 0x00 44 | OTA_UPGRADE_MANUFACTURER_WILDCARD = 0xFFFF 45 | OTA_UPGRADE_IMAGE_TYPE_WILDCARD = 0xFFFF 46 | OTA_UPGRADE_FILE_HEADER_STACK_PRO = 0x0002 47 | 48 | OTA_UPGRADE_SUBELEMENT_HEADER_SIZE = 2 + 4 # Tag ID + Length Field 49 | OTA_UPGRADE_SUBELEMENT_TRIGGER_TYPE = 0xCDEF 50 | OTA_UPGRADE_SUBELEMENT_TRIGGER_LENGTH = 1 + 4 + 4 + 4 + 4 # See background_dfu_trigger_t in the nRF5 SDK for explanation 51 | 52 | OTA_UPGRADE_FIELD_CONTROL_BIT_MASK_HW_VER = (1 << 2) 53 | OTA_UPGRADE_MIN_HW_VERSION_LENGTH = 2 54 | OTA_UPGRADE_MAX_HW_VERSION_LENGTH = 2 55 | ''' 56 | background_dfu_trigger_t type defined in components/iot/background_dfu/background_dfu_state.h of nRF5 SDK: 57 | 58 | /** @brief Trigger packet structure. */ 59 | typedef PACKED_STRUCT 60 | { 61 | uint8_t flags; /**< Trigger message flags. Bits 7:4 (oldest) - trigger version, bit 3 - DFU mode, bits 2:0 - reserved. */ 62 | uint32_t init_length; 63 | uint32_t init_crc; 64 | uint32_t image_length; 65 | uint32_t image_crc; 66 | } background_dfu_trigger_t; 67 | ''' 68 | 69 | class OTA_file: 70 | 71 | def __init__(self, 72 | file_version, 73 | init_cmd_len, 74 | init_cmd_crc, 75 | init_cmd, 76 | firmware_len, 77 | firmware_crc, 78 | firmware, 79 | manufacturer_code = OTA_UPGRADE_MANUFACTURER_WILDCARD, 80 | image_type = OTA_UPGRADE_IMAGE_TYPE_WILDCARD, 81 | comment = '', 82 | min_hw_version=None, 83 | max_hw_version=None): 84 | '''A constructor for the OTA file class, see Zigbee ZCL spec 11.4.2 (Zigbee Document 07-5123-06) 85 | see: http://www.zigbee.org/~zigbeeor/wp-content/uploads/2014/10/07-5123-06-zigbee-cluster-library-specification.pdf 86 | (access verified as of 2018-08-06) 87 | ''' 88 | 89 | total_len = OTA_UPGRADE_FILE_HEADER_LENGTH + 3 * OTA_UPGRADE_SUBELEMENT_HEADER_SIZE + OTA_UPGRADE_SUBELEMENT_TRIGGER_LENGTH + init_cmd_len + firmware_len 90 | 91 | ota_header = OTA_header(OTA_UPGRADE_FILE_HEADER_FILE_ID, 92 | OTA_UPGRADE_FILE_HEADER_FILE_VERSION, 93 | OTA_UPGRADE_FILE_HEADER_LENGTH, 94 | OTA_UPGRADE_FIELD_CONTROL, 95 | manufacturer_code, 96 | image_type, 97 | file_version, 98 | OTA_UPGRADE_FILE_HEADER_STACK_PRO, 99 | comment, 100 | total_len, 101 | min_hw_version, 102 | max_hw_version) 103 | 104 | subelement_header_pack_format = '