Skip to content

Commit

Permalink
Merge pull request #3 from PunchThrough/more-fw-state
Browse files Browse the repository at this point in the history
oad: fix logic, improve method signatures for app clients
  • Loading branch information
mplewis committed Mar 11, 2016
2 parents 3475ff9 + 0aa67ef commit ba3aa6b
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 38 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "BeanContainer.h"
#import "StatelessUtils.h"
#import "PTDBean+Protected.h"
#import "PTDUtils.h"

@interface BeanContainer () <PTDBeanManagerDelegate, PTDBeanExtendedDelegate>

Expand Down Expand Up @@ -33,6 +34,8 @@ @interface BeanContainer () <PTDBeanManagerDelegate, PTDBeanExtendedDelegate>

@end

NSString * const firmwareImagesFolder = @"Firmware Images";

@implementation BeanContainer

#pragma mark - Constructors
Expand Down Expand Up @@ -155,10 +158,11 @@ - (BOOL)uploadSketch:(NSString *)hexName

- (BOOL)updateFirmware
{
NSArray *imagePaths = [StatelessUtils firmwareImagesFromResource:@"Firmware Images"];
NSArray *imagePaths = [StatelessUtils firmwareImagesFromResource:firmwareImagesFolder];
NSInteger targetVersion = [StatelessUtils firmwareVersionFromResource:firmwareImagesFolder];
self.beanCompletedFirmwareUpload = [self.testCase expectationWithDescription:@"Firmware updated for Bean"];
[self.bean updateFirmwareWithImages:imagePaths];

[self.bean updateFirmwareWithImages:imagePaths andTargetVersion:targetVersion];
[self.testCase waitForExpectationsWithTimeout:480 handler:nil];
self.beanCompletedFirmwareUpload = nil;

Expand All @@ -167,11 +171,12 @@ - (BOOL)updateFirmware

- (BOOL)updateFirmwareOnce
{
NSArray *imagePaths = [StatelessUtils firmwareImagesFromResource:@"Firmware Images"];
NSArray *imagePaths = [StatelessUtils firmwareImagesFromResource:firmwareImagesFolder];
NSInteger targetVersion = [StatelessUtils firmwareVersionFromResource:firmwareImagesFolder];
NSString *desc = @"Single firmware image uploaded to Bean";
self.beanCompletedFirmwareUploadOfSingleImage = [self.testCase expectationWithDescription:desc];

[self.bean updateFirmwareWithImages:imagePaths];
[self.bean updateFirmwareWithImages:imagePaths andTargetVersion:targetVersion];
[self.testCase waitForExpectationsWithTimeout:120 handler:nil];
self.beanCompletedFirmwareUploadOfSingleImage = nil;

Expand Down Expand Up @@ -313,8 +318,9 @@ - (void)bean:(PTDBean *)bean completedFirmwareUploadWithError:(NSError *)error
- (void)beanFoundWithIncompleteFirmware:(PTDBean *)bean
{
NSLog(@"Refetching firmware images and restarting update process");
NSArray *imagePaths = [StatelessUtils firmwareImagesFromResource:@"Firmware Images"];
[self.bean updateFirmwareWithImages:imagePaths];
NSArray *imagePaths = [StatelessUtils firmwareImagesFromResource:firmwareImagesFolder];
NSInteger targetVersion = [StatelessUtils firmwareVersionFromResource:firmwareImagesFolder];
[self.bean updateFirmwareWithImages:imagePaths andTargetVersion:targetVersion];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,21 @@

/**
* Get the images files from the firmwareImages folder in the test resources folder.
* @param The imageFolder specifies where the .bin files are stored
* @param imageFolder Specifies where the .bin files are stored
* @return An NSArray object with the contents of the folder, or nil if the folder couldn't be opened
*/
+ (NSArray *)firmwareImagesFromResource:(NSString *)imageFolder;

/**
* Get the image files from the firmwareImages folder in the test resources folder and return the front datestamp of
* prefixed to the first file.
*
* @param imageFolder Specifies where the .bin files are stored
*
* @return An NSInteger of the datestamp prefix of the first file listed
*/
+ (NSInteger)firmwareVersionFromResource:(NSString *)imageFolder;

/**
* Returns a stubbed Bean with the given firmware version string.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "StatelessUtils.h"
#import <OCMock/OCMock.h>
#import "PTDIntelHex.h"
#import "PTDUtils.h"

@implementation StatelessUtils

Expand Down Expand Up @@ -45,6 +46,22 @@ + (NSArray *)firmwareImagesFromResource:(NSString *)imageFolder
return firmwarePaths;
}

+ (NSInteger)firmwareVersionFromResource:(NSString *)imageFolder
{
NSString *resourcePath = [[NSBundle bundleForClass:[self class]] resourcePath];
NSString *path = [resourcePath stringByAppendingPathComponent:imageFolder];
NSLog(@"Path = %@", path);

NSError *error;
NSArray *imageNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&error];
if (error) {
return 0;
}

NSNumber *firstImageDatestamp = [PTDUtils parseLeadingInteger:imageNames[0]];
return [firstImageDatestamp integerValue];
}

+ (PTDBean *)fakeBeanWithFirmware:(NSString *)version;
{
PTDBean *bean = OCMClassMock([PTDBean class]);
Expand Down
2 changes: 1 addition & 1 deletion source/Helper/PTDFirmwareHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ typedef NS_ENUM(NSUInteger, FirmwareStatus) {
* For example, "201501110000_A_BEAN_PLUS.bin" should first be parsed to the integer 201501110000
* @param error Pass in an NSError object. If an error occurs, this will be set to the error.
* If successful, this will be nil
* @return YES if Bean's firmware is out of date, NO if Bean has equivalent or newer firmware, NO if an error occurred
* @return FirmwareStatus that represents the status of Bean's firmware in relation to the available firmware
*/
+ (FirmwareStatus)firmwareUpdateRequiredForBean:(PTDBean *)bean availableFirmware:(NSInteger)version withError:(NSError * __autoreleasing *)error;

Expand Down
1 change: 0 additions & 1 deletion source/PTDBean+Protected.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
-(id)initWithPeripheral:(CBPeripheral*)peripheral beanManager:(id<PTDBeanManager>)manager;

-(void)setBeanManager:(id<PTDBeanManager>)manager;
-(BOOL)updateFirmwareWithImagePaths:(NSArray*)firmwareImages;
-(void)setProfilesRequiredToConnect:(NSArray*)classes;

@end
Expand Down
77 changes: 51 additions & 26 deletions source/PTDBean.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#import "PTDBeanRadioConfig.h"
#import "CBPeripheral+RSSI_Universal.h"
#import "PTDBeanRemoteFirmwareVersionManager.h"
#import "PTDFirmwareHelper.h"
#import "PTDUtils.h"

#define ARDUINO_OAD_MAX_CHUNK_SIZE 64

Expand All @@ -25,6 +27,7 @@ @interface PTDBean () <CBPeripheralDelegate, AppMessagingLayerDelegate, OAD_Dele
#pragma mark - Header readonly overrides

@property (nonatomic, readwrite) Boolean updateInProgress;
@property (nonatomic, assign) NSInteger targetFirmwareVersion;

@end

Expand Down Expand Up @@ -321,11 +324,6 @@ -(void)getConfig {
}
[appMessageLayer sendMessageWithID:MSG_ID_BT_GET_CONFIG andPayload:nil];
}

-(BOOL)updateFirmwareWithImagePaths:(NSArray*)firmwareImages{
if(!oad_profile)return FALSE;
return [oad_profile updateFirmwareWithImagePaths:firmwareImages];
}

- (void)checkFirmwareVersionAvailableWithHandler:(void (^)(BOOL firmwareAvailable, NSError *error))handler{

Expand All @@ -350,8 +348,10 @@ - (FirmwareStatus)firmwareUpdateAvailable:(NSInteger)bakedFirmwareVersion error:
return [PTDFirmwareHelper firmwareUpdateRequiredForBean:self availableFirmware:bakedFirmwareVersion withError:error];
}

- (void)updateFirmwareWithImages:(NSArray *)images{

- (void)updateFirmwareWithImages:(NSArray *)images andTargetVersion:(NSInteger)version
{
self.targetFirmwareVersion = version;

if(!oad_profile && self.delegate && [self.delegate respondsToSelector:@selector(bean:completedFirmwareUploadWithError:)]) {
NSError* error = [BEAN_Helper basicError:@"OAD profile not present!" domain:NSStringFromClass([self class]) code:0];
[(id<PTDBeanExtendedDelegate>)self.delegate bean:self completedFirmwareUploadWithError:error];
Expand Down Expand Up @@ -568,40 +568,65 @@ -(BOOL)validScratchNumber:(NSInteger)scratchNumber {
*/
- (void)manageFirmwareUpdateStatus
{
BOOL runningOadImage = [PTDFirmwareHelper oadImageRunningOnBean:self];

if (self.updateInProgress && !runningOadImage) {
if ([PTDFirmwareHelper oadImageRunningOnBean:self]) {
NSLog(@"Bean is running OAD image. Update required.");
if (self.delegate && [self.delegate respondsToSelector:@selector(beanFoundWithIncompleteFirmware:)])
[self.delegate beanFoundWithIncompleteFirmware:self];
return;
}

if (!self.updateInProgress) {
NSLog(@"Bean isn't running OAD image and no update is in progress. No update required.");
return;
}

if (!self.targetFirmwareVersion) {
NSLog(@"Error: Bean requires update but target firmware version is unknown.");
return;
}

// Update in progress. See what the status of Bean is.
NSError *error;
FirmwareStatus updateStatus = [PTDFirmwareHelper firmwareUpdateRequiredForBean:self
availableFirmware:self.targetFirmwareVersion
withError:&error];
if (error) {
NSLog(@"Error fetching Bean update status: %@", error);
return;
}

if (updateStatus == FirmwareStatusBeanNeedsUpdate) {
// Bean is not fully up-to-date, and an update is in progress right now.
// This means Bean just reconnected and needs the next image in the update process.
if (self.delegate && [self.delegate respondsToSelector:@selector(beanFoundWithIncompleteFirmware:)])
[self.delegate beanFoundWithIncompleteFirmware:self];

} else if (updateStatus == FirmwareStatusUpToDate) {
// Update was in progress last time Bean disconnected, and the image is no longer an OAD update image.
// That means the update was successful and Bean is running a fully functional image.
[self completeFirmwareUpdate];
[self completeFirmwareUpdateWithError:nil];

} else if (runningOadImage) {
// Any Bean that's still running an OAD update image needs to be updated until it's fully functional.
[self continueFirmwareUpdate];
} else {
// Bean has more current firmware than Loader, or Bean firmware update status couldn't be determined
NSLog(@"Unexpected Bean update status: FirmwareStatus = %lu", updateStatus);
NSError *myError = nil;
[self completeFirmwareUpdateWithError:myError];
}
}

/**
* Called when a Bean that was in the middle of a firmware update process has just reconnected, and it's now running
* up to date firmware.
*
* @param error nil if everything went OK, an NSError if something went wrong
*/
- (void)completeFirmwareUpdate
- (void)completeFirmwareUpdateWithError:(NSError *)error
{
firmwareUpdateStartTime = NULL;
_updateInProgress = FALSE;
_updateStepNumber = 0;
if (self.delegate && [self.delegate respondsToSelector:@selector(bean:completedFirmwareUploadWithError:)]) {
[(id<PTDBeanExtendedDelegate>)self.delegate bean:self completedFirmwareUploadWithError:NULL];
}
}

/**
* Called when a Bean has just connected and is still in the middle of a firmware update process.
*/
- (void)continueFirmwareUpdate
{
if (self.delegate && [self.delegate respondsToSelector:@selector(beanFoundWithIncompleteFirmware:)]){
[self.delegate beanFoundWithIncompleteFirmware:self];
[(id<PTDBeanExtendedDelegate>)self.delegate bean:self completedFirmwareUploadWithError:error];
}
}

Expand Down
8 changes: 6 additions & 2 deletions source/Public/PTDBean.h
Original file line number Diff line number Diff line change
Expand Up @@ -366,9 +366,13 @@ typedef NS_ENUM(NSUInteger, PTDAdvertisingMode) {
- (FirmwareStatus)firmwareUpdateAvailable:(NSInteger)bakedFirmwareVersion error:(NSError * __autoreleasing *)error;

/**
* Update the firmware with images
* Update this Bean with a set of asymmetric firmware images.
*
* @param images An array of paths to firmware images for this Bean's hardware variant
* @param version An NSInteger of the parsed datestamp for the firmware images. When Bean reflects this date in its
* Hardware Version characteristic, the firmware version process is complete.
*/
- (void)updateFirmwareWithImages:(NSArray *)images;
- (void)updateFirmwareWithImages:(NSArray *)images andTargetVersion:(NSInteger)version;

/**
* Cancel firmware update
Expand Down

0 comments on commit ba3aa6b

Please sign in to comment.