Skip to content

Commit

Permalink
Merge branch 'release/2.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
mplewis committed May 27, 2016
2 parents 86d8125 + b9ffba4 commit a31463a
Show file tree
Hide file tree
Showing 26 changed files with 232 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
- (BOOL)uploadSketch:(NSString *)hexName;

/**
* Update the firmware on Bean with the images inside the "Firmware Images" folder.
* Update the firmware on Bean with the images inside the "Firmware Images/<hardwareName>" folder.
* @return YES if firmware update was successful
*/
- (BOOL)updateFirmware;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,13 @@ - (BOOL)uploadSketch:(NSString *)hexName

- (BOOL)updateFirmware
{
NSArray *imagePaths = [StatelessUtils firmwareImagesFromResource:firmwareImagesFolder];
NSInteger targetVersion = [StatelessUtils firmwareVersionFromResource:firmwareImagesFolder];
NSString *hardwareName = [self deviceHardwareVersion];
NSArray *imagePaths = [StatelessUtils firmwareImagesFromResource:firmwareImagesFolder withHardwareName:hardwareName];
NSNumber *targetVersion = [StatelessUtils firmwareVersionFromResource:firmwareImagesFolder withHardwareName:hardwareName];
if (!targetVersion) return NO;
self.beanCompletedFirmwareUpload = [self.testCase expectationWithDescription:@"Firmware updated for Bean"];

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

Expand All @@ -171,12 +173,14 @@ - (BOOL)updateFirmware

- (BOOL)updateFirmwareOnce
{
NSArray *imagePaths = [StatelessUtils firmwareImagesFromResource:firmwareImagesFolder];
NSInteger targetVersion = [StatelessUtils firmwareVersionFromResource:firmwareImagesFolder];
NSString *hardwareName = [self deviceInfo][@"hardwareVersion"];
NSArray *imagePaths = [StatelessUtils firmwareImagesFromResource:firmwareImagesFolder withHardwareName:hardwareName];
NSNumber *targetVersion = [StatelessUtils firmwareVersionFromResource:firmwareImagesFolder withHardwareName:hardwareName];
if (!targetVersion) return NO;
NSString *desc = @"Single firmware image uploaded to Bean";
self.beanCompletedFirmwareUploadOfSingleImage = [self.testCase expectationWithDescription:desc];

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

Expand Down Expand Up @@ -220,6 +224,20 @@ - (NSDictionary *)deviceInfo
return @{@"hardwareVersion": hardwareVersion, @"firmwareVersion": firmwareVersion};
}

- (NSString *)deviceHardwareVersion
{
__block NSString *hardwareVersion;
XCTestExpectation *hwExpect = [self.testCase expectationWithDescription:@"Bean hardware version retrieved"];

[self.bean checkHardwareVersionAvailableWithHandler:^(BOOL hardwareAvailable, NSError *error) {
hardwareVersion = self.bean.hardwareVersion;
[hwExpect fulfill];
}];
[self.testCase waitForExpectationsWithTimeout:10 handler:nil];

return hardwareVersion;
}

#pragma mark - Helpers that depend on BeanContainer state

- (void)printProgressTimeLeft:(NSNumber *)seconds withPercentage:(NSNumber *)percentageComplete
Expand All @@ -231,6 +249,19 @@ - (void)printProgressTimeLeft:(NSNumber *)seconds withPercentage:(NSNumber *)per
}
}

- (void)printProgressIndexSent:(NSUInteger)index
totalImages:(NSUInteger)total
imageProgress:(NSUInteger)bytesSent
imageSize:(NSUInteger)bytesTotal
{
NSInteger percentage = (float) bytesSent / bytesTotal * 100;
if (percentage != self.lastPercentagePrinted) {
self.lastPercentagePrinted = percentage;
NSLog(@"Upload progress: %ld%% (image %ld/%ld, %ld/%ld bytes)",
percentage, index + 1, total, bytesSent, bytesTotal);
}
}

#pragma mark - PTDBeanManagerDelegate

- (void)beanManagerDidUpdateState:(PTDBeanManager *)beanManager
Expand Down Expand Up @@ -283,9 +314,13 @@ - (void)bean:(PTDBean *)bean ArduinoProgrammingTimeLeft:(NSNumber *)seconds with
[self printProgressTimeLeft:seconds withPercentage:percentageComplete];
}

- (void)bean:(PTDBean *)bean firmwareUploadTimeLeft:(NSNumber *)seconds withPercentage:(NSNumber *)percentageComplete
- (void)bean:(PTDBean *)bean
currentImage:(NSUInteger)index
totalImages:(NSUInteger)total
imageProgress:(NSUInteger)bytesSent
imageSize:(NSUInteger)bytesTotal
{
[self printProgressTimeLeft:seconds withPercentage:percentageComplete];
[self printProgressIndexSent:index totalImages:total imageProgress:bytesSent imageSize:bytesTotal];
}

- (void)bean:(PTDBean *)bean didProgramArduinoWithError:(NSError *)error
Expand Down Expand Up @@ -318,9 +353,14 @@ - (void)bean:(PTDBean *)bean completedFirmwareUploadWithError:(NSError *)error
- (void)beanFoundWithIncompleteFirmware:(PTDBean *)bean
{
NSLog(@"Refetching firmware images and restarting update process");
NSArray *imagePaths = [StatelessUtils firmwareImagesFromResource:firmwareImagesFolder];
NSInteger targetVersion = [StatelessUtils firmwareVersionFromResource:firmwareImagesFolder];
[self.bean updateFirmwareWithImages:imagePaths andTargetVersion:targetVersion];
NSString *hardwareName = self.bean.hardwareVersion; // not kosher, but we're in the middle of an xctest await during connection
NSArray *imagePaths = [StatelessUtils firmwareImagesFromResource:firmwareImagesFolder withHardwareName:hardwareName];
NSNumber *targetVersion = [StatelessUtils firmwareVersionFromResource:firmwareImagesFolder withHardwareName:hardwareName];
if (!targetVersion) {
NSLog(@"version.txt not found; can't continue firmware update");
return;
}
[self.bean updateFirmwareWithImages:imagePaths andTargetVersion:[targetVersion integerValue]];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,35 @@

/**
* Parse an Intel HEX file (with the extension .hex) into raw bytes.
*
* @param intelHexFileName The name of the Intel HEX file. For example, to read from mysketch.hex,
* <code>intelHexFileName</code> should be "mysketch"
* @param klass The class to be used to select the bundle. Usually this should be <code>[self class]</code>
*
* @return An NSData object with the contents of the file, or nil if the file couldn't be opened
*/
+ (NSData *)bytesFromIntelHexResource:(NSString *)intelHexFilename usingBundleForClass:(id)klass;

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

/**
* 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
* @param hardwareName The name of the hardware binary folder, e.g. "Bean"
*
* @return An NSInteger of the datestamp prefix of the first file listed
* @return An NSNumber of the datestamp prefix of the first file listed, or nil if none could be parsed
*/
+ (NSInteger)firmwareVersionFromResource:(NSString *)imageFolder;
+ (NSNumber *)firmwareVersionFromResource:(NSString *)imageFolder withHardwareName:(NSString *)hardwareName;

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

@implementation StatelessUtils

Expand All @@ -25,10 +26,11 @@ + (NSData *)bytesFromIntelHexResource:(NSString *)intelHexFilename usingBundleFo
return [intelHex bytes];
}

+ (NSArray *)firmwareImagesFromResource:(NSString *)imageFolder
+ (NSArray *)firmwareImagesFromResource:(NSString *)imageFolder withHardwareName:(NSString *)hardwareName
{
NSString *resourcePath = [[NSBundle bundleForClass:[self class]] resourcePath];
NSString *path = [resourcePath stringByAppendingPathComponent:imageFolder];
path = [path stringByAppendingPathComponent:[PTDHardwareLookup hardwareNameForVersion:hardwareName]];
NSLog(@"Path = %@", path);

NSError *error;
Expand All @@ -40,26 +42,27 @@ + (NSArray *)firmwareImagesFromResource:(NSString *)imageFolder
// build full resource path to each firmware image
NSMutableArray *firmwarePaths = [NSMutableArray new];
for (NSString *imageName in imageNames){
if (![imageName hasSuffix:@".bin"]) continue;
[firmwarePaths addObject:[path stringByAppendingPathComponent:imageName]];
}

return firmwarePaths;
}

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

NSString *folderPath = [resourcePath stringByAppendingPathComponent:imageFolder];
folderPath = [folderPath stringByAppendingPathComponent:[PTDHardwareLookup hardwareNameForVersion:hardwareName]];
NSString *versionFile = [folderPath stringByAppendingPathComponent:@"version.txt"];
NSError *error;
NSArray *imageNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&error];
NSString *versionFileData = [NSString stringWithContentsOfFile:versionFile encoding:NSUTF8StringEncoding error:&error];
if (error) {
return 0;
NSLog(@"Could not open version file (%@): %@", versionFile, error);
return nil;
}

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

+ (PTDBean *)fakeBeanWithFirmware:(NSString *)version;
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
201605240000
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
201605240000
31 changes: 25 additions & 6 deletions Bean OSX Static Library/Bean OSX LibraryTests/TestBeanFeatures.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@ @interface TestBeanFeatures : XCTestCase
/**
* This filter selects Beans named "Bean", the name Bean has out of the box
*/
static BOOL (^outOfBoxFilter)(PTDBean *bean) = ^BOOL(PTDBean *bean) {
static BOOL (^beanFilter)(PTDBean *bean) = ^BOOL(PTDBean *bean) {
return [bean.name isEqualToString:@"Bean"];
};

/**
* This filter selects Bean+s named "Bean+", the name Bean+ has out of the box
*/
static BOOL (^beanPlusFilter)(PTDBean *bean) = ^BOOL(PTDBean *bean) {
return [bean.name isEqualToString:@"Bean+"];
};

@implementation TestBeanFeatures

#pragma mark - Test configuration
Expand All @@ -28,7 +35,7 @@ - (void)setUp
*/
- (void)testBlinkBean
{
BeanContainer *beanContainer = [self containerWithBeanFilter:outOfBoxFilter andOptions:nil];
BeanContainer *beanContainer = [self containerWithBeanFilter:beanFilter andOptions:nil];
NSColor *magenta = [NSColor colorWithRed:1 green:0 blue:1 alpha:1];

XCTAssertTrue([beanContainer connect]);
Expand All @@ -41,7 +48,7 @@ - (void)testBlinkBean
*/
- (void)testUploadSketchToBean
{
BeanContainer *beanContainer = [self containerWithBeanFilter:outOfBoxFilter andOptions:nil];
BeanContainer *beanContainer = [self containerWithBeanFilter:beanFilter andOptions:nil];

XCTAssertTrue([beanContainer connect]);
XCTAssertTrue([beanContainer uploadSketch:@"blink"]);
Expand All @@ -55,8 +62,20 @@ - (void)testBeanFirmwareUpdate
{
// Connection callback doesn't happen until Bean firmware is fully updated. Increase the connection timeout.
NSDictionary *options = @{@"connectTimeout": @600};
BeanContainer *beanContainer = [self containerWithBeanFilter:outOfBoxFilter andOptions:options];

BeanContainer *beanContainer = [self containerWithBeanFilter:beanFilter andOptions:options];
XCTAssertTrue([beanContainer connect]);
XCTAssertTrue([beanContainer updateFirmware]);
XCTAssertTrue([beanContainer disconnect]);
}

/**
* Test that Bean+ firmware can be updated.
*/
- (void)testBeanPlusFirmwareUpdate
{
// Connection callback doesn't happen until Bean firmware is fully updated. Increase the connection timeout.
NSDictionary *options = @{@"connectTimeout": @600};
BeanContainer *beanContainer = [self containerWithBeanFilter:beanPlusFilter andOptions:options];
XCTAssertTrue([beanContainer connect]);
XCTAssertTrue([beanContainer updateFirmware]);
XCTAssertTrue([beanContainer disconnect]);
Expand All @@ -67,7 +86,7 @@ - (void)testBeanFirmwareUpdate
*/
- (void)testBeanHasDeviceInfo
{
BeanContainer *beanContainer = [self containerWithBeanFilter:outOfBoxFilter andOptions:nil];
BeanContainer *beanContainer = [self containerWithBeanFilter:beanFilter andOptions:nil];

XCTAssertTrue([beanContainer connect]);
XCTAssertNotNil([beanContainer deviceInfo]);
Expand Down
2 changes: 1 addition & 1 deletion Bean-iOS-OSX-SDK.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Pod::Spec.new do |s|

s.name = "Bean-iOS-OSX-SDK"
s.version = "2.0.1"
s.version = "2.1.0"
s.summary = "Punch Through Design's SDK for speeding up development with the LightBlue Bean development platform"
s.homepage = "https://github.com/PunchThrough/Bean-iOS-OSX-SDK"
s.license = { :type => "MIT", :file => "LICENSE.txt" }
Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,35 @@
__/ | SDK for iOS and OS X
|___/

---------------------------------
2.1.0
Released on 2016-05-26
---------------------------------
App Message Definitions: master/369b766 (2014-09-16)
Bean Test Firmware: 201605240000 (2016-05-24)
Bean+ Test Firmware: 201605240000 (2016-05-24)
---------------------------------

FEATURES:
* Added PTDBean `bean:bluetoothError:` delegate method to report CoreBluetooth
errors
* Tests can now ensure firmware updates work on both Bean and Bean+

IMPROVEMENTS:
* Better documentation for PTDBleDevice delegates
* rssiDidUpdateWithError:
* servicesHaveBeenModified
* notificationStateUpdatedWithError:
* Test helpers can now find and send firmware for both Bean and Bean+

BUG FIXES:
* Sending a firmware image now completes when the last block is sent, instead of
waiting for the completion timer to fire. Fixes a race condition in which Bean
would reconnect and begin sending another image before the completion handler
was called.
* Fixed a bug where an inverted boolean caused firmware status to be passed back
at the wrong time

---------------------------------
2.0.1
Released on 2016-04-11
Expand Down
13 changes: 11 additions & 2 deletions source/PTDBean.m
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,15 @@ -(void)rssiDidUpdateWithError:(NSError*)error{
}
}

-(void)notificationStateUpdatedWithError:(NSError *)error
{
if (error.domain == CBATTErrorDomain && error.code == 1 && self.delegate
&& [self.delegate respondsToSelector:@selector(bean:bluetoothError:)]){
// alert user that bluetooth error occurred where GATT table handles invalid
[self.delegate bean:self bluetoothError:BeanBluetoothError_InvalidHandle];
}
}

-(void)servicesHaveBeenModified{
// TODO: Re-Instantiate the Bean object
}
Expand Down Expand Up @@ -892,7 +901,7 @@ - (void)device:(OadProfile *)device completedFirmwareUploadOfSingleImage:(NSStri
[self device:device completedFirmwareUploadWithError:error];
return;
}

if (self.delegate && [self.delegate respondsToSelector:@selector(bean:completedFirmwareUploadOfSingleImage:imageIndex:totalImages:withError:)])
[(id<PTDBeanExtendedDelegate>)self.delegate bean:self completedFirmwareUploadOfSingleImage:path imageIndex:index totalImages:images withError:error];
}
Expand Down Expand Up @@ -929,7 +938,7 @@ - (void)firmwareVersionDidUpdate
[self manageFirmwareUpdateStatus];

// Don't send firmware version back to handler when firmware update is still in progress
if (!self.updateInProgress) return;
if (self.updateInProgress) return;

if (firmwareVersionAvailableHandler) {
[self checkFirmwareVersionAvailableWithHandler:firmwareVersionAvailableHandler];
Expand Down
13 changes: 7 additions & 6 deletions source/PTDBeanManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ -(void)connectToBean:(PTDBean*)bean_ withOptions:(NSDictionary*)options error:(N
[cbcentralmanager connectPeripheral:bean.peripheral options:nil];
}

-(void)disconnectBean:(PTDBean*)bean_ error:(NSError**)error{
-(void)disconnectBean:(PTDBean*)bean_ error:(NSError**)error
{
//Find BeanPeripheral that corresponds to this UUID
PTDBean* bean = [beanRecords objectForKey:bean_.identifier];
//Check if the device isn't currently connected
Expand Down Expand Up @@ -342,12 +343,12 @@ - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPe

if(!bean)
return; //This may not be the best way to handle this case
if ( bean.autoReconnect || bean.updateInProgress ) {
PTDLog(@"autoReconnecting to %@", bean);
[self connectToBean:bean error:nil];

if (bean.updateInProgress || bean.autoReconnect) {
PTDLog(@"Auto-reconnecting to %@", bean);
[self connectToBean:bean error:nil];
}

//Alert the delegate of the disconnect
[self __notifyDelegateOfDisconnectedBean:bean error:error];
}
Expand Down
Loading

0 comments on commit a31463a

Please sign in to comment.