Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Kevin Townsend committed Nov 17, 2017
1 parent c4d7bfa commit 07b4383
Show file tree
Hide file tree
Showing 109 changed files with 23,158 additions and 2 deletions.
47 changes: 45 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,45 @@
# nRF52_nrfutil
Modified version of Nordic's nrfutil 0.5.2 for use with the Adafruit Feather nRF52
# nrfutil

`nrfutil` is a Python package that includes the nrfutil command line utility
and the nordicsemi library.

This tool can be used used with the [Adafruit nRF52 Feather](https://www.adafruit.com/product/3406)
to flash firmware images onto the device using the simple serial port.

This library is written for Python 2.7.

# Installation

Run the following commands to make `nrfutil` available from the command line
or to development platforms like the Arduino IDE or CircuitPython:

```
$ sudo pip install -r requirements.txt
$ sudo python setup.py install
```

**Notes** : Do **NOT** install nrfutil from the pip package (ex. `sudo pip
install nrfutil`). The latest nrfutil does not support DFU via Serial, and you
should install the local copy of 0.5.2 included with the BSP via the `python
setup.py install` command above.

# Usage

To get info on usage of nrfutil:

```
nrfutil --help
```

To convert an nRF52 .hex file into a DFU pkg file that the serial bootloader
can make use of:

```
nrfutil dfu genpkg --dev-type 0x0052 --application firmware.hex dfu-package.zip
```

To flash a DFU pkg file over serial:

```
nrfutil dfu serial --package dfu-package.zip -p /dev/tty.SLAB_USBtoUART -b 115200
```
Binary file added binaries/win32/nrfutil.exe
Binary file not shown.
29 changes: 29 additions & 0 deletions build/lib/nordicsemi/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright (c) 2015, Nordic Semiconductor
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of Nordic Semiconductor ASA nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""Package marker file."""
303 changes: 303 additions & 0 deletions build/lib/nordicsemi/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
# Copyright (c) 2015, Nordic Semiconductor
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of Nordic Semiconductor ASA nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""nrfutil command line tool."""
import logging
import os
import click

from nordicsemi.dfu.dfu import Dfu
from nordicsemi.dfu.dfu_transport import DfuEvent
from nordicsemi.dfu.dfu_transport_serial import DfuTransportSerial
from nordicsemi.dfu.package import Package
from nordicsemi import version as nrfutil_version
from nordicsemi.dfu.signing import Signing
from nordicsemi.dfu.util import query_func


class nRFException(Exception):
pass


def int_as_text_to_int(value):
try:
if value[:2].lower() == '0x':
return int(value[2:], 16)
elif value[:1] == '0':
return int(value, 8)
return int(value, 10)
except ValueError:
raise nRFException('%s is not a valid integer' % value)


class BasedIntOrNoneParamType(click.ParamType):
name = 'Int or None'

def convert(self, value, param, ctx):
try:
if value.lower() == 'none':
return 'none'
return int_as_text_to_int(value)
except nRFException:
self.fail('%s is not a valid integer' % value, param, ctx)

BASED_INT_OR_NONE = BasedIntOrNoneParamType()


class TextOrNoneParamType(click.ParamType):
name = 'Text or None'

def convert(self, value, param, ctx):
return value

TEXT_OR_NONE = TextOrNoneParamType()


@click.group()
@click.option('--verbose',
help='Show verbose information',
is_flag=True)
def cli(verbose):
if verbose:
logging.basicConfig(format='%(message)s', level=logging.INFO)
else:
logging.basicConfig(format='%(message)s')


@cli.command()
def version():
"""Displays nrf utility version."""
click.echo("nrfutil version {}".format(nrfutil_version.NRFUTIL_VERSION))


@cli.command(short_help='Generate keys for signing or generate public keys')
@click.argument('key_file', required=True)
@click.option('--gen-key',
help='generate signing key and store at given path (pem-file)',
type=click.BOOL,
is_flag=True)
@click.option('--show-vk',
help='Show the verification keys for DFU Signing (hex|code|pem)',
type=click.STRING)
def keys(key_file,
gen_key,
show_vk):
"""
This set of commands support creation of signing key (private) and showing the verification key (public)
from a previously loaded signing key. Signing key is stored in PEM format
"""
if not gen_key and show_vk is None:
raise nRFException("Use either gen-key or show-vk.")

signer = Signing()

if gen_key:
if os.path.exists(key_file):
if not query_func("File found at %s. Do you want to overwrite the file?" % key_file):
click.echo('Key generation aborted')
return

signer.gen_key(key_file)
click.echo("Generated key at: %s" % key_file)

elif show_vk:
if not os.path.isfile(key_file):
raise nRFException("No key file to load at: %s" % key_file)

signer.load_key(key_file)
click.echo(signer.get_vk(show_vk))


@cli.group()
def dfu():
"""
This set of commands support Nordic DFU OTA package generation for distribution to
applications and serial DFU.
"""
pass


@dfu.command(short_help='Generate a package for distribution to Apps supporting Nordic DFU OTA')
@click.argument('zipfile',
required=True,
type=click.Path())
@click.option('--application',
help='The application firmware file',
type=click.STRING)
@click.option('--application-version',
help='Application version, default: 0xFFFFFFFF',
type=BASED_INT_OR_NONE,
default=str(Package.DEFAULT_APP_VERSION))
@click.option('--bootloader',
help='The bootloader firmware file',
type=click.STRING)
@click.option('--dev-revision',
help='Device revision, default: 0xFFFF',
type=BASED_INT_OR_NONE,
default=str(Package.DEFAULT_DEV_REV))
@click.option('--dev-type',
help='Device type, default: 0xFFFF',
type=BASED_INT_OR_NONE,
default=str(Package.DEFAULT_DEV_TYPE))
@click.option('--dfu-ver',
help='DFU packet version to use, default: 0.5',
type=click.FLOAT,
default=Package.DEFAULT_DFU_VER)
@click.option('--sd-req',
help='SoftDevice requirement. A list of SoftDevice versions (1 or more)'
'of which one is required to be present on the target device.'
'Example: --sd-req 0x4F,0x5A. Default: 0xFFFE.',
type=TEXT_OR_NONE,
default=str(Package.DEFAULT_SD_REQ[0]))
@click.option('--softdevice',
help='The SoftDevice firmware file',
type=click.STRING)
@click.option('--key-file',
help='Signing key (pem fomat)',
type=click.Path(exists=True, resolve_path=True, file_okay=True, dir_okay=False))
def genpkg(zipfile,
application,
application_version,
bootloader,
dev_revision,
dev_type,
dfu_ver,
sd_req,
softdevice,
key_file):
"""
Generate a zipfile package for distribution to Apps supporting Nordic DFU OTA.
The application, bootloader and softdevice files are converted to .bin if it is a .hex file.
For more information on the generated init packet see:
http://developer.nordicsemi.com/nRF51_SDK/doc/7.2.0/s110/html/a00065.html
"""
zipfile_path = zipfile

if application_version == 'none':
application_version = None

if dev_revision == 'none':
dev_revision = None

if dev_type == 'none':
dev_type = None

sd_req_list = None

if sd_req.lower() == 'none':
sd_req_list = []
elif sd_req:
try:
# This will parse any string starting with 0x as base 16.
sd_req_list = sd_req.split(',')
sd_req_list = map(int_as_text_to_int, sd_req_list)
except ValueError:
raise nRFException("Could not parse value for --sd-req. "
"Hex values should be prefixed with 0x.")

if key_file and dfu_ver < 0.8:
click.echo("Key file was given, setting DFU version to 0.8")

package = Package(dev_type,
dev_revision,
application_version,
sd_req_list,
application,
bootloader,
softdevice,
dfu_ver,
key_file)

package.generate_package(zipfile_path)

log_message = "Zip created at {0}".format(zipfile_path)
click.echo(log_message)


global_bar = None


def update_progress(progress=0, done=False, log_message=""):
del done, log_message # Unused parameters
#global global_bar
#if global_bar is None:
# with click.progressbar(length=100) as bar:
# global_bar = bar
#global_bar.update(max(1, progress))
click.echo('#', nl=False)


@dfu.command(short_help="Program a device with bootloader that support serial DFU")
@click.option('-pkg', '--package',
help='DFU package filename',
type=click.Path(exists=True, resolve_path=True, file_okay=True, dir_okay=False),
required=True)
@click.option('-p', '--port',
help='Serial port COM Port to which the device is connected',
type=click.STRING,
required=True)
@click.option('-b', '--baudrate',
help='Desired baud rate 38400/96000/115200/230400/250000/460800/921600/1000000 (default: 38400). '
'Note: Physical serial ports (e.g. COM1) typically do not support baud rates > 115200',
type=click.INT,
default=DfuTransportSerial.DEFAULT_BAUD_RATE)
@click.option('-fc', '--flowcontrol',
help='Enable flow control, default: disabled',
type=click.BOOL,
is_flag=True)
def serial(package, port, baudrate, flowcontrol):
"""Program a device with bootloader that support serial DFU"""
serial_backend = DfuTransportSerial(port, baudrate, flowcontrol)
serial_backend.register_events_callback(DfuEvent.PROGRESS_EVENT, update_progress)
dfu = Dfu(package, dfu_transport=serial_backend)

click.echo("Upgrading target on {1} with DFU package {0}. Flow control is {2}."
.format(package, port, "enabled" if flowcontrol else "disabled"))

try:
dfu.dfu_send_images()

except Exception as e:
click.echo("")
click.echo("Failed to upgrade target. Error is: {0}".format(e.message))
click.echo("")
click.echo("Possible causes:")
click.echo("- Bootloader, SoftDevice or Application on target "
"does not match the requirements in the DFU package.")
click.echo("- Baud rate must be 115200, Flow control must be off.")
click.echo("- Target is not in DFU mode. Ground DFU pin and RESET and release both to enter DFU mode.")

return False

click.echo("Device programmed.")

return True


if __name__ == '__main__':
cli()
Loading

0 comments on commit 07b4383

Please sign in to comment.