-
Notifications
You must be signed in to change notification settings - Fork 158
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Generic ANT Channel Data Field and Barrel
- Loading branch information
Ben Pryhoda
committed
Oct 14, 2020
1 parent
8f7f6d0
commit a72b6fc
Showing
29 changed files
with
1,065 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<projectDescription> | ||
<name>GenericChannelHeartRateBarrel</name> | ||
<comment></comment> | ||
<projects> | ||
</projects> | ||
<buildSpec> | ||
<buildCommand> | ||
<name>connectiq.barrelBuilder</name> | ||
<arguments> | ||
</arguments> | ||
</buildCommand> | ||
</buildSpec> | ||
<natures> | ||
<nature>connectiq.barrelProjectNature</nature> | ||
</natures> | ||
</projectDescription> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
eclipse.preferences.version=1 | ||
project_manifest=manifest.xml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# GenericChannelHeartRateBarrel | ||
This barrel demonstrates how to use the Connect IQ Generic ANT Channel module to connect to an ANT+ Heart Rate monitor. This project can be adapted to work with any ANT or ANT+ device. See the [Generic ANT+ Heart Rate Data Field](https://github.com/garmin/connectiq-apps/tree/master/datafields/GenericAntPlusHeartRateField) for an example project that uses this barrel. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<!-- This is a generated file. It is highly recommended that you DO NOT edit this file. --><iq:manifest xmlns:iq="http://www.garmin.com/xml/connectiq" version="3"> | ||
<iq:barrel id="445b1620-8d6b-4305-b40e-b7f9b56363ec" module="GenericChannelHeartRateBarrel" version="0.0.1"> | ||
<iq:products/> | ||
<iq:permissions> | ||
<iq:uses-permission id="Ant"/> | ||
</iq:permissions> | ||
<iq:languages/> | ||
<iq:barrels/> | ||
<iq:annotations/> | ||
</iq:barrel> | ||
</iq:manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
project.manifest = manifest.xml | ||
|
208 changes: 208 additions & 0 deletions
208
barrels/GenericChannelHeartRateBarrel/source/AntPlusHeartRateSensor.mc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
using Toybox.Ant; | ||
|
||
module GenericChannelHeartRateBarrel { | ||
|
||
class AntPlusHeartRateSensor extends Toybox.Ant.GenericChannel { | ||
// Channel configuration | ||
private const CHANNEL_PERIOD = 8070; // ANT+ HR Channel Period | ||
private const DEVICE_TYPE = 120; // ANT+ HR Device Type | ||
private const RADIO_FREQUENCY = 57; // ANT+ Radio Frequency | ||
private const SEARCH_TIMEOUT = 1; // 2.5 second search timeout | ||
private const DISABLED = 0; | ||
|
||
// Message indexes | ||
private const MESSAGE_ID_INDEX = 0; | ||
private const MESSAGE_CODE_INDEX = 1; | ||
|
||
// Proximity bin defines | ||
private const WILDCARD_PAIRING = 0; | ||
private const CLOSEST_SEARCH_BIN = 1; | ||
private const FARTHEST_SEARCH_BIN = 10; | ||
private const PROXIMITY_DISABLED = 0; | ||
|
||
// Variables | ||
hidden var chanAssign; | ||
hidden var deviceCfg; | ||
hidden var deviceNumber; | ||
hidden var transmissionType; | ||
hidden var searchThreshold; | ||
hidden var hrSensorDelegate; | ||
hidden var onUpdateCallback; | ||
hidden var onPairedCallback; | ||
hidden var isClosed; // Tracks when the app wants us to stay closed | ||
hidden var isPaired; // Paired is an event we only fire once | ||
|
||
var data; | ||
|
||
// Initializes AntPlusHeartRateSensor, configures and opens channel | ||
// @param extendedDeviceNumber, a 20-bit ANT+ defined integer used for identification | ||
// @param isProximityPairing, true enables pairing based on signal strength from strongest to weakest | ||
function initialize( extendedDeviceNumber, isProximityPairing ) { | ||
|
||
if (extendedDeviceNumber == WILDCARD_PAIRING) { | ||
deviceNumber = WILDCARD_PAIRING; | ||
transmissionType = WILDCARD_PAIRING; | ||
} else { | ||
parseExtendedDeviceNumber( extendedDeviceNumber ); | ||
} | ||
|
||
if ( isProximityPairing ) { | ||
searchThreshold = CLOSEST_SEARCH_BIN; | ||
} else { | ||
searchThreshold = WILDCARD_PAIRING; | ||
} | ||
|
||
data = new LegacyHeartData(); | ||
|
||
// Create channel assignment | ||
chanAssign = new Toybox.Ant.ChannelAssignment( | ||
Toybox.Ant.CHANNEL_TYPE_RX_NOT_TX, | ||
Toybox.Ant.NETWORK_PLUS); | ||
|
||
// Initialize the channel through the superclass | ||
GenericChannel.initialize( method(:onMessage), chanAssign ); | ||
|
||
// Set the configuration | ||
deviceCfg = new Toybox.Ant.DeviceConfig( { | ||
:deviceNumber => deviceNumber, | ||
:deviceType => DEVICE_TYPE, | ||
:transmissionType => transmissionType, | ||
:messagePeriod => CHANNEL_PERIOD, | ||
:radioFrequency => RADIO_FREQUENCY, | ||
:searchTimeoutLowPriority => SEARCH_TIMEOUT, | ||
:searchTimeoutHighPriority => DISABLED, | ||
:searchThreshold => searchThreshold} ); | ||
GenericChannel.setDeviceConfig( deviceCfg ); | ||
|
||
// The channel was initialized into a CLOSED state | ||
isClosed = true; | ||
|
||
// The channel has not paired with a device yet | ||
isPaired = false; | ||
|
||
hrSensorDelegate = null; | ||
onUpdateCallback = null; | ||
} | ||
|
||
// Opens the generic channel | ||
function open() { | ||
isClosed = false; // Externally opening the channel means it is no longer CLOSED | ||
deviceCfg.searchThreshold = searchThreshold; | ||
GenericChannel.setDeviceConfig( deviceCfg ); | ||
GenericChannel.open(); | ||
} | ||
|
||
// Closes the generic channel | ||
function close() { | ||
isClosed = true; // Externally closing the channel means it will stay CLOSED | ||
GenericChannel.close(); | ||
} | ||
|
||
// Release the generic channel | ||
// Once the channel is released it cannot be re-opened or closed again | ||
function release() { | ||
GenericChannel.release(); | ||
} | ||
|
||
// Sets the delegate handler for asynchronous sensor events | ||
// An application can only have 1 registered delegate. Subsequent calls to this function will override the current delegate. | ||
// Setting this to null will remove any registered delegate. | ||
function setDelegate( hrSensorDelegate ) { | ||
hrSensorDelegate = hrSensorDelegate; | ||
|
||
if ( hrSensorDelegate != null ) { | ||
onUpdateCallback = hrSensorDelegate.method(:onHeartRateSensorUpdate); | ||
onPairedCallback = hrSensorDelegate.method(:onHeartRateSensorPaired); | ||
} else { | ||
onUpdateCallback = null; | ||
onPairedCallback = null; | ||
} | ||
} | ||
|
||
// Returns the current extended device number. | ||
// This will change to the sensor's value once paired. | ||
function getExtendedDeviceNumber () { | ||
return (deviceNumber | ((transmissionType & 0xF0) << 12)); | ||
} | ||
|
||
// On new ANT Message, parses the message | ||
// @param msg, a Toybox.Ant.Message object | ||
function onMessage( msg ) { | ||
// Parse the payload | ||
var payload = msg.getPayload(); | ||
|
||
if ( Toybox.Ant.MSG_ID_CHANNEL_RESPONSE_EVENT == msg.messageId ) { | ||
if ( Toybox.Ant.MSG_ID_RF_EVENT == payload[MESSAGE_ID_INDEX] ) { | ||
// React to changes in the ANT channel state | ||
switch(payload[MESSAGE_CODE_INDEX]) { | ||
|
||
// Drop to search occurs after 2s elapse or 8 RX_FAIL events, whichever comes first | ||
case Toybox.Ant.MSG_CODE_EVENT_RX_FAIL_GO_TO_SEARCH: | ||
// Reset HR data after missing over 2s of messages | ||
data.reset(); | ||
if ( onUpdateCallback != null ) { | ||
onUpdateCallback.invoke(data.computedHeartRate); | ||
} | ||
break; | ||
|
||
// Search timeout occurs after SEARCH_TIMEOUT duration passes without pairing | ||
case Toybox.Ant.MSG_CODE_EVENT_RX_SEARCH_TIMEOUT: | ||
// Only change the search threshold if proximity pairing is enabled | ||
if ( searchThreshold != PROXIMITY_DISABLED ) { | ||
// Expand search radius after each channel close event due to search timeout | ||
if ( searchThreshold < FARTHEST_SEARCH_BIN ) { | ||
searchThreshold++; | ||
} else { | ||
// Pair to any signal strength if we've searched every bin | ||
searchThreshold = WILDCARD_PAIRING; | ||
} | ||
|
||
} | ||
break; | ||
|
||
// Close event occurs after a search timeout or if it was requested | ||
case Toybox.Ant.MSG_CODE_EVENT_CHANNEL_CLOSED: | ||
// Reset HR data after the channel closes | ||
data.reset(); | ||
|
||
if ( onUpdateCallback != null ) { | ||
onUpdateCallback.invoke(data.computedHeartRate); | ||
} | ||
|
||
// If ANT closed the channel, re-open it to continue pairing | ||
if(!isClosed) { | ||
open(); | ||
} | ||
break; | ||
} | ||
} | ||
|
||
} else if ( Toybox.Ant.MSG_ID_BROADCAST_DATA == msg.messageId ) { | ||
data.parse( payload ); // Parse payload into data | ||
|
||
if ( onUpdateCallback != null ) { | ||
onUpdateCallback.invoke(data.computedHeartRate); // Pass data to callback | ||
} | ||
|
||
if ( !isPaired ) { | ||
isPaired = true; // Only fire paired event once | ||
|
||
deviceNumber = msg.deviceNumber; | ||
transmissionType = msg.transmissionType; | ||
|
||
if ( onPairedCallback != null ) { | ||
onPairedCallback.invoke(getExtendedDeviceNumber()); | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Parses the 20-bit extended device number into its two separate components | ||
// @param extendedDeviceNumber, a 20-bit ANT+ defined integer used for identification | ||
private function parseExtendedDeviceNumber( extendedDeviceNumber ) { | ||
// Parse the extended device number for the upper nibble | ||
transmissionType = ((extendedDeviceNumber >> 12) & 0xF0) | 0x01; | ||
deviceNumber = extendedDeviceNumber & 0xFFFF; | ||
} | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
barrels/GenericChannelHeartRateBarrel/source/HeartRateSensorDelegate.mc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module GenericChannelHeartRateBarrel { | ||
|
||
// Delegate Class for ANT+ Heart Rate Sensor Callbacks. | ||
class HeartRateSensorDelegate { | ||
|
||
// If the sensor is being tracked this will be called with the latest data. | ||
function onHeartRateSensorUpdate( computedHeartRate ) { | ||
} | ||
|
||
// If the extended device number was wildcarded at initialization this will be called with the paired value. | ||
function onHeartRateSensorPaired( extendedDeviceNumber ) { | ||
} | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
barrels/GenericChannelHeartRateBarrel/source/LegacyHeartData.mc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
module GenericChannelHeartRateBarrel { | ||
|
||
// Represents the data available from any ANT+ Heart Rate strap | ||
class LegacyHeartData { | ||
private static const COMPUTED_HR_INDEX = 7; | ||
private static const INVALID_HR = 0; | ||
|
||
var computedHeartRate; | ||
|
||
function initialize() { | ||
computedHeartRate = INVALID_HR; | ||
} | ||
|
||
// Parses the computed heart rate value from the sensor | ||
// @param payload, application data from an ANT broadcast message | ||
function parse( payload ) { | ||
computedHeartRate = payload[COMPUTED_HR_INDEX]; | ||
} | ||
|
||
// Sets the computed heart rate value to INVALID | ||
function reset() { | ||
computedHeartRate = INVALID_HR; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<projectDescription> | ||
<name>GenericAntPlusHeartRateField</name> | ||
<comment></comment> | ||
<projects> | ||
</projects> | ||
<buildSpec> | ||
<buildCommand> | ||
<name>connectiq.builder</name> | ||
<arguments> | ||
</arguments> | ||
</buildCommand> | ||
</buildSpec> | ||
<natures> | ||
<nature>connectiq.projectNature</nature> | ||
</natures> | ||
</projectDescription> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# GenericAntPlusHeartRateField | ||
A Connect IQ Simple Data Field that uses the [Generic Channel Heart Rate Barrel](https://github.com/garmin/connectiq-apps/tree/master/barrels/GenericChannelHeartRateBarrel) to connect to an ANT+ Heart Rate Monitor. This data field demonstrates using barrels, app settings, on-device app settings, FIT Developer Fields, and unit tests. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Do not hand edit this file. To make changes right click | ||
# on the project and select "Configure Monkey Barrels". | ||
|
||
GenericChannelHeartRateBarrel = [../../barrels/GenericChannelHeartRateBarrel/monkey.jungle] | ||
base.barrelPath = $(base.barrelPath);$(GenericChannelHeartRateBarrel) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<!-- This is a generated file. It is highly recommended that you DO NOT edit this file. --><iq:manifest xmlns:iq="http://www.garmin.com/xml/connectiq" version="3"> | ||
<iq:application entry="GenericAntPlusHeartRateFieldApp" id="a658988723e947919e496ced36a6fbc8" launcherIcon="@Drawables.LauncherIcon" minSdkVersion="1.4.0" name="@Strings.AppName" type="datafield" version="0.0.2"> | ||
<iq:products> | ||
<iq:product id="edge1030plus"/> | ||
<iq:product id="fenix6"/> | ||
<iq:product id="fenix6pro"/> | ||
<iq:product id="fr945"/> | ||
</iq:products> | ||
<iq:permissions> | ||
<iq:uses-permission id="Ant"/> | ||
<iq:uses-permission id="FitContributor"/> | ||
</iq:permissions> | ||
<iq:languages> | ||
<iq:language>eng</iq:language> | ||
</iq:languages> | ||
<iq:barrels> | ||
<iq:depends name="GenericChannelHeartRateBarrel" version="0.0.1"/> | ||
</iq:barrels> | ||
</iq:application> | ||
</iq:manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
project.manifest = manifest.xml |
3 changes: 3 additions & 0 deletions
3
datafields/GenericAntPlusHeartRateField/resources/drawables/drawables.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<drawables> | ||
<bitmap id="LauncherIcon" filename="launcher_icon.png" /> | ||
</drawables> |
Binary file added
BIN
+1.44 KB
datafields/GenericAntPlusHeartRateField/resources/drawables/launcher_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.