Skip to content

Commit 62a0acc

Browse files
committed
[heartratemonitor] move from other repo
1 parent 2f12d81 commit 62a0acc

37 files changed

+976
-3
lines changed

HeartRateMonitor/AppDelegate.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using MonoTouch.Foundation;
6+
using MonoTouch.UIKit;
7+
8+
namespace Xamarin.HeartMonitor
9+
{
10+
/// <summary>Kick everything off</summary>
11+
public class Application
12+
{
13+
static void Main (string[] args)
14+
{
15+
UIApplication.Main (args, null, "AppDelegate");
16+
}
17+
}
18+
19+
/// <summary>
20+
/// Sizes the window according to the screen, for iPad as well as iPhone support
21+
/// </summary>
22+
[Register ("AppDelegate")]
23+
public class AppDelegate : UIApplicationDelegate
24+
{
25+
UIWindow window;
26+
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
27+
{
28+
var ms = new MainScreen();
29+
30+
window = new UIWindow (UIScreen.MainScreen.Bounds);
31+
window.BackgroundColor = UIColor.White;
32+
window.Bounds = UIScreen.MainScreen.Bounds;
33+
34+
UINavigationBar.Appearance.TintColor = UIColor.Red;
35+
UIButton.Appearance.TintColor = UIColor.Red;
36+
37+
window.RootViewController = ms;
38+
window.MakeKeyAndVisible ();
39+
return true;
40+
}
41+
}
42+
}

HeartRateMonitor/Entitlements.plist

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>com.apple.developer.healthkit</key>
6+
<true/>
7+
</dict>
8+
</plist>

HeartRateMonitor/HeartBeat.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//
2+
// HeartBeat.cs
3+
//
4+
// Author:
5+
// Aaron Bockover <[email protected]>
6+
//
7+
// Copyright 2013 Xamarin, Inc.
8+
//
9+
// Permission is hereby granted, free of charge, to any person obtaining a copy
10+
// of this software and associated documentation files (the "Software"), to deal
11+
// in the Software without restriction, including without limitation the rights
12+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
// copies of the Software, and to permit persons to whom the Software is
14+
// furnished to do so, subject to the following conditions:
15+
//
16+
// The above copyright notice and this permission notice shall be included in
17+
// all copies or substantial portions of the Software.
18+
//
19+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
// THE SOFTWARE.
26+
27+
using System;
28+
29+
namespace Xamarin.HeartMonitor
30+
{
31+
public struct HeartBeat
32+
{
33+
public DateTime Time { get; set; }
34+
public ushort Rate { get; set; }
35+
36+
public override string ToString ()
37+
{
38+
return String.Format ("{0}: {1} bpm", Time, Rate);
39+
}
40+
}
41+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//
2+
// HeartBeatEventArgs.cs
3+
//
4+
// Author:
5+
// Aaron Bockover <[email protected]>
6+
//
7+
// Copyright 2013 Xamarin, Inc.
8+
//
9+
// Permission is hereby granted, free of charge, to any person obtaining a copy
10+
// of this software and associated documentation files (the "Software"), to deal
11+
// in the Software without restriction, including without limitation the rights
12+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
// copies of the Software, and to permit persons to whom the Software is
14+
// furnished to do so, subject to the following conditions:
15+
//
16+
// The above copyright notice and this permission notice shall be included in
17+
// all copies or substantial portions of the Software.
18+
//
19+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
// THE SOFTWARE.
26+
27+
using System;
28+
29+
namespace Xamarin.HeartMonitor
30+
{
31+
public sealed class HeartBeatEventArgs : EventArgs
32+
{
33+
public HeartBeat PreviousHeartBeat { get; private set; }
34+
public HeartBeat CurrentHeartBeat { get; private set; }
35+
36+
public HeartBeatEventArgs (HeartBeat previous, HeartBeat current)
37+
{
38+
PreviousHeartBeat = previous;
39+
CurrentHeartBeat = current;
40+
}
41+
}
42+
}

HeartRateMonitor/HeartRateMonitor.cs

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
//
2+
// HeartRateMonitor.cs
3+
//
4+
// Author:
5+
// Aaron Bockover <[email protected]>
6+
//
7+
// Copyright 2013 Xamarin, Inc.
8+
//
9+
// Permission is hereby granted, free of charge, to any person obtaining a copy
10+
// of this software and associated documentation files (the "Software"), to deal
11+
// in the Software without restriction, including without limitation the rights
12+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
// copies of the Software, and to permit persons to whom the Software is
14+
// furnished to do so, subject to the following conditions:
15+
//
16+
// The above copyright notice and this permission notice shall be included in
17+
// all copies or substantial portions of the Software.
18+
//
19+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
// THE SOFTWARE.
26+
27+
using System;
28+
29+
#if XAMMAC
30+
using MonoMac.Foundation;
31+
using MonoMac.CoreBluetooth;
32+
#else
33+
using MonoTouch.Foundation;
34+
using MonoTouch.CoreBluetooth;
35+
#endif
36+
37+
namespace Xamarin.HeartMonitor
38+
{
39+
public class HeartRateMonitor : CBPeripheralDelegate
40+
{
41+
static readonly CBUUID PeripheralUUID = CBUUID.FromPartial (0x180D);
42+
static readonly CBUUID HeartRateMeasurementCharacteristicUUID = CBUUID.FromPartial (0x2A37);
43+
static readonly CBUUID BodySensorLocationCharacteristicUUID = CBUUID.FromPartial (0x2A38);
44+
static readonly CBUUID HeartRateControlPointCharacteristicUUID = CBUUID.FromPartial (0x2A39);
45+
46+
public static void ScanForHeartRateMonitors (CBCentralManager manager)
47+
{
48+
if (manager == null) {
49+
throw new ArgumentNullException ("manager");
50+
}
51+
52+
manager.ScanForPeripherals (PeripheralUUID);
53+
}
54+
55+
NSTimer beatTimer;
56+
bool disposed;
57+
58+
public CBCentralManager Manager { get; private set; }
59+
public CBPeripheral Peripheral { get; private set; }
60+
61+
public HeartRateMonitorLocation Location { get; private set; }
62+
public HeartBeat CurrentHeartBeat { get; private set; }
63+
public HeartBeat PreviousHeartBeat { get; private set; }
64+
65+
public event EventHandler<HeartBeatEventArgs> HeartRateUpdated;
66+
public event EventHandler HeartBeat;
67+
public event EventHandler LocationUpdated;
68+
69+
public string Name {
70+
get { return Peripheral.Name; }
71+
}
72+
73+
protected override void Dispose (bool disposing)
74+
{
75+
disposed = true;
76+
if (beatTimer != null) {
77+
beatTimer.Dispose ();
78+
beatTimer = null;
79+
}
80+
81+
base.Dispose (disposing);
82+
}
83+
84+
public HeartRateMonitor (CBCentralManager manager, CBPeripheral peripheral)
85+
{
86+
if (manager == null) {
87+
throw new ArgumentNullException ("manager");
88+
} else if (peripheral == null) {
89+
throw new ArgumentNullException ("peripheral");
90+
}
91+
92+
Location = HeartRateMonitorLocation.Unknown;
93+
94+
Manager = manager;
95+
96+
Peripheral = peripheral;
97+
Peripheral.Delegate = this;
98+
Peripheral.DiscoverServices ();
99+
}
100+
101+
public void Connect ()
102+
{
103+
if (disposed) {
104+
return;
105+
}
106+
107+
Manager.ConnectPeripheral (Peripheral, new PeripheralConnectionOptions {
108+
NotifyOnDisconnectionKey = true
109+
});
110+
}
111+
112+
public override void DiscoveredService (CBPeripheral peripheral, NSError error)
113+
{
114+
if (disposed) {
115+
return;
116+
}
117+
118+
foreach (var service in peripheral.Services) {
119+
if (service.UUID == PeripheralUUID) {
120+
peripheral.DiscoverCharacteristics (service);
121+
}
122+
}
123+
}
124+
125+
public override void DiscoverCharacteristic (CBPeripheral peripheral, CBService service, NSError error)
126+
{
127+
if (disposed) {
128+
return;
129+
}
130+
131+
foreach (var characteristic in service.Characteristics) {
132+
if (characteristic.UUID == HeartRateMeasurementCharacteristicUUID) {
133+
service.Peripheral.SetNotifyValue (true, characteristic);
134+
} else if (characteristic.UUID == BodySensorLocationCharacteristicUUID) {
135+
service.Peripheral.ReadValue (characteristic);
136+
} else if (characteristic.UUID == HeartRateControlPointCharacteristicUUID) {
137+
service.Peripheral.WriteValue (NSData.FromBytes ((IntPtr)1, 1),
138+
characteristic, CBCharacteristicWriteType.WithResponse);
139+
}
140+
}
141+
}
142+
143+
public override void UpdatedCharacterteristicValue (CBPeripheral peripheral, CBCharacteristic characteristic, NSError error)
144+
{
145+
if (disposed || error != null || characteristic.Value == null) {
146+
return;
147+
}
148+
149+
if (characteristic.UUID == HeartRateMeasurementCharacteristicUUID) {
150+
UpdateHeartRate (characteristic.Value);
151+
} else if (characteristic.UUID == BodySensorLocationCharacteristicUUID) {
152+
UpdateBodySensorLocation (characteristic.Value);
153+
}
154+
}
155+
156+
protected virtual void OnHeartRateUpdated ()
157+
{
158+
var handler = HeartRateUpdated;
159+
if (handler != null) {
160+
handler (this, new HeartBeatEventArgs (PreviousHeartBeat, CurrentHeartBeat));
161+
}
162+
}
163+
164+
protected virtual void OnHeartBeat ()
165+
{
166+
var handler = HeartBeat;
167+
if (handler != null) {
168+
handler (this, EventArgs.Empty);
169+
}
170+
}
171+
172+
protected virtual void OnLocationUpdated ()
173+
{
174+
var handler = LocationUpdated;
175+
if (handler != null) {
176+
handler (this, EventArgs.Empty);
177+
}
178+
}
179+
180+
void ScheduleBeatTimer ()
181+
{
182+
if (disposed) {
183+
return;
184+
}
185+
186+
if (beatTimer != null) {
187+
beatTimer.Dispose ();
188+
}
189+
190+
OnHeartBeat ();
191+
beatTimer = NSTimer.CreateScheduledTimer (60 / (double)CurrentHeartBeat.Rate, ScheduleBeatTimer);
192+
}
193+
194+
/* to use the unsafe version of this method,
195+
* 'tick' **Project > Options > Build > General > Allow 'unsafe' code** */
196+
/*unsafe*/ void UpdateHeartRate (NSData hr)
197+
{
198+
var now = DateTime.Now;
199+
200+
// unsafe line
201+
// var data = (byte *)hr.Bytes;
202+
203+
// replaced by safe lines
204+
byte[] data = new byte[hr.Length];
205+
System.Runtime.InteropServices.Marshal.Copy(hr.Bytes, data, 0, Convert.ToInt32(hr.Length));
206+
// end safe lines
207+
208+
ushort bpm = 0;
209+
if ((data [0] & 0x01) == 0) {
210+
bpm = data [1];
211+
} else {
212+
bpm = (ushort)data [1];
213+
bpm = (ushort)(((bpm >> 8) & 0xFF) | ((bpm << 8) & 0xFF00));
214+
}
215+
216+
PreviousHeartBeat = CurrentHeartBeat;
217+
CurrentHeartBeat = new HeartBeat { Time = now, Rate = bpm };
218+
219+
OnHeartRateUpdated ();
220+
221+
if (PreviousHeartBeat.Rate == 0 && CurrentHeartBeat.Rate != 0) {
222+
OnHeartBeat ();
223+
ScheduleBeatTimer ();
224+
}
225+
}
226+
227+
/* to use the unsafe version of this method,
228+
* 'tick' **Project > Options > Build > General > Allow 'unsafe' code** */
229+
/*unsafe*/ void UpdateBodySensorLocation (NSData location)
230+
{
231+
// unsafe line
232+
// var value = ((byte *)location.Bytes) [0];
233+
234+
// replaced by safe lines
235+
byte[] data = new byte[location.Length];
236+
System.Runtime.InteropServices.Marshal.Copy(location.Bytes, data, 0, Convert.ToInt32(location.Length));
237+
var value = (int)data[0];
238+
// end safe lines
239+
240+
if (value < 0 || value > (byte)HeartRateMonitorLocation.Reserved) {
241+
Location = HeartRateMonitorLocation.Unknown;
242+
} else {
243+
Location = (HeartRateMonitorLocation)value;
244+
}
245+
246+
OnLocationUpdated ();
247+
}
248+
}
249+
}

0 commit comments

Comments
 (0)