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.

Committer:
MarceloSalazar
Date:
Tue Feb 13 10:07:23 2018 +0000
Revision:
0:e13a8a944e25
First version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
MarceloSalazar 0:e13a8a944e25 1 #!/usr/bin/env python
MarceloSalazar 0:e13a8a944e25 2
MarceloSalazar 0:e13a8a944e25 3 ## ----------------------------------------------------------------------------
MarceloSalazar 0:e13a8a944e25 4 ## Copyright 2016-2017 ARM Ltd.
MarceloSalazar 0:e13a8a944e25 5 ##
MarceloSalazar 0:e13a8a944e25 6 ## SPDX-License-Identifier: Apache-2.0
MarceloSalazar 0:e13a8a944e25 7 ##
MarceloSalazar 0:e13a8a944e25 8 ## Licensed under the Apache License, Version 2.0 (the "License");
MarceloSalazar 0:e13a8a944e25 9 ## you may not use this file except in compliance with the License.
MarceloSalazar 0:e13a8a944e25 10 ## You may obtain a copy of the License at
MarceloSalazar 0:e13a8a944e25 11 ##
MarceloSalazar 0:e13a8a944e25 12 ## http://www.apache.org/licenses/LICENSE-2.0
MarceloSalazar 0:e13a8a944e25 13 ##
MarceloSalazar 0:e13a8a944e25 14 ## Unless required by applicable law or agreed to in writing, software
MarceloSalazar 0:e13a8a944e25 15 ## distributed under the License is distributed on an "AS IS" BASIS,
MarceloSalazar 0:e13a8a944e25 16 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
MarceloSalazar 0:e13a8a944e25 17 ## See the License for the specific language governing permissions and
MarceloSalazar 0:e13a8a944e25 18 ## limitations under the License.
MarceloSalazar 0:e13a8a944e25 19 ## ----------------------------------------------------------------------------
MarceloSalazar 0:e13a8a944e25 20
MarceloSalazar 0:e13a8a944e25 21 from os import path
MarceloSalazar 0:e13a8a944e25 22 import json
MarceloSalazar 0:e13a8a944e25 23 import hashlib, zlib, struct
MarceloSalazar 0:e13a8a944e25 24 import time
MarceloSalazar 0:e13a8a944e25 25 import sys
MarceloSalazar 0:e13a8a944e25 26
MarceloSalazar 0:e13a8a944e25 27 '''
MarceloSalazar 0:e13a8a944e25 28 define FIRMWARE_HEADER_MAGIC 0x5a51b3d4UL
MarceloSalazar 0:e13a8a944e25 29 define FIRMWARE_HEADER_VERSION 2
MarceloSalazar 0:e13a8a944e25 30 define ARM_UC_SHA512_SIZE (512/8)
MarceloSalazar 0:e13a8a944e25 31 define ARM_UC_GUID_SIZE (128/8)
MarceloSalazar 0:e13a8a944e25 32 typedef struct _arm_uc_internal_header_t
MarceloSalazar 0:e13a8a944e25 33 {
MarceloSalazar 0:e13a8a944e25 34 /* Metadata-header specific magic code */
MarceloSalazar 0:e13a8a944e25 35 uint32_t headerMagic;
MarceloSalazar 0:e13a8a944e25 36
MarceloSalazar 0:e13a8a944e25 37 /* Revision number for metadata header. */
MarceloSalazar 0:e13a8a944e25 38 uint32_t headerVersion;
MarceloSalazar 0:e13a8a944e25 39
MarceloSalazar 0:e13a8a944e25 40 /* Version number accompanying the firmware. Larger numbers imply more
MarceloSalazar 0:e13a8a944e25 41 recent and preferred versions. This is used for determining the
MarceloSalazar 0:e13a8a944e25 42 selection order when multiple versions are available. For downloaded
MarceloSalazar 0:e13a8a944e25 43 firmware the manifest timestamp is used as the firmware version.
MarceloSalazar 0:e13a8a944e25 44 */
MarceloSalazar 0:e13a8a944e25 45 uint64_t firmwareVersion;
MarceloSalazar 0:e13a8a944e25 46
MarceloSalazar 0:e13a8a944e25 47 /* Total space (in bytes) occupied by the firmware BLOB. */
MarceloSalazar 0:e13a8a944e25 48 uint64_t firmwareSize;
MarceloSalazar 0:e13a8a944e25 49
MarceloSalazar 0:e13a8a944e25 50 /* Firmware hash calculated over the firmware size. Should match the hash
MarceloSalazar 0:e13a8a944e25 51 generated by standard command line tools, e.g., shasum on Linux/Mac.
MarceloSalazar 0:e13a8a944e25 52 */
MarceloSalazar 0:e13a8a944e25 53 uint8_t firmwareHash[ARM_UC_SHA512_SIZE];
MarceloSalazar 0:e13a8a944e25 54
MarceloSalazar 0:e13a8a944e25 55 /* The ID for the update campaign that resulted in the firmware update.
MarceloSalazar 0:e13a8a944e25 56 */
MarceloSalazar 0:e13a8a944e25 57 uint8_t campaign[ARM_UC_GUID_SIZE];
MarceloSalazar 0:e13a8a944e25 58
MarceloSalazar 0:e13a8a944e25 59 /* Size of the firmware signature. Must be 0 if no signature is supplied. */
MarceloSalazar 0:e13a8a944e25 60 uint32_t firmwareSignatureSize;
MarceloSalazar 0:e13a8a944e25 61
MarceloSalazar 0:e13a8a944e25 62 /* Header 32 bit CRC. Calculated over the entire header, including the CRC
MarceloSalazar 0:e13a8a944e25 63 field, but with the CRC set to zero.
MarceloSalazar 0:e13a8a944e25 64 */
MarceloSalazar 0:e13a8a944e25 65 uint32_t headerCRC;
MarceloSalazar 0:e13a8a944e25 66
MarceloSalazar 0:e13a8a944e25 67 /* Optional firmware signature. Hashing algorithm should be the same as the
MarceloSalazar 0:e13a8a944e25 68 one used for the firmware hash. The firmwareSignatureSize must be set.
MarceloSalazar 0:e13a8a944e25 69 */
MarceloSalazar 0:e13a8a944e25 70 uint8_t firmwareSignature[0];
MarceloSalazar 0:e13a8a944e25 71 } arm_uc_internal_header_t;
MarceloSalazar 0:e13a8a944e25 72 '''
MarceloSalazar 0:e13a8a944e25 73
MarceloSalazar 0:e13a8a944e25 74 # define defaults to go into the metadata header
MarceloSalazar 0:e13a8a944e25 75 SIZEOF_SHA512 = int(512/8)
MarceloSalazar 0:e13a8a944e25 76 SIZEOF_GUID = int(128/8)
MarceloSalazar 0:e13a8a944e25 77 FIRMWARE_HEADER_MAGIC = 0x5a51b3d4
MarceloSalazar 0:e13a8a944e25 78 FIRMWARE_HEADER_VERSION = 2
MarceloSalazar 0:e13a8a944e25 79 header_format = ">2I2Q{}s{}s2I".format(SIZEOF_SHA512, SIZEOF_GUID)
MarceloSalazar 0:e13a8a944e25 80
MarceloSalazar 0:e13a8a944e25 81 if sys.version_info < (3,):
MarceloSalazar 0:e13a8a944e25 82 def b(x):
MarceloSalazar 0:e13a8a944e25 83 return bytearray(x)
MarceloSalazar 0:e13a8a944e25 84 else:
MarceloSalazar 0:e13a8a944e25 85 def b(x):
MarceloSalazar 0:e13a8a944e25 86 return x
MarceloSalazar 0:e13a8a944e25 87
MarceloSalazar 0:e13a8a944e25 88 def create_header(app_blob, firmwareVersion):
MarceloSalazar 0:e13a8a944e25 89 # calculate the hash of the application
MarceloSalazar 0:e13a8a944e25 90 firmwareHash = hashlib.sha256(app_blob).digest()
MarceloSalazar 0:e13a8a944e25 91
MarceloSalazar 0:e13a8a944e25 92 # calculate the total size which is defined as the application size + metadata header
MarceloSalazar 0:e13a8a944e25 93 firmwareSize = len(app_blob)
MarceloSalazar 0:e13a8a944e25 94
MarceloSalazar 0:e13a8a944e25 95 # set campaign GUID to 0
MarceloSalazar 0:e13a8a944e25 96 campaign = b'\00'
MarceloSalazar 0:e13a8a944e25 97
MarceloSalazar 0:e13a8a944e25 98 # signature not supported, set size to 0
MarceloSalazar 0:e13a8a944e25 99 signatureSize = 0
MarceloSalazar 0:e13a8a944e25 100
MarceloSalazar 0:e13a8a944e25 101 print ('imageSize: {}'.format(firmwareSize))
MarceloSalazar 0:e13a8a944e25 102 print ('imageHash: {}'.format(''.join(['{:0>2x}'.format(c) for c in b(firmwareHash)])))
MarceloSalazar 0:e13a8a944e25 103 print ('imageversion: {}'.format(firmwareVersion))
MarceloSalazar 0:e13a8a944e25 104
MarceloSalazar 0:e13a8a944e25 105 # construct struct for CRC calculation
MarceloSalazar 0:e13a8a944e25 106 headerCRC = 0
MarceloSalazar 0:e13a8a944e25 107 FirmwareHeader = struct.pack(header_format,
MarceloSalazar 0:e13a8a944e25 108 FIRMWARE_HEADER_MAGIC,
MarceloSalazar 0:e13a8a944e25 109 FIRMWARE_HEADER_VERSION,
MarceloSalazar 0:e13a8a944e25 110 firmwareVersion,
MarceloSalazar 0:e13a8a944e25 111 firmwareSize,
MarceloSalazar 0:e13a8a944e25 112 firmwareHash,
MarceloSalazar 0:e13a8a944e25 113 campaign,
MarceloSalazar 0:e13a8a944e25 114 signatureSize,
MarceloSalazar 0:e13a8a944e25 115 headerCRC)
MarceloSalazar 0:e13a8a944e25 116
MarceloSalazar 0:e13a8a944e25 117 # calculate checksum over header, including signatureSize but without headerCRC
MarceloSalazar 0:e13a8a944e25 118 headerCRC = zlib.crc32(FirmwareHeader[:-4]) & 0xffffffff
MarceloSalazar 0:e13a8a944e25 119
MarceloSalazar 0:e13a8a944e25 120 # Pack the data into a binary blob
MarceloSalazar 0:e13a8a944e25 121 FirmwareHeader = struct.pack(header_format,
MarceloSalazar 0:e13a8a944e25 122 FIRMWARE_HEADER_MAGIC,
MarceloSalazar 0:e13a8a944e25 123 FIRMWARE_HEADER_VERSION,
MarceloSalazar 0:e13a8a944e25 124 firmwareVersion,
MarceloSalazar 0:e13a8a944e25 125 firmwareSize,
MarceloSalazar 0:e13a8a944e25 126 firmwareHash,
MarceloSalazar 0:e13a8a944e25 127 campaign,
MarceloSalazar 0:e13a8a944e25 128 signatureSize,
MarceloSalazar 0:e13a8a944e25 129 headerCRC)
MarceloSalazar 0:e13a8a944e25 130
MarceloSalazar 0:e13a8a944e25 131 return FirmwareHeader
MarceloSalazar 0:e13a8a944e25 132
MarceloSalazar 0:e13a8a944e25 133
MarceloSalazar 0:e13a8a944e25 134 def combine(bootloader_blob, app_blob, app_offset, hdr_offset, output, version):
MarceloSalazar 0:e13a8a944e25 135
MarceloSalazar 0:e13a8a944e25 136 # create header to go with the application binary
MarceloSalazar 0:e13a8a944e25 137 FirmwareHeader = create_header(app_blob, version)
MarceloSalazar 0:e13a8a944e25 138
MarceloSalazar 0:e13a8a944e25 139 # write the bootloader first
MarceloSalazar 0:e13a8a944e25 140 offset = 0
MarceloSalazar 0:e13a8a944e25 141 output.write(bootloader_blob)
MarceloSalazar 0:e13a8a944e25 142 offset += len(bootloader_blob)
MarceloSalazar 0:e13a8a944e25 143
MarceloSalazar 0:e13a8a944e25 144 # write the padding between bootloader and firmware header
MarceloSalazar 0:e13a8a944e25 145 output.write(b'\00' * (hdr_offset - offset))
MarceloSalazar 0:e13a8a944e25 146 offset += (hdr_offset - offset)
MarceloSalazar 0:e13a8a944e25 147
MarceloSalazar 0:e13a8a944e25 148 # write firmware header
MarceloSalazar 0:e13a8a944e25 149 output.write(FirmwareHeader)
MarceloSalazar 0:e13a8a944e25 150 offset += len(FirmwareHeader)
MarceloSalazar 0:e13a8a944e25 151
MarceloSalazar 0:e13a8a944e25 152 # write padding between header and application
MarceloSalazar 0:e13a8a944e25 153 output.write(b'\00' * (app_offset - offset))
MarceloSalazar 0:e13a8a944e25 154
MarceloSalazar 0:e13a8a944e25 155 # write the application
MarceloSalazar 0:e13a8a944e25 156 output.write(app_blob)
MarceloSalazar 0:e13a8a944e25 157
MarceloSalazar 0:e13a8a944e25 158
MarceloSalazar 0:e13a8a944e25 159 if __name__ == '__main__':
MarceloSalazar 0:e13a8a944e25 160 import argparse
MarceloSalazar 0:e13a8a944e25 161
MarceloSalazar 0:e13a8a944e25 162 parser = argparse.ArgumentParser(
MarceloSalazar 0:e13a8a944e25 163 description='Combine bootloader with application adding metadata header.')
MarceloSalazar 0:e13a8a944e25 164
MarceloSalazar 0:e13a8a944e25 165 def offset_arg(s):
MarceloSalazar 0:e13a8a944e25 166 if s.startswith('0x'):
MarceloSalazar 0:e13a8a944e25 167 return int(s, 16)
MarceloSalazar 0:e13a8a944e25 168 else:
MarceloSalazar 0:e13a8a944e25 169 return int(s)
MarceloSalazar 0:e13a8a944e25 170
MarceloSalazar 0:e13a8a944e25 171 bin_map = {
MarceloSalazar 0:e13a8a944e25 172 'k64f': {
MarceloSalazar 0:e13a8a944e25 173 'mem_start': '0x0'
MarceloSalazar 0:e13a8a944e25 174 },
MarceloSalazar 0:e13a8a944e25 175 'ublox_evk_odin_w2': {
MarceloSalazar 0:e13a8a944e25 176 'mem_start': '0x08000000'
MarceloSalazar 0:e13a8a944e25 177 },
MarceloSalazar 0:e13a8a944e25 178 'nucleo_f429zi': {
MarceloSalazar 0:e13a8a944e25 179 'mem_start': '0x08000000'
MarceloSalazar 0:e13a8a944e25 180 }
MarceloSalazar 0:e13a8a944e25 181 }
MarceloSalazar 0:e13a8a944e25 182
MarceloSalazar 0:e13a8a944e25 183 curdir = path.dirname(path.abspath(__file__))
MarceloSalazar 0:e13a8a944e25 184
MarceloSalazar 0:e13a8a944e25 185 def parse_mbed_app_offset(mcu, key):
MarceloSalazar 0:e13a8a944e25 186 mem_start = bin_map[mcu]["mem_start"]
MarceloSalazar 0:e13a8a944e25 187 with open(path.join(curdir, "..", "mbed_app.json")) as fd:
MarceloSalazar 0:e13a8a944e25 188 mbed_json = json.load(fd)
MarceloSalazar 0:e13a8a944e25 189 offset = mbed_json["target_overrides"][mcu.upper()][key]
MarceloSalazar 0:e13a8a944e25 190 return offset_arg(offset) - offset_arg(mem_start)
MarceloSalazar 0:e13a8a944e25 191
MarceloSalazar 0:e13a8a944e25 192 # specify arguments
MarceloSalazar 0:e13a8a944e25 193 parser.add_argument('-m', '--mcu', type=lambda s : s.lower().replace("-","_"), required=False,
MarceloSalazar 0:e13a8a944e25 194 help='mcu', choices=bin_map.keys())
MarceloSalazar 0:e13a8a944e25 195 parser.add_argument('-b', '--bootloader', type=argparse.FileType('rb'), required=False,
MarceloSalazar 0:e13a8a944e25 196 help='path to the bootloader binary')
MarceloSalazar 0:e13a8a944e25 197 parser.add_argument('-a', '--app', type=argparse.FileType('rb'), required=True,
MarceloSalazar 0:e13a8a944e25 198 help='path to application binary')
MarceloSalazar 0:e13a8a944e25 199 parser.add_argument('-c', '--app-offset', type=offset_arg, required=False,
MarceloSalazar 0:e13a8a944e25 200 help='offset of the application')
MarceloSalazar 0:e13a8a944e25 201 parser.add_argument('-d', '--header-offset', type=offset_arg, required=False,
MarceloSalazar 0:e13a8a944e25 202 help='offset of the firmware metadata header')
MarceloSalazar 0:e13a8a944e25 203 parser.add_argument('-o', '--output', type=argparse.FileType('wb'), required=True,
MarceloSalazar 0:e13a8a944e25 204 help='output combined file path')
MarceloSalazar 0:e13a8a944e25 205 parser.add_argument('-s', '--set-version', type=int, required=False,
MarceloSalazar 0:e13a8a944e25 206 help='set version number', default=int(time.time()))
MarceloSalazar 0:e13a8a944e25 207
MarceloSalazar 0:e13a8a944e25 208 # workaround for http://bugs.python.org/issue9694
MarceloSalazar 0:e13a8a944e25 209 parser._optionals.title = "arguments"
MarceloSalazar 0:e13a8a944e25 210
MarceloSalazar 0:e13a8a944e25 211 # get and validate arguments
MarceloSalazar 0:e13a8a944e25 212 args = parser.parse_args()
MarceloSalazar 0:e13a8a944e25 213
MarceloSalazar 0:e13a8a944e25 214 if(not (args.mcu or args.bootloader)):
MarceloSalazar 0:e13a8a944e25 215 print("Please specify bootloader location or MCU")
MarceloSalazar 0:e13a8a944e25 216 exit(-1)
MarceloSalazar 0:e13a8a944e25 217
MarceloSalazar 0:e13a8a944e25 218 fname = ''
MarceloSalazar 0:e13a8a944e25 219 if args.mcu:
MarceloSalazar 0:e13a8a944e25 220 fname = path.join(curdir, 'mbed-bootloader-' + args.mcu.replace('_', '-')+'.bin')
MarceloSalazar 0:e13a8a944e25 221 if not path.exists(fname):
MarceloSalazar 0:e13a8a944e25 222 print("Specified MCU does not have a binary in this location")
MarceloSalazar 0:e13a8a944e25 223 exit(-1)
MarceloSalazar 0:e13a8a944e25 224
MarceloSalazar 0:e13a8a944e25 225 # Use specified bootloader or default if none is provided
MarceloSalazar 0:e13a8a944e25 226 bootloader = args.bootloader or open(fname, 'rb')
MarceloSalazar 0:e13a8a944e25 227
MarceloSalazar 0:e13a8a944e25 228 # read the contents of bootloader and application binaries into buffers
MarceloSalazar 0:e13a8a944e25 229 bootloader_blob = bootloader.read()
MarceloSalazar 0:e13a8a944e25 230 bootloader.close()
MarceloSalazar 0:e13a8a944e25 231 app_blob = args.app.read()
MarceloSalazar 0:e13a8a944e25 232 args.app.close()
MarceloSalazar 0:e13a8a944e25 233
MarceloSalazar 0:e13a8a944e25 234 # Use specified offsets or default if none are provided
MarceloSalazar 0:e13a8a944e25 235 if(not (args.mcu or args.app_offset)):
MarceloSalazar 0:e13a8a944e25 236 print("Please specify app offset or MCU")
MarceloSalazar 0:e13a8a944e25 237 exit(-1)
MarceloSalazar 0:e13a8a944e25 238 app_offset = args.app_offset or parse_mbed_app_offset(args.mcu, "target.mbed_app_start")
MarceloSalazar 0:e13a8a944e25 239
MarceloSalazar 0:e13a8a944e25 240 if(not (args.mcu or args.header_offset)):
MarceloSalazar 0:e13a8a944e25 241 print("Please specify header offset or MCU")
MarceloSalazar 0:e13a8a944e25 242 exit(-1)
MarceloSalazar 0:e13a8a944e25 243 header_offset = args.header_offset or parse_mbed_app_offset(args.mcu, "update-client.application-details")
MarceloSalazar 0:e13a8a944e25 244
MarceloSalazar 0:e13a8a944e25 245 # combine application and bootloader adding metadata info
MarceloSalazar 0:e13a8a944e25 246 combine(bootloader_blob, app_blob, app_offset, header_offset, args.output, args.set_version)
MarceloSalazar 0:e13a8a944e25 247
MarceloSalazar 0:e13a8a944e25 248 # close output file
MarceloSalazar 0:e13a8a944e25 249 output_fn = path.abspath(args.output.name)
MarceloSalazar 0:e13a8a944e25 250 args.output.close()
MarceloSalazar 0:e13a8a944e25 251
MarceloSalazar 0:e13a8a944e25 252 # print the output file path
MarceloSalazar 0:e13a8a944e25 253 print('Combined binary:' + output_fn)