Simple Mbed Cloud Client application using features of K64 & K66
Connect to Mbed Cloud!
This example was customized a bit for FRDM-K66 and FRDM-K64F.
It depends on having an SD Card plugged in for storage of credentials. It could be changed later to use a SPI flash or other storage on a shield or wired in.
The app keeps track of how many times switch 2 (SW2) is pressed. The value can be retrieved via a GET request to Mbed Cloud.
Also, it will blink a pattern based on milisecond (ms) timing values that can be sent from Mbed Cloud. The pattern can be sent with a PUT request and the blinking sequence can be triggered by a POST request.
Diff: combine_bootloader_with_app.py
- Revision:
- 0:e13a8a944e25
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/combine_bootloader_with_app.py Tue Feb 13 10:07:23 2018 +0000
@@ -0,0 +1,253 @@
+#!/usr/bin/env python
+
+## ----------------------------------------------------------------------------
+## Copyright 2016-2017 ARM Ltd.
+##
+## SPDX-License-Identifier: Apache-2.0
+##
+## Licensed under the Apache License, Version 2.0 (the "License");
+## you may not use this file except in compliance with the License.
+## You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ----------------------------------------------------------------------------
+
+from os import path
+import json
+import hashlib, zlib, struct
+import time
+import sys
+
+'''
+define FIRMWARE_HEADER_MAGIC 0x5a51b3d4UL
+define FIRMWARE_HEADER_VERSION 2
+define ARM_UC_SHA512_SIZE (512/8)
+define ARM_UC_GUID_SIZE (128/8)
+typedef struct _arm_uc_internal_header_t
+{
+ /* Metadata-header specific magic code */
+ uint32_t headerMagic;
+
+ /* Revision number for metadata header. */
+ uint32_t headerVersion;
+
+ /* Version number accompanying the firmware. Larger numbers imply more
+ recent and preferred versions. This is used for determining the
+ selection order when multiple versions are available. For downloaded
+ firmware the manifest timestamp is used as the firmware version.
+ */
+ uint64_t firmwareVersion;
+
+ /* Total space (in bytes) occupied by the firmware BLOB. */
+ uint64_t firmwareSize;
+
+ /* Firmware hash calculated over the firmware size. Should match the hash
+ generated by standard command line tools, e.g., shasum on Linux/Mac.
+ */
+ uint8_t firmwareHash[ARM_UC_SHA512_SIZE];
+
+ /* The ID for the update campaign that resulted in the firmware update.
+ */
+ uint8_t campaign[ARM_UC_GUID_SIZE];
+
+ /* Size of the firmware signature. Must be 0 if no signature is supplied. */
+ uint32_t firmwareSignatureSize;
+
+ /* Header 32 bit CRC. Calculated over the entire header, including the CRC
+ field, but with the CRC set to zero.
+ */
+ uint32_t headerCRC;
+
+ /* Optional firmware signature. Hashing algorithm should be the same as the
+ one used for the firmware hash. The firmwareSignatureSize must be set.
+ */
+ uint8_t firmwareSignature[0];
+} arm_uc_internal_header_t;
+'''
+
+# define defaults to go into the metadata header
+SIZEOF_SHA512 = int(512/8)
+SIZEOF_GUID = int(128/8)
+FIRMWARE_HEADER_MAGIC = 0x5a51b3d4
+FIRMWARE_HEADER_VERSION = 2
+header_format = ">2I2Q{}s{}s2I".format(SIZEOF_SHA512, SIZEOF_GUID)
+
+if sys.version_info < (3,):
+ def b(x):
+ return bytearray(x)
+else:
+ def b(x):
+ return x
+
+def create_header(app_blob, firmwareVersion):
+ # calculate the hash of the application
+ firmwareHash = hashlib.sha256(app_blob).digest()
+
+ # calculate the total size which is defined as the application size + metadata header
+ firmwareSize = len(app_blob)
+
+ # set campaign GUID to 0
+ campaign = b'\00'
+
+ # signature not supported, set size to 0
+ signatureSize = 0
+
+ print ('imageSize: {}'.format(firmwareSize))
+ print ('imageHash: {}'.format(''.join(['{:0>2x}'.format(c) for c in b(firmwareHash)])))
+ print ('imageversion: {}'.format(firmwareVersion))
+
+ # construct struct for CRC calculation
+ headerCRC = 0
+ FirmwareHeader = struct.pack(header_format,
+ FIRMWARE_HEADER_MAGIC,
+ FIRMWARE_HEADER_VERSION,
+ firmwareVersion,
+ firmwareSize,
+ firmwareHash,
+ campaign,
+ signatureSize,
+ headerCRC)
+
+ # calculate checksum over header, including signatureSize but without headerCRC
+ headerCRC = zlib.crc32(FirmwareHeader[:-4]) & 0xffffffff
+
+ # Pack the data into a binary blob
+ FirmwareHeader = struct.pack(header_format,
+ FIRMWARE_HEADER_MAGIC,
+ FIRMWARE_HEADER_VERSION,
+ firmwareVersion,
+ firmwareSize,
+ firmwareHash,
+ campaign,
+ signatureSize,
+ headerCRC)
+
+ return FirmwareHeader
+
+
+def combine(bootloader_blob, app_blob, app_offset, hdr_offset, output, version):
+
+ # create header to go with the application binary
+ FirmwareHeader = create_header(app_blob, version)
+
+ # write the bootloader first
+ offset = 0
+ output.write(bootloader_blob)
+ offset += len(bootloader_blob)
+
+ # write the padding between bootloader and firmware header
+ output.write(b'\00' * (hdr_offset - offset))
+ offset += (hdr_offset - offset)
+
+ # write firmware header
+ output.write(FirmwareHeader)
+ offset += len(FirmwareHeader)
+
+ # write padding between header and application
+ output.write(b'\00' * (app_offset - offset))
+
+ # write the application
+ output.write(app_blob)
+
+
+if __name__ == '__main__':
+ import argparse
+
+ parser = argparse.ArgumentParser(
+ description='Combine bootloader with application adding metadata header.')
+
+ def offset_arg(s):
+ if s.startswith('0x'):
+ return int(s, 16)
+ else:
+ return int(s)
+
+ bin_map = {
+ 'k64f': {
+ 'mem_start': '0x0'
+ },
+ 'ublox_evk_odin_w2': {
+ 'mem_start': '0x08000000'
+ },
+ 'nucleo_f429zi': {
+ 'mem_start': '0x08000000'
+ }
+ }
+
+ curdir = path.dirname(path.abspath(__file__))
+
+ def parse_mbed_app_offset(mcu, key):
+ mem_start = bin_map[mcu]["mem_start"]
+ with open(path.join(curdir, "..", "mbed_app.json")) as fd:
+ mbed_json = json.load(fd)
+ offset = mbed_json["target_overrides"][mcu.upper()][key]
+ return offset_arg(offset) - offset_arg(mem_start)
+
+ # specify arguments
+ parser.add_argument('-m', '--mcu', type=lambda s : s.lower().replace("-","_"), required=False,
+ help='mcu', choices=bin_map.keys())
+ parser.add_argument('-b', '--bootloader', type=argparse.FileType('rb'), required=False,
+ help='path to the bootloader binary')
+ parser.add_argument('-a', '--app', type=argparse.FileType('rb'), required=True,
+ help='path to application binary')
+ parser.add_argument('-c', '--app-offset', type=offset_arg, required=False,
+ help='offset of the application')
+ parser.add_argument('-d', '--header-offset', type=offset_arg, required=False,
+ help='offset of the firmware metadata header')
+ parser.add_argument('-o', '--output', type=argparse.FileType('wb'), required=True,
+ help='output combined file path')
+ parser.add_argument('-s', '--set-version', type=int, required=False,
+ help='set version number', default=int(time.time()))
+
+ # workaround for http://bugs.python.org/issue9694
+ parser._optionals.title = "arguments"
+
+ # get and validate arguments
+ args = parser.parse_args()
+
+ if(not (args.mcu or args.bootloader)):
+ print("Please specify bootloader location or MCU")
+ exit(-1)
+
+ fname = ''
+ if args.mcu:
+ fname = path.join(curdir, 'mbed-bootloader-' + args.mcu.replace('_', '-')+'.bin')
+ if not path.exists(fname):
+ print("Specified MCU does not have a binary in this location")
+ exit(-1)
+
+ # Use specified bootloader or default if none is provided
+ bootloader = args.bootloader or open(fname, 'rb')
+
+ # read the contents of bootloader and application binaries into buffers
+ bootloader_blob = bootloader.read()
+ bootloader.close()
+ app_blob = args.app.read()
+ args.app.close()
+
+ # Use specified offsets or default if none are provided
+ if(not (args.mcu or args.app_offset)):
+ print("Please specify app offset or MCU")
+ exit(-1)
+ app_offset = args.app_offset or parse_mbed_app_offset(args.mcu, "target.mbed_app_start")
+
+ if(not (args.mcu or args.header_offset)):
+ print("Please specify header offset or MCU")
+ exit(-1)
+ header_offset = args.header_offset or parse_mbed_app_offset(args.mcu, "update-client.application-details")
+
+ # combine application and bootloader adding metadata info
+ combine(bootloader_blob, app_blob, app_offset, header_offset, args.output, args.set_version)
+
+ # close output file
+ output_fn = path.abspath(args.output.name)
+ args.output.close()
+
+ # print the output file path
+ print('Combined binary:' + output_fn)