Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 7020fc82830cf7a84ee76eb959a2997cc51d26d2 0 parents
@timburks authored
9 README
@@ -0,0 +1,9 @@
+
+This simple iOS app is adapted from Apple's CoreBluetooth: Health Thermometer
+sample app (a Mac app).
+
+http://developer.apple.com/library/mac/#samplecode/HealthThermometer
+
+Use freely.
+
+Tim Burks
275 iOSHealthThermometer.xcodeproj/project.pbxproj
@@ -0,0 +1,275 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 22A8518B153E8F3E000B4042 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22A8518A153E8F3E000B4042 /* UIKit.framework */; };
+ 22A8518D153E8F3E000B4042 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22A8518C153E8F3E000B4042 /* Foundation.framework */; };
+ 22A8518F153E8F3E000B4042 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22A8518E153E8F3E000B4042 /* CoreGraphics.framework */; };
+ 22A85195153E8F3E000B4042 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 22A85193153E8F3E000B4042 /* InfoPlist.strings */; };
+ 22A85197153E8F3E000B4042 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A85196153E8F3E000B4042 /* main.m */; };
+ 22A8519B153E8F3E000B4042 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A8519A153E8F3E000B4042 /* AppDelegate.m */; };
+ 22A851A2153E8F4F000B4042 /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22A851A1153E8F4F000B4042 /* CoreBluetooth.framework */; };
+ 22A851AE153E964B000B4042 /* ThermometerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A851AC153E964A000B4042 /* ThermometerViewController.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 22A85186153E8F3E000B4042 /* iOSHealthThermometer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSHealthThermometer.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 22A8518A153E8F3E000B4042 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ 22A8518C153E8F3E000B4042 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 22A8518E153E8F3E000B4042 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+ 22A85192153E8F3E000B4042 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 22A85196153E8F3E000B4042 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 22A85198153E8F3E000B4042 /* Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = "<group>"; };
+ 22A85199153E8F3E000B4042 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ 22A8519A153E8F3E000B4042 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ 22A851A1153E8F4F000B4042 /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; };
+ 22A851AB153E964A000B4042 /* ThermometerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThermometerViewController.h; sourceTree = "<group>"; };
+ 22A851AC153E964A000B4042 /* ThermometerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThermometerViewController.m; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 22A85183153E8F3E000B4042 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 22A851A2153E8F4F000B4042 /* CoreBluetooth.framework in Frameworks */,
+ 22A8518B153E8F3E000B4042 /* UIKit.framework in Frameworks */,
+ 22A8518D153E8F3E000B4042 /* Foundation.framework in Frameworks */,
+ 22A8518F153E8F3E000B4042 /* CoreGraphics.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 22A8517B153E8F3E000B4042 = {
+ isa = PBXGroup;
+ children = (
+ 22A85190153E8F3E000B4042 /* iOSHealthThermometer */,
+ 22A85189153E8F3E000B4042 /* Frameworks */,
+ 22A85187153E8F3E000B4042 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ 22A85187153E8F3E000B4042 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 22A85186153E8F3E000B4042 /* iOSHealthThermometer.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 22A85189153E8F3E000B4042 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 22A851A1153E8F4F000B4042 /* CoreBluetooth.framework */,
+ 22A8518A153E8F3E000B4042 /* UIKit.framework */,
+ 22A8518C153E8F3E000B4042 /* Foundation.framework */,
+ 22A8518E153E8F3E000B4042 /* CoreGraphics.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 22A85190153E8F3E000B4042 /* iOSHealthThermometer */ = {
+ isa = PBXGroup;
+ children = (
+ 22A85199153E8F3E000B4042 /* AppDelegate.h */,
+ 22A8519A153E8F3E000B4042 /* AppDelegate.m */,
+ 22A851AB153E964A000B4042 /* ThermometerViewController.h */,
+ 22A851AC153E964A000B4042 /* ThermometerViewController.m */,
+ 22A85191153E8F3E000B4042 /* Supporting Files */,
+ );
+ path = iOSHealthThermometer;
+ sourceTree = "<group>";
+ };
+ 22A85191153E8F3E000B4042 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 22A85192153E8F3E000B4042 /* Info.plist */,
+ 22A85193153E8F3E000B4042 /* InfoPlist.strings */,
+ 22A85196153E8F3E000B4042 /* main.m */,
+ 22A85198153E8F3E000B4042 /* Prefix.pch */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 22A85185153E8F3E000B4042 /* iOSHealthThermometer */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 22A8519E153E8F3E000B4042 /* Build configuration list for PBXNativeTarget "iOSHealthThermometer" */;
+ buildPhases = (
+ 22A85182153E8F3E000B4042 /* Sources */,
+ 22A85183153E8F3E000B4042 /* Frameworks */,
+ 22A85184153E8F3E000B4042 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = iOSHealthThermometer;
+ productName = iOSHealthThermometer;
+ productReference = 22A85186153E8F3E000B4042 /* iOSHealthThermometer.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 22A8517D153E8F3E000B4042 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0430;
+ ORGANIZATIONNAME = "Radtastical Inc.";
+ };
+ buildConfigurationList = 22A85180153E8F3E000B4042 /* Build configuration list for PBXProject "iOSHealthThermometer" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 22A8517B153E8F3E000B4042;
+ productRefGroup = 22A85187153E8F3E000B4042 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 22A85185153E8F3E000B4042 /* iOSHealthThermometer */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 22A85184153E8F3E000B4042 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 22A85195153E8F3E000B4042 /* InfoPlist.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 22A85182153E8F3E000B4042 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 22A85197153E8F3E000B4042 /* main.m in Sources */,
+ 22A8519B153E8F3E000B4042 /* AppDelegate.m in Sources */,
+ 22A851AE153E964B000B4042 /* ThermometerViewController.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 22A85193153E8F3E000B4042 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 22A8519C153E8F3E000B4042 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 5.1;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 22A8519D153E8F3E000B4042 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 5.1;
+ OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 22A8519F153E8F3E000B4042 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = iOSHealthThermometer/Prefix.pch;
+ INFOPLIST_FILE = iOSHealthThermometer/Info.plist;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ WRAPPER_EXTENSION = app;
+ };
+ name = Debug;
+ };
+ 22A851A0153E8F3E000B4042 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = iOSHealthThermometer/Prefix.pch;
+ INFOPLIST_FILE = iOSHealthThermometer/Info.plist;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ WRAPPER_EXTENSION = app;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 22A85180153E8F3E000B4042 /* Build configuration list for PBXProject "iOSHealthThermometer" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 22A8519C153E8F3E000B4042 /* Debug */,
+ 22A8519D153E8F3E000B4042 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 22A8519E153E8F3E000B4042 /* Build configuration list for PBXNativeTarget "iOSHealthThermometer" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 22A8519F153E8F3E000B4042 /* Debug */,
+ 22A851A0153E8F3E000B4042 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 22A8517D153E8F3E000B4042 /* Project object */;
+}
11 iOSHealthThermometer/AppDelegate.h
@@ -0,0 +1,11 @@
+//
+// AppDelegate.h
+// iOSHealthThermometer
+//
+// Created by Tim Burks on 7/2/12.
+// Copyright (c) 2012 Radtastical Inc. All rights reserved.
+//
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+@property (nonatomic, strong) UIWindow *window;
+@end
24 iOSHealthThermometer/AppDelegate.m
@@ -0,0 +1,24 @@
+//
+// AppDelegate.m
+// iOSHealthThermometer
+//
+// Created by Tim Burks on 7/2/12.
+// Copyright (c) 2012 Radtastical Inc. All rights reserved.
+//
+
+#import "AppDelegate.h"
+#import "ThermometerViewController.h"
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ NSLog(@"Launching");
+ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+ [self.window makeKeyAndVisible];
+
+ self.window.rootViewController = [[ThermometerViewController alloc] init];
+ return YES;
+}
+
+@end
45 iOSHealthThermometer/Info.plist
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.radtastical.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>UISupportedInterfaceOrientations~ipad</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
14 iOSHealthThermometer/Prefix.pch
@@ -0,0 +1,14 @@
+//
+// Prefix header for all source files of the 'iOSHealthThermometer' target in the 'iOSHealthThermometer' project
+//
+
+#import <Availability.h>
+
+#ifndef __IPHONE_3_0
+#warning "This project uses features only available in iOS SDK 3.0 and later."
+#endif
+
+#ifdef __OBJC__
+ #import <UIKit/UIKit.h>
+ #import <Foundation/Foundation.h>
+#endif
11 iOSHealthThermometer/ThermometerViewController.h
@@ -0,0 +1,11 @@
+//
+// ThermometerViewController.h
+// iOSHealthThermometer
+//
+// Created by Tim Burks on 7/2/12.
+// Copyright (c) 2012 Radtastical Inc. All rights reserved.
+//
+
+@interface ThermometerViewController : UIViewController
+
+@end
466 iOSHealthThermometer/ThermometerViewController.m
@@ -0,0 +1,466 @@
+//
+// ThermometerViewController.m
+// iOSHealthThermometer
+//
+// Created by Tim Burks on 7/2/12.
+// Copyright (c) 2012 Radtastical Inc. All rights reserved.
+//
+
+#import "ThermometerViewController.h"
+#import <CoreBluetooth/CoreBluetooth.h>
+
+@interface ThermometerViewController () <CBCentralManagerDelegate, CBPeripheralDelegate>
+@property (nonatomic, strong) CBCentralManager *manager;
+@property (nonatomic, strong) CBPeripheral *peripheral;
+@property (nonatomic, strong) CBCharacteristic *temperatureCharacteristic;
+@property (nonatomic, strong) CBCharacteristic *intermediateTemperatureCharacteristic;
+@property (nonatomic, strong) NSMutableArray *thermometers;
+
+@property (nonatomic, strong) UILabel *temperatureLabel;
+@property (nonatomic, strong) UILabel *rssiLabel;
+@property (nonatomic, strong) UILabel *manufacturerLabel;
+@end
+
+@implementation ThermometerViewController
+
+- (id) init {
+ if (self = [super init]) {
+ self.thermometers = [NSMutableArray array];
+ self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
+ [self startScan];
+ }
+ return self;
+}
+
+- (void) prepareLabel:(UILabel *) label {
+ label.autoresizingMask = UIViewAutoresizingFlexibleWidth+UIViewAutoresizingFlexibleHeight;
+ label.textAlignment = UITextAlignmentCenter;
+ label.backgroundColor = [UIColor clearColor];
+ label.textColor = [UIColor redColor];
+ [self.view addSubview:label];
+}
+
+- (void)loadView
+{
+ [super loadView];
+ self.temperatureLabel = [[UILabel alloc]
+ initWithFrame:CGRectInset(self.view.bounds,
+ 0.2*self.view.bounds.size.width,
+ 0.45*self.view.bounds.size.height)];
+ self.temperatureLabel.font = [UIFont boldSystemFontOfSize:self.view.bounds.size.width * 0.10];
+ self.temperatureLabel.text = @"";
+ [self prepareLabel:self.temperatureLabel];
+
+ self.rssiLabel = [[UILabel alloc]
+ initWithFrame:CGRectOffset(self.temperatureLabel.frame,
+ 0,
+ self.temperatureLabel.frame.size.height)];
+ self.rssiLabel.font = [UIFont boldSystemFontOfSize:self.view.bounds.size.width * 0.05];
+ self.rssiLabel.text = @"";
+ [self prepareLabel:self.rssiLabel];
+
+
+ self.manufacturerLabel = [[UILabel alloc]
+ initWithFrame:CGRectOffset(self.rssiLabel.frame,
+ 0,
+ self.rssiLabel.frame.size.height)];
+ self.manufacturerLabel.font = [UIFont boldSystemFontOfSize:self.view.bounds.size.width * 0.05];
+ self.manufacturerLabel.text = @"Disconnected";
+ [self prepareLabel:self.manufacturerLabel];
+}
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
+{
+ return (interfaceOrientation == UIInterfaceOrientationPortrait);
+}
+
+#pragma mark - Start/Stop Scan methods
+
+// Use CBCentralManager to check whether the current platform/hardware supports Bluetooth LE.
+- (BOOL) isLECapableHardware
+{
+ NSString * state = nil;
+ switch ([self.manager state]) {
+ case CBCentralManagerStateUnsupported:
+ state = @"The platform/hardware doesn't support Bluetooth Low Energy.";
+ break;
+ case CBCentralManagerStateUnauthorized:
+ state = @"The app is not authorized to use Bluetooth Low Energy.";
+ break;
+ case CBCentralManagerStatePoweredOff:
+ state = @"Bluetooth is currently powered off.";
+ break;
+ case CBCentralManagerStatePoweredOn:
+ return TRUE;
+ case CBCentralManagerStateUnknown:
+ default:
+ return FALSE;
+ }
+ NSLog(@"Central manager state: %@", state);
+ return FALSE;
+}
+
+// Request CBCentralManager to scan for peripherals
+- (void) startScan
+{
+ NSArray *services = nil; // [NSArray arrayWithObject:[CBUUID UUIDWithString:@"1809"]];
+ [self.manager scanForPeripheralsWithServices:services options:nil];
+}
+
+// Request CBCentralManager to stop scanning for peripherals
+- (void) stopScan
+{
+ [self.manager stopScan];
+}
+
+#pragma mark - CBCentralManager delegate methods
+
+// Invoked when the central manager's state is updated.
+- (void) centralManagerDidUpdateState:(CBCentralManager *)central
+{
+ [self isLECapableHardware];
+}
+
+// Invoked when the central discovers peripheral while scanning.
+- (void) centralManager:(CBCentralManager *)central
+ didDiscoverPeripheral:(CBPeripheral *)aPeripheral
+ advertisementData:(NSDictionary *)advertisementData
+ RSSI:(NSNumber *)RSSI
+{
+ NSLog(@"RSSI %@", RSSI);
+ NSMutableArray *peripherals = [self mutableArrayValueForKey:@"thermometers"];
+ if(![self.thermometers containsObject:aPeripheral])
+ [peripherals addObject:aPeripheral];
+
+ // Retrieve already known devices
+ [self.manager retrievePeripherals:[NSArray arrayWithObject:(id)aPeripheral.UUID]];
+}
+
+// Invoked when the central manager retrieves the list of known peripherals.
+// Automatically connect to first known peripheral
+- (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
+{
+ NSLog(@"Retrieved peripheral: %u - %@", [peripherals count], peripherals);
+ [self stopScan];
+ // If there are any known devices, automatically connect to it.
+ if([peripherals count] >= 1) {
+ NSLog(@"connecting...");
+ self.peripheral = [peripherals objectAtIndex:0];
+ [self.manager connectPeripheral:self.peripheral
+ options:[NSDictionary dictionaryWithObject:
+ [NSNumber numberWithBool:YES]
+ forKey:
+ CBConnectPeripheralOptionNotifyOnDisconnectionKey]];
+ }
+}
+
+// Invoked when a connection is succesfully created with the peripheral.
+// Discover available services on the peripheral
+- (void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)aPeripheral
+{
+ NSLog(@"connected");
+ [aPeripheral setDelegate:self];
+ [aPeripheral discoverServices:nil];
+}
+
+// Invoked when an existing connection with the peripheral is torn down.
+// Reset local variables
+- (void) centralManager:(CBCentralManager *)central
+didDisconnectPeripheral:(CBPeripheral *)aPeripheral
+ error:(NSError *)error
+{
+ if (self.peripheral) {
+ [self.peripheral setDelegate:nil];
+ self.peripheral = nil;
+ }
+ self.temperatureLabel.text = @"";
+ self.rssiLabel.text = @"";
+ self.manufacturerLabel.text = @"Disconnected";
+ [self startScan];
+}
+
+// Invoked when the central manager fails to create a connection with the peripheral.
+- (void) centralManager:(CBCentralManager *)central
+didFailToConnectPeripheral:(CBPeripheral *)aPeripheral
+ error:(NSError *)error
+{
+ NSLog(@"Fail to connect to peripheral: %@ with error = %@", aPeripheral, [error localizedDescription]);
+ if (self.peripheral) {
+ [self.peripheral setDelegate:nil];
+ self.peripheral = nil;
+ }
+}
+
+#pragma mark - CBPeripheral delegate methods
+
+// Invoked upon completion of a -[discoverServices:] request.
+// Discover available characteristics on interested services
+- (void) peripheral:(CBPeripheral *)aPeripheral didDiscoverServices:(NSError *)error
+{
+ for (CBService *aService in aPeripheral.services) {
+ NSLog(@"Service found with UUID: %@", aService.UUID);
+
+ /* Thermometer Service */
+ if ([aService.UUID isEqual:[CBUUID UUIDWithString:@"1809"]]) {
+ [aPeripheral discoverCharacteristics:nil forService:aService];
+ }
+
+ /* Device Information Service */
+ if ([aService.UUID isEqual:[CBUUID UUIDWithString:@"180A"]]) {
+ [aPeripheral discoverCharacteristics:nil forService:aService];
+ }
+
+ /* GAP (Generic Access Profile) for Device Name */
+ if ([aService.UUID isEqual:[CBUUID UUIDWithString:CBUUIDGenericAccessProfileString]]) {
+ [aPeripheral discoverCharacteristics:nil forService:aService];
+ }
+ }
+}
+
+/*
+ Invoked upon completion of a -[discoverCharacteristics:forService:] request.
+ */
+- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
+{
+ if (error)
+ {
+ NSLog(@"Discovered characteristics for %@ with error: %@",
+ service.UUID, [error localizedDescription]);
+ return;
+ }
+
+ if([service.UUID isEqual:[CBUUID UUIDWithString:@"1809"]])
+ {
+ for (CBCharacteristic * characteristic in service.characteristics)
+ {
+ NSLog(@"discovered characteristic %@", characteristic.UUID);
+ /* Set indication on temperature measurement */
+ if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A1C"]])
+ {
+ self.temperatureCharacteristic = characteristic;
+ [self.peripheral setNotifyValue:YES forCharacteristic:self.temperatureCharacteristic];
+ NSLog(@"Found a Temperature Measurement Characteristic");
+ }
+ /* Set notification on intermediate temperature measurement */
+ if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A1E"]])
+ {
+ self.intermediateTemperatureCharacteristic = characteristic;
+ NSLog(@"Found an Intermediate Temperature Measurement Characteristic");
+ [self.peripheral setNotifyValue:YES forCharacteristic:self.intermediateTemperatureCharacteristic];
+ }
+ /* Write value to measurement interval characteristic */
+ if( [characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A24"]])
+ {
+ uint16_t val = 2;
+ NSData * valData = [NSData dataWithBytes:(void*)&val length:sizeof(val)];
+ [self.peripheral writeValue:valData forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
+ NSLog(@"Found a Temperature Measurement Interval Characteristic - Write interval value");
+ }
+ }
+ }
+
+ else if([service.UUID isEqual:[CBUUID UUIDWithString:@"180A"]])
+ {
+ for (CBCharacteristic * characteristic in service.characteristics)
+ {
+ NSLog(@"discovered 180A characteristic %@", characteristic.UUID);
+ /* Read manufacturer name */
+ if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A29"]])
+ {
+ [self.peripheral readValueForCharacteristic:characteristic];
+ NSLog(@"Found a Device Manufacturer Name Characteristic - Read manufacturer name");
+ }
+ else {
+ [self.peripheral readValueForCharacteristic:characteristic];
+
+ }
+
+ /* Write value to measurement interval characteristic */
+
+ }
+ }
+
+ else if ( [service.UUID isEqual:[CBUUID UUIDWithString:CBUUIDGenericAccessProfileString]] )
+ {
+ for (CBCharacteristic *characteristic in service.characteristics)
+ {
+ NSLog(@"discovered generic characteristic %@", characteristic.UUID);
+
+ /* Read device name */
+ if([characteristic.UUID isEqual:[CBUUID UUIDWithString:CBUUIDDeviceNameString]])
+ {
+ [self.peripheral readValueForCharacteristic:characteristic];
+ NSLog(@"Found a Device Name Characteristic - Read device name");
+ }
+ }
+ }
+
+ else {
+ NSLog(@"unknown service discovery %@", service.UUID);
+
+ }
+}
+
+/*
+ Invoked upon completion of a -[readValueForCharacteristic:] request or on the reception of a notification/indication.
+ */
+- (void) peripheral:(CBPeripheral *)peripheral
+didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
+ error:(NSError *)error
+{
+ if (error)
+ {
+ NSLog(@"Error updating value for characteristic %@ error: %@", characteristic.UUID, [error localizedDescription]);
+ return;
+ }
+
+ /* Updated value for temperature measurement received */
+ if(([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A1E"]] ||
+ [characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A1C"]]) &&
+ characteristic.value)
+ {
+ NSData * updatedValue = characteristic.value;
+ uint8_t* dataPointer = (uint8_t*)[updatedValue bytes];
+
+ uint8_t flags = dataPointer[0]; dataPointer++;
+ int32_t tempData = (int32_t)CFSwapInt32LittleToHost(*(uint32_t*)dataPointer); dataPointer += 4;
+ int8_t exponent = (int8_t)(tempData >> 24);
+ int32_t mantissa = (int32_t)(tempData & 0x00FFFFFF);
+
+ if( tempData == 0x007FFFFF )
+ {
+ NSLog(@"Invalid temperature value received");
+ return;
+ }
+
+ float tempValue = (float)(mantissa*pow(10, exponent));
+ NSString *temperatureString = [NSString stringWithFormat:@"%.1f", tempValue];
+ NSLog(@"temperatureString %@", temperatureString);
+
+ /* measurement type */
+ if(flags & 0x01)
+ {
+ temperatureString = [temperatureString stringByAppendingString:@"ºF"];
+ NSLog(@"measurement type: ºF");
+ }
+ else
+ {
+ temperatureString = [temperatureString stringByAppendingString:@"ºC"];
+ NSLog(@"measurement type: ºC");
+ }
+
+ /* timestamp */
+ if( flags & 0x02 )
+ {
+ uint16_t year = CFSwapInt16LittleToHost(*(uint16_t*)dataPointer); dataPointer += 2;
+ uint8_t month = *(uint8_t*)dataPointer; dataPointer++;
+ uint8_t day = *(uint8_t*)dataPointer; dataPointer++;
+ uint8_t hour = *(uint8_t*)dataPointer; dataPointer++;
+ uint8_t min = *(uint8_t*)dataPointer; dataPointer++;
+ uint8_t sec = *(uint8_t*)dataPointer; dataPointer++;
+
+ NSString * dateString = [NSString stringWithFormat:@"%d %d %d %d %d %d", year, month, day, hour, min, sec];
+
+ NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
+ [dateFormat setDateFormat: @"yyyy MM dd HH mm ss"];
+ NSDate* date = [dateFormat dateFromString:dateString];
+
+ [dateFormat setDateFormat:@"EEE MMM dd, yyyy"];
+ NSString* dateFormattedString = [dateFormat stringFromDate:date];
+
+ [dateFormat setDateFormat:@"h:mm a"];
+ NSString* timeFormattedString = [dateFormat stringFromDate:date];
+
+
+ if( dateFormattedString && timeFormattedString )
+ {
+ NSString *timeStampString = [NSString stringWithFormat:@"%@ at %@", dateFormattedString, timeFormattedString];
+ NSLog(@"timestamp %@", timeStampString);
+ }
+ }
+
+ /* temperature type */
+ if( flags & 0x04 )
+ {
+ uint8_t type = *(uint8_t*)dataPointer;
+ NSString* location = nil;
+
+ switch (type)
+ {
+ case 0x01:
+ location = @"Armpit";
+ break;
+ case 0x02:
+ location = @"Body - general";
+ break;
+ case 0x03:
+ location = @"Ear";
+ break;
+ case 0x04:
+ location = @"Finger";
+ break;
+ case 0x05:
+ location = @"Gastro-intenstinal Tract";
+ break;
+ case 0x06:
+ location = @"Mouth";
+ break;
+ case 0x07:
+ location = @"Rectum";
+ break;
+ case 0x08:
+ location = @"Toe";
+ break;
+ case 0x09:
+ location = @"Tympanum - ear drum";
+ break;
+ default:
+ break;
+ }
+ if (location)
+ {
+ NSString *temperatureType = [NSString stringWithFormat:@"Body location: %@", location];
+ NSLog(@"temp type: %@", temperatureType);
+ }
+ }
+
+ [self.peripheral readRSSI];
+
+ self.temperatureLabel.text = temperatureString;
+ self.rssiLabel.text = [self.peripheral.RSSI stringValue];
+ }
+
+ /* Value for device name received */
+ else if([characteristic.UUID isEqual:[CBUUID UUIDWithString:CBUUIDDeviceNameString]])
+ {
+ NSString *deviceName = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
+ NSLog(@"Device Name = %@", deviceName);
+ }
+
+ /* Value for manufacturer name received */
+ else if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A29"]])
+ {
+ NSString *manufacturerName = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
+ NSLog(@"Manufacturer Name = %@", manufacturerName);
+ self.manufacturerLabel.text = manufacturerName;
+ }
+ else if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A24"]])
+ {
+ NSLog(@"2A24 thing happening");
+ NSString *thing = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
+ NSLog(@"thing = %@", thing);
+ }
+ else if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A25"]])
+ {
+ NSLog(@"2A25 thing happening");
+ NSData * updatedValue = characteristic.value;
+ NSLog(@"length %d", [updatedValue length]);
+ }
+ else {
+ NSLog(@"unknown thing happening");
+ NSString *thing = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
+ NSLog(@"thing = %@", thing);
+ }
+}
+
+@end
18 iOSHealthThermometer/main.m
@@ -0,0 +1,18 @@
+//
+// main.m
+// iOSHealthThermometer
+//
+// Created by Tim Burks on 4/17/12.
+// Copyright (c) 2012 Radtastical Inc. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+#import "AppDelegate.h"
+
+int main(int argc, char *argv[])
+{
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.