Skip to content

Instantly share code, notes, and snippets.

@jonathanlking
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonathanlking/0dfbc5123bcf4de2db8e to your computer and use it in GitHub Desktop.
Save jonathanlking/0dfbc5123bcf4de2db8e to your computer and use it in GitHub Desktop.
Ammmendments made to run UI changes on main thread using GCD
//
// DeviceDetailViewController.m
// MetaWearApiTest
//
// Created by Stephen Schiffli on 7/30/14.
// Copyright (c) 2014 MbientLab. All rights reserved.
//
// Amendments made to run UI changes on main thread using GCD by Jonathan King - 31/8/14
#import "DeviceDetailViewController.h"
#import "MBProgressHUD.h"
#import "APLGraphView.h"
@interface DeviceDetailViewController () <MFMailComposeViewControllerDelegate>
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (weak, nonatomic) IBOutlet UISwitch *connectionSwitch;
@property (weak, nonatomic) IBOutlet UILabel *tempratureLabel;
@property (weak, nonatomic) IBOutlet UISegmentedControl *accelerometerScale;
@property (weak, nonatomic) IBOutlet UISegmentedControl *sampleFrequency;
@property (weak, nonatomic) IBOutlet UISwitch *highPassFilterSwitch;
@property (weak, nonatomic) IBOutlet UISwitch *lowNoiseSwitch;
@property (weak, nonatomic) IBOutlet UISegmentedControl *activePowerScheme;
@property (weak, nonatomic) IBOutlet UISwitch *autoSleepSwitch;
@property (weak, nonatomic) IBOutlet UISegmentedControl *sleepSampleFrequency;
@property (weak, nonatomic) IBOutlet UISegmentedControl *sleepPowerScheme;
@property (weak, nonatomic) IBOutlet APLGraphView *accelerometerGraph;
@property (weak, nonatomic) IBOutlet UILabel *mechanicalSwitchLabel;
@property (weak, nonatomic) IBOutlet UILabel *batteryLevelLabel;
@property (weak, nonatomic) IBOutlet UILabel *rssiLevelLabel;
@property (weak, nonatomic) IBOutlet UITextField *hapticPulseWidth;
@property (weak, nonatomic) IBOutlet UITextField *hapticDutyCycle;
@property (weak, nonatomic) IBOutlet UISegmentedControl *gpioPinSelector;
@property (weak, nonatomic) IBOutlet UILabel *gpioPinDigitalValue;
@property (weak, nonatomic) IBOutlet UILabel *gpioPinAnalogValue;
@property (weak, nonatomic) IBOutlet UIButton *startAccelerometer;
@property (weak, nonatomic) IBOutlet UIButton *stopAccelerometer;
@property (weak, nonatomic) IBOutlet UILabel *mfgNameLabel;
@property (weak, nonatomic) IBOutlet UILabel *serialNumLabel;
@property (weak, nonatomic) IBOutlet UILabel *hwRevLabel;
@property (weak, nonatomic) IBOutlet UILabel *fwRevLabel;
@property (weak, nonatomic) IBOutlet UILabel *firmwareUpdateLabel;
@property (strong, nonatomic) UIView *grayScreen;
@property (strong, nonatomic) NSString *accDataString;
@property (strong, nonatomic) NSMutableArray *accDataArray;
@end
@implementation DeviceDetailViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.grayScreen = [[UIView alloc] initWithFrame:CGRectMake(0, 120, self.view.frame.size.width, self.view.frame.size.height - 120)];
self.grayScreen.backgroundColor = [UIColor grayColor];
self.grayScreen.alpha = 0.4;
[self.view addSubview:self.grayScreen];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self connectDevice:YES];
[self.stopAccelerometer setEnabled:FALSE];
}
- (void)setConnected:(BOOL)on
{
[self.connectionSwitch setOn:on animated:YES];
[self.grayScreen setHidden:on];
}
- (void)connectDevice:(BOOL)on
{
if (on) {
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = @"Connecting...";
[[MBLMetaWearManager sharedManager] connectMetaWear:self.device withHandler:^(NSError *error) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self setConnected:(error == nil)];
hud.mode = MBProgressHUDModeText;
if (error) {
hud.labelText = error.localizedDescription;
[hud hide:YES afterDelay:2];
} else {
hud.labelText = @"Connected!";
[hud hide:YES afterDelay:0.5];
}
}];
}];
} else {
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = @"Disconnecting...";
[[MBLMetaWearManager sharedManager] cancelMetaWearConnection:self.device withHandler:^(NSError *error) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self setConnected:NO];
hud.mode = MBProgressHUDModeText;
if (error) {
hud.labelText = error.localizedDescription;
[hud hide:YES afterDelay:2];
} else {
hud.labelText = @"Disconnected!";
[hud hide:YES afterDelay:0.5];
}
}];
}];
}
}
- (IBAction)connectionSwitchPressed:(id)sender
{
[self connectDevice:self.connectionSwitch.on];
}
- (IBAction)readTempraturePressed:(id)sender
{
[self.device.temperature readTemperatureWithHandler:^(NSDecimalNumber *temp, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{self.tempratureLabel.text = [temp stringValue];});
}];
}
- (IBAction)turnOnGreenLEDPressed:(id)sender
{
[self.device.led setLEDColor:[UIColor greenColor] withIntensity:0.25];
}
- (IBAction)flashGreenLEDPressed:(id)sender
{
[self.device.led flashLEDColor:[UIColor greenColor] withIntensity:0.25];
}
- (IBAction)turnOnRedLEDPressed:(id)sender
{
[self.device.led setLEDColor:[UIColor redColor] withIntensity:0.25];
}
- (IBAction)flashRedLEDPressed:(id)sender
{
[self.device.led flashLEDColor:[UIColor redColor] withIntensity:0.25];
}
- (IBAction)turnOnBlueLEDPressed:(id)sender
{
[self.device.led setLEDColor:[UIColor blueColor] withIntensity:0.25];
}
- (IBAction)flashBlueLEDPressed:(id)sender
{
[self.device.led flashLEDColor:[UIColor blueColor] withIntensity:0.25];
}
- (IBAction)turnOffLEDPressed:(id)sender
{
[self.device.led setLEDOn:NO withOptions:1];
}
- (IBAction)readSwitchPressed:(id)sender
{
[self.device.mechanicalSwitch readSwitchStateWithHandler:^(BOOL isPressed, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{self.mechanicalSwitchLabel.text = isPressed ? @"Down" : @"Up";});
}];
}
- (IBAction)startSwitchNotifyPressed:(id)sender
{
[self.device.mechanicalSwitch startSwitchUpdatesWithHandler:^(BOOL isPressed, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{self.mechanicalSwitchLabel.text = isPressed ? @"Down" : @"Up";});
}];
}
- (IBAction)StopSwitchNotifyPressed:(id)sender
{
[self.device.mechanicalSwitch stopSwitchUpdates];
}
- (IBAction)readBatteryPressed:(id)sender
{
[self.device readBatteryLifeWithHandler:^(NSNumber *number, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{self.batteryLevelLabel.text = [number stringValue];});
}];
}
- (IBAction)readRSSIPressed:(id)sender
{
[self.device readRSSIWithHandler:^(NSNumber *number, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{self.rssiLevelLabel.text = [number stringValue];});
}];
}
- (IBAction)readDeviceInfoPressed:(id)sender
{
[self.device readDeviceInfoWithHandler:^(MBLDeviceInfo *deviceInfo, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
self.mfgNameLabel.text = deviceInfo.manufacturerName;
self.serialNumLabel.text = deviceInfo.serialNumber;
self.hwRevLabel.text = deviceInfo.hardwareRevision;
self.fwRevLabel.text = deviceInfo.firmwareRevision;
});
}];
}
- (IBAction)resetDevicePressed:(id)sender
{
// Resetting causes a disconnection
[self setConnected:NO];
[self.device resetDevice];
}
- (IBAction)checkForFirmwareUpdatesPressed:(id)sender
{
[self.device checkForFirmwareUpdateWithHandler:^(BOOL isTrue, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{self.firmwareUpdateLabel.text = isTrue ? @"Avaliable!" : @"Up To Date";});
}];
}
- (IBAction)updateFirmware:(id)sender
{
// Pause the screen while update is going on
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeDeterminateHorizontalBar;
hud.labelText = @"Updating...";
// Updating firmware causes a disconnection
[self setConnected:NO];
[self.device updateFirmwareWithHandler:^(NSError *error) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
if (error) {
hud.labelText = error.localizedDescription;
NSLog(@"Firmware update error: %@", error.localizedDescription);
} else {
hud.labelText = @"Success!";
}
[hud hide:YES afterDelay:2.5];
}];
} progressHandler:^(float number, NSError *error) {
hud.progress = number;
}];
}
- (IBAction)startHapticDriverPressed:(id)sender
{
uint8_t dcycle = [self.hapticDutyCycle.text intValue];
uint16_t pwidth = [self.hapticPulseWidth.text intValue];
[self.device.hapticBuzzer startHapticWithDutyCycle:dcycle pulseWidth:pwidth completion:^{
[self.device.hapticBuzzer startHapticWithDutyCycle:dcycle pulseWidth:pwidth completion:nil];
}];
}
- (IBAction)startiBeaconPressed:(id)sender
{
[self.device.iBeacon setBeaconOn:YES];
}
- (IBAction)stopiBeaconPressed:(id)sender
{
[self.device.iBeacon setBeaconOn:NO];
}
- (IBAction)setPullUpPressed:(id)sender
{
[self.device.gpio configurePin:self.gpioPinSelector.selectedSegmentIndex withOptions:0];
}
- (IBAction)setPullDownPressed:(id)sender
{
[self.device.gpio configurePin:self.gpioPinSelector.selectedSegmentIndex withOptions:1];
}
- (IBAction)setNoPullPressed:(id)sender
{
[self.device.gpio configurePin:self.gpioPinSelector.selectedSegmentIndex withOptions:2];
}
- (IBAction)setPinPressed:(id)sender
{
[self.device.gpio setPin:self.gpioPinSelector.selectedSegmentIndex toDigitalValue:YES];
}
- (IBAction)clearPinPressed:(id)sender
{
[self.device.gpio setPin:self.gpioPinSelector.selectedSegmentIndex toDigitalValue:NO];
}
- (IBAction)readDigitalPressed:(id)sender
{
[self.device.gpio readDigitalPin:self.gpioPinSelector.selectedSegmentIndex withHander:^(BOOL isTrue, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{self.gpioPinDigitalValue.text = isTrue ? @"1" : @"0";});
}];
}
- (IBAction)readAnalogPressed:(id)sender
{
[self.device.gpio readAnalogPin:self.gpioPinSelector.selectedSegmentIndex usingOptions:0 withHandler:^(NSDecimalNumber *number, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{self.gpioPinAnalogValue.text = [number stringValue];});
}];
}
- (IBAction)startAccelerationPressed:(id)sender
{
if (self.accelerometerScale.selectedSegmentIndex == 0) {
self.accelerometerGraph.fullScale = 2;
} else if (self.accelerometerScale.selectedSegmentIndex == 1) {
self.accelerometerGraph.fullScale = 4;
} else {
self.accelerometerGraph.fullScale = 8;
}
self.device.accelerometer.fullScaleRange = (int)self.accelerometerScale.selectedSegmentIndex;
self.device.accelerometer.sampleFrequency = (int)self.sampleFrequency.selectedSegmentIndex;
self.device.accelerometer.highPassFilter = self.highPassFilterSwitch.on;
self.device.accelerometer.lowNoise = self.highPassFilterSwitch.on;
self.device.accelerometer.activePowerScheme = (int)self.activePowerScheme.selectedSegmentIndex;
self.device.accelerometer.autoSleep = self.autoSleepSwitch.on;
self.device.accelerometer.sleepSampleFrequency = (int)self.sleepSampleFrequency.selectedSegmentIndex;
self.device.accelerometer.activePowerScheme = (int)self.activePowerScheme.selectedSegmentIndex;
[self.startAccelerometer setEnabled:FALSE];
[self.stopAccelerometer setEnabled:TRUE];
// These variables are used for data recording
self.accDataArray = [[NSMutableArray alloc] initWithCapacity:1000];
[self.device.accelerometer startAccelerometerUpdatesWithHandler:^(MBLAccelerometerData *acceleration, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.accelerometerGraph addX:acceleration.x y:acceleration.y z:acceleration.z];
// Add data to data array for saving
[self.accDataArray addObject:acceleration];
});
}];
}
- (IBAction)stopAccelerationPressed:(id)sender
{
[self.device.accelerometer stopAccelerometerUpdates];
[self.startAccelerometer setEnabled:TRUE];
[self.stopAccelerometer setEnabled:FALSE];
self.accDataString = [self processAccData];
}
- (NSString *)processAccData
{
NSMutableString *AccelerometerString = [[NSMutableString alloc] init];
for (MBLAccelerometerData *dataElement in self.accDataArray)
{
@autoreleasepool {
[AccelerometerString appendFormat:@"%f,%f,%f,%f\n", dataElement.intervalSinceCaptureBegan,
dataElement.x,
dataElement.y,
dataElement.z];
}
}
return AccelerometerString;
}
- (NSString *)saveDatatoDisk:(NSString *)dataString
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterLongStyle];
[dateFormatter setDateStyle:NSDateFormatterShortStyle];
// Some filesystems hate colons
NSString *dateString = [[dateFormatter stringFromDate:[NSDate date]] stringByReplacingOccurrencesOfString:@":" withString:@"_"];
// I hate spaces in dates
dateString = [dateString stringByReplacingOccurrencesOfString:@" " withString:@"_"];
// OS hates forward slashes
dateString = [dateString stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"userAcceleration_%@.txt", dateString, nil]];
[dataString writeToFile:fullPath
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
return fullPath;
}
- (IBAction)sendDataPressed:(id)sender
{
NSString *filePath = [self saveDatatoDisk:self.accDataString];
[self mailMe:filePath];
}
- (void)mailMe:(NSString *)filePath
{
if (![MFMailComposeViewController canSendMail]) {
[[[UIAlertView alloc] initWithTitle:@"Mail Error" message:@"This device does not have an email account setup" delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles:nil] show];
return;
}
// Get current Time/Date
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterLongStyle];
[dateFormatter setDateStyle:NSDateFormatterShortStyle];
// Some filesystems hate colons
NSString *dateString = [[dateFormatter stringFromDate:[NSDate date]] stringByReplacingOccurrencesOfString:@":" withString:@"_"];
// I hate spaces in dates
dateString = [dateString stringByReplacingOccurrencesOfString:@" " withString:@"_"];
// OS hates forward slashes
dateString = [dateString stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
// recipient address
NSString *email = @"your@email.com";
NSMutableArray *toRecipient = [[NSMutableArray alloc]initWithObjects:nil];
[toRecipient addObject:email];
MFMailComposeViewController *emailController = [[MFMailComposeViewController alloc] init];
emailController.mailComposeDelegate = self;
// attachment
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSString *name = [NSString stringWithFormat:@"AccData_%@.txt", dateString, nil];
[emailController addAttachmentData:data mimeType:@"text/plain" fileName:name];
// subject
NSString *subject = [NSString stringWithFormat:@"Accelerometer Data %@.txt", dateString, nil];
[emailController setSubject:subject];
NSString *messageBody = [NSString stringWithFormat:@"The data was recorded on %@.", dateString,nil];
[emailController setMessageBody:messageBody isHTML:NO];
[emailController setToRecipients:toRecipient];
[self presentViewController:emailController animated:YES completion:NULL];
}
-(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
[self dismissViewControllerAnimated:YES completion:nil];
NSLog (@"mail finished"); // NEVER REACHES THIS POINT.
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment