Skip to content

Commit 691bb06

Browse files
committed
Refactored the Unpacker class
1 parent 4e30ae2 commit 691bb06

2 files changed

Lines changed: 68 additions & 68 deletions

File tree

README.md

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,18 @@ I've made some substantial changes to the code from the original repo, mainly:
77
* Add support for the new secure bootloader from NRF SDK 12
88

99
## What does it do?
10-
This is a Python program that uses gatttool (provided with the Linux BlueZ driver) to achieve Device Firmware Updates (DFU) to a Nordic Semiconductor nRF51/52 device via Bluetooth Low Energy (BLE).
10+
11+
This is a Python program that uses `gatttool` (provided with the Linux BlueZ driver) to achieve Over The Air (OTA) Device Firmware Updates (DFU) to a Nordic Semiconductor nRF5 (either nRF51 or nRF52) device via Bluetooth Low Energy (BLE).
1112

1213
### Main features:
1314

1415
* Perform OTA DFU to an nRF5 peripheral without an external USB BLE dongle.
1516
* Ability to detect if the peripheral is running in application mode or bootloader, and automatically switch if needed (buttonless).
1617
* Support for both Legacy (SDK <= 11) and Secure (SDK >= 12) bootloader.
1718

18-
Before using this utility the nRF peripheral device needs to be programmed with a DFU bootloader (see Nordic Semiconductor documentation/examples for instructions on that).
19+
Before using this utility the nRF5 peripheral device needs to be programmed with a DFU bootloader (see Nordic Semiconductor documentation/examples for instructions on that).
1920

20-
This project assumes you are developing and deploying to Linux system. Astronomer80 has repos for similar applications for [Windows](https://github.com/astronomer80/nrf52_bledfu_win) and [Mac OS X](https://github.com/astronomer80/nrf52_bledfu_mac).
21+
This project assumes you are developing on and deploying to a Linux system. Astronomer80 has repos for similar applications for [Windows](https://github.com/astronomer80/nrf52_bledfu_win) and [Mac OS X](https://github.com/astronomer80/nrf52_bledfu_mac).
2122

2223
## Prerequisites
2324

@@ -27,9 +28,10 @@ This project assumes you are developing and deploying to Linux system. Astronome
2728
* Python `intelhex` module (available via pip)
2829

2930
## Firmware Build Requirement
30-
* Your nRF5 peripheral firmware build method will produce a firmware file ending with either `*.hex` or `*.bin`.
31+
32+
* Your nRF5 peripheral firmware build method will produce a firmware file ending with either `*.hex` or `*.bin`.
3133
* Your nRF5 firmware build method will produce an Init file ending with `.dat`.
32-
* The Nordic naming convention is `application.bin` and `application.dat`, but this utility will accept any names.
34+
* The typical naming convention is `application.bin` and `application.dat`, but this utility will accept other names.
3335

3436
## Generating init files
3537

@@ -38,10 +40,10 @@ This project assumes you are developing and deploying to Linux system. Astronome
3840
Use the `gen_dat` application (you need to compile it with `gcc gen_dat.c -o gen_dat` on first run) to generate a `.dat` file from your `.bin` file. Example:
3941

4042
./gen_dat application.bin application.dat
41-
42-
Note: The `gen_dat` utility expects a `.bin` file input, so you'll get CRC errors during DFU using a `.dat` file generated from a `.hex` file.
4343

44-
An alternative is to use `nrfutil` from Nordic Semi, but I've found this method to be easier. You may need to edit the `gen_dat` source to fit your specific application.
44+
Note: The `gen_dat` utility expects a `.bin` file input, so you'll get Cyclic Redundancy Check (CRC) errors during DFU using a `.dat` file generated from a `.hex` file.
45+
46+
An alternative is to use `nrfutil` from Nordic Semiconductor, but I've found this method to be easier. You may need to edit the `gen_dat` source to fit your specific application.
4547

4648
### Secure bootloader
4749

@@ -51,34 +53,34 @@ Note: I've had problems with the pip version of `nrfutil`. I recommend [installi
5153

5254
## Usage
5355

54-
There are two ways to specify firmware files for this utility. Either by specifying both the `.hex` or `.bin` file with the `.dat` file, or more easily by the `.zip` file, which contains both the hex and dat files.
56+
There are two ways to specify firmware files for this utility. Either by specifying both the `.hex` or `.bin` file with the `.dat` file, or more easily by the `.zip` file, which contains both the hex and dat files.
57+
5558
The new `.zip` file form is encouraged by Nordic, but the older hex/bin + dat file methods should still work.
5659

5760
## Usage Examples
5861

5962
> sudo ./dfu.py -f ~/application.hex -d ~/application.dat -a CD:E3:4A:47:1C:E4
6063

61-
or
64+
or:
6265

63-
> sudo ./dfu.py -z ~/application.zip -a CD:E3:4A:47:1C:E4
66+
> sudo ./dfu.py -z ~/application.zip -a CD:E3:4A:47:1C:E4
6467

65-
To figure out the address of DfuTarg do a `hcitool lescan` -
68+
You can use the `hcitool lescan` to figure out the address of a DFU target, for example:
6669

67-
$ sudo hcitool -i hci0 lescan
68-
LE Scan ...
69-
CD:E3:4A:47:1C:E4 <TARGET_NAME>
70-
CD:E3:4A:47:1C:E4 (unknown)
70+
$ sudo hcitool -i hci0 lescan
71+
LE Scan ...
72+
CD:E3:4A:47:1C:E4 <TARGET_NAME>
73+
CD:E3:4A:47:1C:E4 (unknown)
7174

7275

73-
Example Output
74-
------------------------
75-
76+
## Example Output
77+
7678
================================
7779
== ==
7880
== DFU Server ==
7981
== ==
8082
================================
81-
83+
8284
Sending file application.bin to CD:E3:4A:47:1C:E4
8385
bin array size: 60788
8486
Checking DFU State...
@@ -90,14 +92,14 @@ Example Output
9092
Waiting for INIT DFU notification
9193
Begin DFU
9294
Progress: |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| 100.0% Complete (60788 of 60788 bytes)
93-
95+
9496
Upload complete in 0 minutes and 14 seconds
9597
segments sent: 3040
9698
Waiting for DFU complete notification
9799
Waiting for Firmware Validation notification
98100
Activate and reset
99101
DFU Server done
100-
102+
101103
## TODO:
102104

103105
* Implement link-loss procedure for Legacy Controller.

unpacker.py

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,52 @@
11
#!/usr/bin/env python
22

33
import os.path
4-
import zipfile
5-
import tempfile
64
import random
7-
import string
8-
import shutil
95
import re
6+
import shutil
7+
import string
8+
import tempfile
9+
import zipfile
1010

11-
from os.path import basename
1211

1312
class Unpacker(object):
14-
#--------------------------------------------------------------------------
15-
#
16-
#--------------------------------------------------------------------------
17-
def entropy(self, length):
18-
return ''.join(random.choice(string.lowercase) for i in range (length))
19-
20-
#--------------------------------------------------------------------------
21-
#
22-
#--------------------------------------------------------------------------
23-
def unpack_zipfile(self, file):
24-
25-
if not os.path.isfile(file):
26-
raise Exception("Error: file, not found!")
27-
28-
# Create unique working direction into which the zip file is expanded
29-
self.unzip_dir = "{0}/{1}_{2}".format(tempfile.gettempdir(), os.path.splitext(basename(file))[0], self.entropy(6))
30-
31-
datfilename = ""
32-
binfilename = ""
33-
34-
with zipfile.ZipFile(file, 'r') as zip:
35-
files = [item.filename for item in zip.infolist()]
36-
datfilename = [m.group(0) for f in files for m in [re.search('.*\.dat', f)] if m].pop()
37-
binfilename = [m.group(0) for f in files for m in [re.search('.*\.bin', f)] if m].pop()
38-
39-
zip.extractall(r'{0}'.format(self.unzip_dir))
40-
41-
datfile = "{0}/{1}".format(self.unzip_dir, datfilename)
42-
binfile = "{0}/{1}".format(self.unzip_dir, binfilename)
43-
44-
# print "DAT file: " + datfile
45-
# print "BIN file: " + binfile
46-
47-
return binfile, datfile
48-
49-
#--------------------------------------------------------------------------
50-
#
51-
#--------------------------------------------------------------------------
52-
def delete(self):
53-
# delete self.unzip_dir and its contents
54-
shutil.rmtree(self.unzip_dir)
13+
"""
14+
Helper class to unpack a nRF5 Device Firmware Update (DFU)
15+
based .zip file in a temporary folder and locate the .bin
16+
and associated .dat files inside of it.
17+
Removes the temporary folder on desctruction of the instance.
18+
"""
19+
20+
def __init__(self):
21+
self.unzip_dir = ''
22+
23+
def unpack_zipfile(self, zip_fname):
24+
if not os.path.isfile(zip_fname):
25+
raise Exception("Error: file '{}' not found!".format(zip_fname))
26+
# create unique working directory into which to expand the zip file
27+
rnd_str = ''.join(random.choice(string.ascii_lowercase) for i in range(6))
28+
self.unzip_dir = '{0}/{1}_{2}'.format( \
29+
tempfile.gettempdir(), \
30+
os.path.splitext(os.path.basename(zip_fname))[0], \
31+
rnd_str)
32+
bin_fname = ''
33+
dat_fname = ''
34+
with zipfile.ZipFile(zip_fname, 'r') as zf:
35+
files = [item.filename for item in zf.infolist()]
36+
bin_fname = [m.group(0) for f in files
37+
for m in [re.search('.*\.bin', f)] if m].pop()
38+
dat_fname = [m.group(0) for f in files
39+
for m in [re.search('.*\.dat', f)] if m].pop()
40+
zf.extractall(r'{0}'.format(self.unzip_dir))
41+
bin_file = '{0}/{1}'.format(self.unzip_dir, bin_fname)
42+
dat_file = '{0}/{1}'.format(self.unzip_dir, dat_fname)
43+
return bin_file, dat_file
44+
45+
def __del__(self):
46+
if self.unzip_dir:
47+
# delete self.unzip_dir and its contents
48+
shutil.rmtree(self.unzip_dir)
49+
50+
def delete(self):
51+
# delete self.unzip_dir and its contents
52+
shutil.rmtree(self.unzip_dir)

0 commit comments

Comments
 (0)