@@ -216,15 +216,6 @@ public class FirmwareUpgradeManager : FirmwareUpgradeController, ConnectionObser
216216 }
217217 }
218218
219- private func verify( ) {
220- objc_sync_setState ( . confirm)
221- if !paused {
222- // This will confirm the image on slot 0
223- log ( msg: " Sending Confirm command... " , atLevel: . verbose)
224- imageManager. confirm ( callback: confirmCallback)
225- }
226- }
227-
228219 private func eraseAppSettings( ) {
229220 objc_sync_setState ( . eraseAppSettings)
230221 log ( msg: " Erasing app settings... " , atLevel: . verbose)
@@ -240,6 +231,28 @@ public class FirmwareUpgradeManager : FirmwareUpgradeController, ConnectionObser
240231 }
241232 }
242233
234+ /**
235+ Called in .test&Confirm mode after uploaded images have been sent 'Test' command, they
236+ are tested, then Reset, and now we need to Confirm all Images.
237+ */
238+ private func testAndConfirmAfterReset( ) {
239+ if let untestedImage = images. first ( where: { $0. uploaded && !$0. tested } ) {
240+ self . fail ( error: FirmwareUpgradeError . untestedImageFound ( image: untestedImage. image, slot: untestedImage. slot) )
241+ return
242+ }
243+
244+ if let firstUnconfirmedImage = images. first ( where: {
245+ $0. uploaded && !$0. confirmed && !$0. confirmSent }
246+ ) {
247+ confirm ( firstUnconfirmedImage)
248+ mark ( firstUnconfirmedImage, as: \. confirmSent)
249+ } else {
250+ // in .testAndConfirm, we test all uploaded images before Reset.
251+ // So if we're here after Reset and there's nothing to confirm, we're done.
252+ self . success ( )
253+ }
254+ }
255+
243256 private func success( ) {
244257 objc_sync_setState ( . success)
245258
@@ -288,12 +301,12 @@ public class FirmwareUpgradeManager : FirmwareUpgradeController, ConnectionObser
288301 case . upload:
289302 imageManager. continueUpload ( )
290303 case . test:
291- guard let nextImageToTest = self . images. first ( where: { !$0. tested } ) else { return }
304+ guard let nextImageToTest = self . images. first ( where: { $0 . uploaded && !$0. tested } ) else { return }
292305 test ( nextImageToTest)
293306 case . reset:
294307 reset ( )
295308 case . confirm:
296- guard let nextImageToConfirm = self . images. first ( where: { !$0. confirmed } ) else { return }
309+ guard let nextImageToConfirm = self . images. first ( where: { $0 . uploaded && !$0. confirmed } ) else { return }
297310 confirm ( nextImageToConfirm)
298311 default :
299312 break
@@ -570,29 +583,31 @@ public class FirmwareUpgradeManager : FirmwareUpgradeController, ConnectionObser
570583 return
571584 }
572585
573- for image in self . images {
574- // Check that the image in secondary slot is pending (i.e. test succeeded).
575- guard let secondary = responseImages. first ( where: { $0. image == image. image && $0. slot == 1 } ) else {
576- self . fail ( error: FirmwareUpgradeError . unknown ( " Unable to find secondary slot for image \( image. image) in Test Response. " ) )
586+ for image in self . images where !image. tested {
587+ guard let targetSlot = responseImages. first ( where: {
588+ $0. image == image. image && Data ( $0. hash) == image. hash
589+ } ) else {
590+ self . fail ( error: FirmwareUpgradeError . unknown ( " Unable to find Uploaded Image \( image. image) Slot \( image. slot) in Test Response. " ) )
577591 return
578592 }
579593
580- guard secondary. pending else {
594+ // Check the target image is pending (i.e. test succeeded).
595+ guard targetSlot. pending else {
581596 // For every image we upload, we need to send it the TEST Command.
582597 guard image. tested else {
583598 self . test ( image)
584599 return
585600 }
586601
587- // If we've sent it the TEST Command, the secondary slot must be in pending state to pass test.
588- self . fail ( error: FirmwareUpgradeError . unknown ( " Image \( image. image) is not in a pending state. " ) )
602+ // If we've sent it the TEST Command, the slot must be in pending state to pass test.
603+ self . fail ( error: FirmwareUpgradeError . unknown ( " Image \( image. image) Slot \( image . slot ) is not in a pending state." ) )
589604 return
590605 }
591606 self . mark ( image, as: \. tested)
592607 }
593608
594609 // Test image succeeded. Begin device reset.
595- self . log ( msg: " All test commands sent " , atLevel: . application)
610+ self . log ( msg: " All Test commands sent " , atLevel: . application)
596611 self . reset ( )
597612 }
598613
@@ -628,14 +643,9 @@ public class FirmwareUpgradeManager : FirmwareUpgradeController, ConnectionObser
628643 return
629644 }
630645
631- for image in self . images {
646+ for image in self . images where !image . confirmed {
632647 switch self . configuration. upgradeMode {
633648 case . confirmOnly:
634- // Check if the image was already confirmed.
635- if image. confirmed {
636- continue
637- }
638-
639649 guard let targetSlot = responseImages. first ( where: {
640650 $0. image == image. image && Data ( $0. hash) == image. hash
641651 } ) else {
@@ -668,17 +678,20 @@ public class FirmwareUpgradeManager : FirmwareUpgradeController, ConnectionObser
668678
669679 self . mark ( image, as: \. confirmed)
670680 case . testAndConfirm:
671- if let primary = responseImages. first ( where: { $0. image == image. image && $0. slot == 0 } ) {
672- // If Primary is available, check that the upgrade image has successfully booted.
673- if Data ( primary. hash) != image. hash {
674- self . fail ( error: FirmwareUpgradeError . unknown ( " Device failed to boot into Image \( primary. image) . " ) )
675- return
681+ if let targetSlot = responseImages. first ( where: {
682+ $0. image == image. image && Data ( $0. hash) == image. hash
683+ } ) {
684+ if targetSlot. active || targetSlot. permanent {
685+ // Image booted. All okay.
686+ self . mark ( image, as: \. confirmed)
687+ continue
676688 }
677- // Check that the new image is in confirmed state.
678- if !primary . confirmed {
679- self . fail ( error: FirmwareUpgradeError . unknown ( " Image \( primary . image) is not in a confirmed state. " ) )
689+
690+ if image . confirmSent && !targetSlot . confirmed {
691+ self . fail ( error: FirmwareUpgradeError . unknown ( " Image \( targetSlot . image) Slot \( targetSlot . slot ) was sent Confirm command but is not in a Confirmed state." ) )
680692 return
681693 }
694+
682695 self . mark ( image, as: \. confirmed)
683696 }
684697 case . testOnly:
@@ -687,11 +700,13 @@ public class FirmwareUpgradeManager : FirmwareUpgradeController, ConnectionObser
687700 }
688701 }
689702
703+ self . log ( msg: " Work Complete! " , atLevel: . verbose)
690704 self . log ( msg: " Upgrade complete " , atLevel: . application)
691705 switch self . configuration. upgradeMode {
692706 case . confirmOnly:
693707 self . reset ( )
694708 case . testAndConfirm:
709+ // No need to reset again.
695710 self . success ( )
696711 case . testOnly:
697712 // Impossible!
@@ -818,7 +833,7 @@ public class FirmwareUpgradeManager : FirmwareUpgradeController, ConnectionObser
818833 case . reset:
819834 switch self . configuration. upgradeMode {
820835 case . testAndConfirm:
821- self . verify ( )
836+ self . testAndConfirmAfterReset ( )
822837 default :
823838 self . log ( msg: " Upgrade complete " , atLevel: . application)
824839 self . success ( )
@@ -945,15 +960,15 @@ extension FirmwareUpgradeManager: ImageUploadDelegate {
945960 // We might send 'Confirm', but the firmware might not change the flag to reflect it.
946961 // If we don't track this internally, we could enter into an infinite loop always trying
947962 // to Confirm an image.
948- self . mark ( firstUnconfirmedImage, as: \. confirmSent)
963+ mark ( firstUnconfirmedImage, as: \. confirmSent)
949964 return
950965 } else {
951966 // If there's no image left to Confirm, then we Reset.
952967 reset ( )
953968 return
954969 }
955970 case . testOnly, . testAndConfirm:
956- if let firstUntestedImage = images. first ( where: { !$0. tested } ) {
971+ if let firstUntestedImage = images. first ( where: { $0 . uploaded && !$0. tested } ) {
957972 test ( firstUntestedImage)
958973 return
959974 }
@@ -970,6 +985,7 @@ public enum FirmwareUpgradeError: Error {
970985 case unknown( String )
971986 case invalidResponse( McuMgrResponse )
972987 case connectionFailedAfterReset
988+ case untestedImageFound( image: Int , slot: Int )
973989}
974990
975991extension FirmwareUpgradeError : LocalizedError {
@@ -982,6 +998,8 @@ extension FirmwareUpgradeError: LocalizedError {
982998 return " Invalid response: \( response) . "
983999 case . connectionFailedAfterReset:
9841000 return " Connection failed after reset. "
1001+ case . untestedImageFound( let image, let slot) :
1002+ return " Image \( image) Slot \( slot) found to be not Tested after Reset. After Reset, all Uploaded Images are expected to have been Tested (Verified). "
9851003 }
9861004 }
9871005
0 commit comments