From 8b0e0f886de39faa365f6ee60e7257e0d2900cb6 Mon Sep 17 00:00:00 2001 From: Dinesh Harjani Date: Tue, 10 Oct 2023 12:25:46 +0100 Subject: [PATCH] Internal Structures Support for targeting specific Image Slot Before Direct XIP, active slot was always assumed to be 0, or Primary. And upload or target slot was always 1, or Secondary. That's not the case, so we need a way to track which slot is the target. This represents ongoing work. --- Example/Example/Util/McuMgrPackage.swift | 21 +++++++----- .../FirmwareUploadViewController.swift | 25 +++++--------- .../Managers/DFU/FirmwareUpgradeManager.swift | 11 +++--- Source/Managers/ImageManager.swift | 34 ++++++++++++++++++- 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/Example/Example/Util/McuMgrPackage.swift b/Example/Example/Util/McuMgrPackage.swift index f958569..72d3e20 100644 --- a/Example/Example/Util/McuMgrPackage.swift +++ b/Example/Example/Util/McuMgrPackage.swift @@ -31,18 +31,23 @@ public struct McuMgrPackage { // MARK: - API - static func imageName(at index: Int) -> String { - switch index { - case 0: return "App Core" - case 1: return "Net Core" - default: return "Image \(index)" + func imageName(at index: Int) -> String { + let coreName: String + switch images[index].image { + case 0: + coreName = "App Core" + case 1: + coreName = "Net Core" + default: + coreName = "Image \(index)" } + return "\(coreName) Slot \(images[index].slot)" } func sizeString() -> String { var sizeString = "" for (i, image) in images.enumerated() { - sizeString += "\(image.data.count) bytes (\(Self.imageName(at: i)))" + sizeString += "\(image.data.count) bytes (\(imageName(at: i)))" guard i != images.count - 1 else { continue } sizeString += "\n" } @@ -54,7 +59,7 @@ public struct McuMgrPackage { for (i, image) in images.enumerated() { let hash = try McuMgrImage(data: image.data).hash let hashString = hash.hexEncodedString(options: .upperCase) - result += "0x\(hashString.prefix(6))...\(hashString.suffix(6)) (\(Self.imageName(at: i)))" + result += "0x\(hashString.prefix(6))...\(hashString.suffix(6)) (\(imageName(at: i)))" guard i != images.count - 1 else { continue } result += "\n" } @@ -120,7 +125,7 @@ fileprivate extension McuMgrPackage { throw McuMgrPackage.Error.manifestImageNotFound } let imageData = try Data(contentsOf: imageURL) - return (manifestFile.image, imageData) + return ImageManager.Image(manifestFile, data: imageData) } try unzippedURLs.forEach { url in try fileManager.removeItem(at: url) diff --git a/Example/Example/View Controllers/Manager/FirmwareUploadViewController.swift b/Example/Example/View Controllers/Manager/FirmwareUploadViewController.swift index 38328bf..640a73e 100644 --- a/Example/Example/View Controllers/Manager/FirmwareUploadViewController.swift +++ b/Example/Example/View Controllers/Manager/FirmwareUploadViewController.swift @@ -100,17 +100,10 @@ class FirmwareUploadViewController: UIViewController, McuMgrViewController { guard let package = package else { return } uploadImageSize = nil - let images: [ImageManager.Image] - if package.images.count > 1 { - images = package.images.map { ImageManager.Image(image: $0.image, data: $0.data) } - } else { - images = Self.uploadImages.map { ImageManager.Image(image: $0, data: package.images[0].data) } - } - - let alertController = UIAlertController(title: "Select Core Slot", message: nil, preferredStyle: .actionSheet) + let alertController = UIAlertController(title: "Select", message: nil, preferredStyle: .actionSheet) let configuration = uploadConfiguration - for image in images { - alertController.addAction(UIAlertAction(title: McuMgrPackage.imageName(at: image.image), style: .default) { [weak self] + for (i, image) in package.images.enumerated() { + alertController.addAction(UIAlertAction(title: package.imageName(at: i), style: .default) { [weak self] action in self?.actionBuffers.isEnabled = false self?.actionAlignment.isEnabled = false @@ -119,10 +112,10 @@ class FirmwareUploadViewController: UIViewController, McuMgrViewController { self?.actionPause.isHidden = false self?.actionCancel.isHidden = false self?.actionSelect.isEnabled = false - self?.imageSlot = image.image + self?.packageImageIndex = i self?.status.textColor = .primary - self?.status.text = "UPLOADING \(McuMgrPackage.imageName(at: image.image))..." - _ = self?.imageManager.upload(images: [ImageManager.Image(image: image.image, data: image.data)], + self?.status.text = "UPLOADING \(package.imageName(at: i))..." + _ = self?.imageManager.upload(images: [image], using: configuration, delegate: self) }) } @@ -148,8 +141,8 @@ class FirmwareUploadViewController: UIViewController, McuMgrViewController { @IBAction func resume(_ sender: UIButton) { status.textColor = .primary - if let image = self.imageSlot { - status.text = "UPLOADING IMAGE \(McuMgrPackage.imageName(at: image))..." + if let package, let i = packageImageIndex { + status.text = "UPLOADING IMAGE \(package.imageName(at: i))..." } else { status.text = "UPLOADING..." } @@ -163,8 +156,8 @@ class FirmwareUploadViewController: UIViewController, McuMgrViewController { imageManager.cancelUpload() } - private var imageSlot: Int? private var package: McuMgrPackage? + private var packageImageIndex: Int? private var imageManager: ImageManager! var transporter: McuMgrTransport! { didSet { diff --git a/Source/Managers/DFU/FirmwareUpgradeManager.swift b/Source/Managers/DFU/FirmwareUpgradeManager.swift index d6bd5ed..5dea799 100644 --- a/Source/Managers/DFU/FirmwareUpgradeManager.swift +++ b/Source/Managers/DFU/FirmwareUpgradeManager.swift @@ -64,13 +64,14 @@ public class FirmwareUpgradeManager : FirmwareUpgradeController, ConnectionObser /// - parameter data: `Data` to upload to App Core (Image 0). /// - parameter configuration: Fine-tuning of details regarding the upgrade process. public func start(data: Data, using configuration: FirmwareUpgradeConfiguration = FirmwareUpgradeConfiguration()) throws { - try start(images: [(0, data)], using: configuration) + try start(images: [ImageManager.Image(image: 0, data: data)], + using: configuration) } /// Start the firmware upgrade. /// /// This is the full-featured API to start DFU update, including support for Multi-Image uploads. - /// - parameter images: An Array of (Image, `Data`) pairs with the Image Core/Index and its corresponding `Data` to upload. + /// - parameter images: An Array of (`ImageManager.Image`) to upload. /// - parameter configuration: Fine-tuning of details regarding the upgrade process. public func start(images: [ImageManager.Image], using configuration: FirmwareUpgradeConfiguration = FirmwareUpgradeConfiguration()) throws { objc_sync_enter(self) @@ -179,7 +180,7 @@ public class FirmwareUpgradeManager : FirmwareUpgradeController, ConnectionObser if !paused { let imagesToUpload = images .filter { !$0.uploaded } - .map { ImageManager.Image($0.image, $0.data) } + .map { ImageManager.Image($0) } guard !imagesToUpload.isEmpty else { log(msg: "Nothing to be uploaded", atLevel: .info) uploadDidFinish() @@ -996,11 +997,12 @@ public protocol FirmwareUpgradeDelegate: AnyObject { // MARK: - FirmwareUpgradeImage -fileprivate struct FirmwareUpgradeImage { +internal struct FirmwareUpgradeImage { // MARK: Properties let image: Int + let slot: Int let data: Data let hash: Data var uploaded: Bool @@ -1011,6 +1013,7 @@ fileprivate struct FirmwareUpgradeImage { init(_ image: ImageManager.Image) throws { self.image = image.image + self.slot = image.slot self.data = image.data self.hash = try McuMgrImage(data: image.data).hash self.uploaded = false diff --git a/Source/Managers/ImageManager.swift b/Source/Managers/ImageManager.swift index 08e362d..53cf21e 100644 --- a/Source/Managers/ImageManager.swift +++ b/Source/Managers/ImageManager.swift @@ -8,8 +8,40 @@ import Foundation import CoreBluetooth import SwiftCBOR +// MARK: - ImageManager + public class ImageManager: McuManager { - public typealias Image = (image: Int, data: Data) + + // MARK: Image + + public struct Image { + public let image: Int + public let slot: Int + public let data: Data + + /** + So far, only DirectXIP would target `slot` 0 (Primary). So if not specifically + stated, all of the previous code / modes target `slot` 1 (Secondary). Hence, + why that's the default. + */ + public init(image: Int, slot: Int = 1, data: Data) { + self.image = image + self.slot = slot + self.data = data + } + + public init(_ manifest: McuMgrManifest.File, data: Data) { + self.image = manifest.image + self.slot = manifest.slot + self.data = data + } + + internal init(_ image: FirmwareUpgradeImage) { + self.image = image.image + self.slot = image.slot + self.data = image.data + } + } override class var TAG: McuMgrLogCategory { .image }