Skip to content

Commit

Permalink
feat(#66): Update Proto
Browse files Browse the repository at this point in the history
Updated proto file:
- Created new 'ProtoImage' model with hash, data, slot and image fields
- Added 'hash' to single image update arguments.

Updated Swift code:
- added extension for ImageManager.Image struct to create it with Proto model
- fixed code after upgrade to v1.6

Flutter and Android pard are still broken
  • Loading branch information
NickKibish committed Mar 18, 2024
1 parent 3db45b3 commit 07f64c6
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 111 deletions.
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.2.0+1"
version: "0.3.3"
meta:
dependency: transitive
description:
Expand Down
25 changes: 25 additions & 0 deletions ios/Classes/Extensions/Image+Proto.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Image+Proto.swift
// mcumgr_flutter
//
// Created by Nick Kibysh on 18/03/2024.
//

import Foundation
import iOSMcuManagerLibrary

extension ImageManager.Image {
init(proto: ProtoImage) {
let image = Int(proto.image)
let slot = Int(proto.slot)
let hash = proto.hash
let data = proto.data

if proto.hasSlot {
self.init(image: image, slot: slot, hash: hash, data: data)
} else {
self.init(image: image, hash: hash, data: data)
}

}
}
4 changes: 2 additions & 2 deletions ios/Classes/SwiftMcumgrFlutterPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public class SwiftMcumgrFlutterPlugin: NSObject, FlutterPlugin {
throw FlutterError(code: ErrorCode.updateManagerDoesNotExist.rawValue, message: "Update manager does not exist", details: call.debugDetails)
}

let images = args.images.map { (Int($0.key), $0.value) }
let images = args.images.map { ImageManager.Image(proto: $0) }
let config = args.hasConfiguration ? FirmwareUpgradeConfiguration(proto: args.configuration) : FirmwareUpgradeConfiguration()

try manager.update(images: images, config: config)
Expand All @@ -177,7 +177,7 @@ public class SwiftMcumgrFlutterPlugin: NSObject, FlutterPlugin {

let config = args.hasConfiguration ? FirmwareUpgradeConfiguration(proto: args.configuration) : FirmwareUpgradeConfiguration()

try manager.update(data: args.firmwareData, config: config)
try manager.update(hash: args.hash, data: args.firmwareData, config: config)
}

private func kill(call: FlutterMethodCall) throws {
Expand Down
9 changes: 4 additions & 5 deletions ios/Classes/UpdateManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,14 @@ class UpdateManager {
self.logStreamHandler = logStreamHandler
}

func update(data: Data, config: FirmwareUpgradeConfiguration) throws {
func update(hash: Data, data: Data, config: FirmwareUpgradeConfiguration) throws {
dfuManager.logDelegate = updateLogger
try dfuManager.start(data: data, using: config)
// try dfuManager.start(hash: , data: data, using: config)
}

func update(images: [(Int, Data)], config: FirmwareUpgradeConfiguration) throws {
func update(images: [ImageManager.Image], config: FirmwareUpgradeConfiguration) throws {
dfuManager.logDelegate = updateLogger
let imgs = images.map { ImageManager.Image(image: $0.0, data: $0.1) }
try dfuManager.start(images: imgs, using: config)
try dfuManager.start(images: images)
}

func pause() {
Expand Down
96 changes: 66 additions & 30 deletions ios/Classes/lib/proto/flutter_mcu.pb.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ struct ProtoUpdateCallArgument {

var deviceUuid: String = String()

var hash: Data = Data()

var firmwareData: Data = Data()

var configuration: ProtoFirmwareUpgradeConfiguration {
Expand Down Expand Up @@ -58,19 +60,31 @@ struct ProtoError {
init() {}
}

/// Firmware image pair
struct Pair {
struct ProtoImage {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.

var key: Int32 = 0
var image: Int32 = 0

var slot: Int32 {
get {return _slot ?? 0}
set {_slot = newValue}
}
/// Returns true if `slot` has been explicitly set.
var hasSlot: Bool {return self._slot != nil}
/// Clears the value of `slot`. Subsequent reads from it will return its default value.
mutating func clearSlot() {self._slot = nil}

var hash: Data = Data()

var value: Data = Data()
var data: Data = Data()

var unknownFields = SwiftProtobuf.UnknownStorage()

init() {}

fileprivate var _slot: Int32? = nil
}

struct ProtoUpdateWithImageCallArguments {
Expand All @@ -80,7 +94,7 @@ struct ProtoUpdateWithImageCallArguments {

var deviceUuid: String = String()

var images: [Pair] = []
var images: [ProtoImage] = []

var configuration: ProtoFirmwareUpgradeConfiguration {
get {return _configuration ?? ProtoFirmwareUpgradeConfiguration()}
Expand Down Expand Up @@ -206,7 +220,7 @@ struct ProtoUpdateStateChanges {

extension ProtoUpdateStateChanges.FirmwareUpgradeState: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static let allCases: [ProtoUpdateStateChanges.FirmwareUpgradeState] = [
static var allCases: [ProtoUpdateStateChanges.FirmwareUpgradeState] = [
.none,
.validate,
.upload,
Expand Down Expand Up @@ -319,7 +333,7 @@ struct ProtoFirmwareUpgradeConfiguration {

extension ProtoFirmwareUpgradeConfiguration.ImageUploadAlignment: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static let allCases: [ProtoFirmwareUpgradeConfiguration.ImageUploadAlignment] = [
static var allCases: [ProtoFirmwareUpgradeConfiguration.ImageUploadAlignment] = [
.disabled,
.twoByte,
.fourByte,
Expand All @@ -330,7 +344,7 @@ extension ProtoFirmwareUpgradeConfiguration.ImageUploadAlignment: CaseIterable {

extension ProtoFirmwareUpgradeConfiguration.FirmwareUpgradeMode: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static let allCases: [ProtoFirmwareUpgradeConfiguration.FirmwareUpgradeMode] = [
static var allCases: [ProtoFirmwareUpgradeConfiguration.FirmwareUpgradeMode] = [
.testOnly,
.confirmOnly,
.testAndConfirm,
Expand Down Expand Up @@ -541,7 +555,7 @@ struct ProtoLogMessage {

extension ProtoLogMessage.LogCategory: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static let allCases: [ProtoLogMessage.LogCategory] = [
static var allCases: [ProtoLogMessage.LogCategory] = [
.transport,
.config,
.crash,
Expand All @@ -557,7 +571,7 @@ extension ProtoLogMessage.LogCategory: CaseIterable {

extension ProtoLogMessage.LogLevel: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static let allCases: [ProtoLogMessage.LogLevel] = [
static var allCases: [ProtoLogMessage.LogLevel] = [
.debug,
.verbose,
.info,
Expand Down Expand Up @@ -600,7 +614,7 @@ struct ProtoReadMessagesResponse {
#if swift(>=5.5) && canImport(_Concurrency)
extension ProtoUpdateCallArgument: @unchecked Sendable {}
extension ProtoError: @unchecked Sendable {}
extension Pair: @unchecked Sendable {}
extension ProtoImage: @unchecked Sendable {}
extension ProtoUpdateWithImageCallArguments: @unchecked Sendable {}
extension ProtoUpdateStateChangesStreamArg: @unchecked Sendable {}
extension ProtoUpdateStateChanges: @unchecked Sendable {}
Expand All @@ -624,8 +638,9 @@ extension ProtoUpdateCallArgument: SwiftProtobuf.Message, SwiftProtobuf._Message
static let protoMessageName: String = "ProtoUpdateCallArgument"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "device_uuid"),
2: .standard(proto: "firmware_data"),
3: .same(proto: "configuration"),
2: .same(proto: "hash"),
3: .standard(proto: "firmware_data"),
4: .same(proto: "configuration"),
]

mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
Expand All @@ -635,8 +650,9 @@ extension ProtoUpdateCallArgument: SwiftProtobuf.Message, SwiftProtobuf._Message
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularStringField(value: &self.deviceUuid) }()
case 2: try { try decoder.decodeSingularBytesField(value: &self.firmwareData) }()
case 3: try { try decoder.decodeSingularMessageField(value: &self._configuration) }()
case 2: try { try decoder.decodeSingularBytesField(value: &self.hash) }()
case 3: try { try decoder.decodeSingularBytesField(value: &self.firmwareData) }()
case 4: try { try decoder.decodeSingularMessageField(value: &self._configuration) }()
default: break
}
}
Expand All @@ -650,17 +666,21 @@ extension ProtoUpdateCallArgument: SwiftProtobuf.Message, SwiftProtobuf._Message
if !self.deviceUuid.isEmpty {
try visitor.visitSingularStringField(value: self.deviceUuid, fieldNumber: 1)
}
if !self.hash.isEmpty {
try visitor.visitSingularBytesField(value: self.hash, fieldNumber: 2)
}
if !self.firmwareData.isEmpty {
try visitor.visitSingularBytesField(value: self.firmwareData, fieldNumber: 2)
try visitor.visitSingularBytesField(value: self.firmwareData, fieldNumber: 3)
}
try { if let v = self._configuration {
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
try visitor.visitSingularMessageField(value: v, fieldNumber: 4)
} }()
try unknownFields.traverse(visitor: &visitor)
}

static func ==(lhs: ProtoUpdateCallArgument, rhs: ProtoUpdateCallArgument) -> Bool {
if lhs.deviceUuid != rhs.deviceUuid {return false}
if lhs.hash != rhs.hash {return false}
if lhs.firmwareData != rhs.firmwareData {return false}
if lhs._configuration != rhs._configuration {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
Expand Down Expand Up @@ -700,11 +720,13 @@ extension ProtoError: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
}
}

extension Pair: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "Pair"
extension ProtoImage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "ProtoImage"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "key"),
2: .same(proto: "value"),
1: .same(proto: "image"),
2: .same(proto: "slot"),
3: .same(proto: "hash"),
4: .same(proto: "data"),
]

mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
Expand All @@ -713,26 +735,40 @@ extension Pair: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase,
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularInt32Field(value: &self.key) }()
case 2: try { try decoder.decodeSingularBytesField(value: &self.value) }()
case 1: try { try decoder.decodeSingularInt32Field(value: &self.image) }()
case 2: try { try decoder.decodeSingularInt32Field(value: &self._slot) }()
case 3: try { try decoder.decodeSingularBytesField(value: &self.hash) }()
case 4: try { try decoder.decodeSingularBytesField(value: &self.data) }()
default: break
}
}
}

func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.key != 0 {
try visitor.visitSingularInt32Field(value: self.key, fieldNumber: 1)
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
if self.image != 0 {
try visitor.visitSingularInt32Field(value: self.image, fieldNumber: 1)
}
try { if let v = self._slot {
try visitor.visitSingularInt32Field(value: v, fieldNumber: 2)
} }()
if !self.hash.isEmpty {
try visitor.visitSingularBytesField(value: self.hash, fieldNumber: 3)
}
if !self.value.isEmpty {
try visitor.visitSingularBytesField(value: self.value, fieldNumber: 2)
if !self.data.isEmpty {
try visitor.visitSingularBytesField(value: self.data, fieldNumber: 4)
}
try unknownFields.traverse(visitor: &visitor)
}

static func ==(lhs: Pair, rhs: Pair) -> Bool {
if lhs.key != rhs.key {return false}
if lhs.value != rhs.value {return false}
static func ==(lhs: ProtoImage, rhs: ProtoImage) -> Bool {
if lhs.image != rhs.image {return false}
if lhs._slot != rhs._slot {return false}
if lhs.hash != rhs.hash {return false}
if lhs.data != rhs.data {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
Expand Down
15 changes: 15 additions & 0 deletions lib/models/image.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'dart:typed_data';

class Image {
int image;
int slot;
Uint8List hash;
Uint8List data;

Image({
required this.image,
required this.slot,
required this.hash,
required this.data,
});
}
Loading

0 comments on commit 07f64c6

Please sign in to comment.