Reading HR data from HRM via ANT+

Hi Guys,

This is a typical case of "it used to work but now it doesn't" and I cannot figure out why. I have modified the TemeAppView example found in the Wearable Programming for the Active Lifes PDF so that it reads the heart rate from my HRM-tri strap. So I created this extremely simple application and I used to be able to get the heart rate (the application was not finished just the first stages trying to figure out ANT programming). However, for no reason that I can explain the onMessageReceived listener is no longer called so the application is not working any more. Can anybody help me or point me to the correct direction? For some reason this code never gets into onMessageReceived().


using Toybox.Ant as Ant;
using Toybox.System as System;
using Toybox.Time as Time;

class TempeSensor extends Ant.GenericChannel
{
const DEVICE_TYPE = 120; // HRM is 120, temp sensor is 25; // The ANT+ device type
const PERIOD = 8070; // 65535; // How often we expect new data
hidden var chanAssign; // The channel assigned by the radio
var data; // Stores the data received from the
// sensor

var searching; // Whether we're currently searching for the sensor

var deviceCfg; // Device configuration details

// This flag indicates we've obtained enough
// data to read the temperature
var tempDataAvailable = false;

class TempeData
{
var currentTemp;
function initialize()
{
currentTemp = 35;
}
}

class TempeDataPage
{
static const PAGE_NUMBER = 1;

function parse(payload, data)
{
// The payload (what we received from the sensor) has
// a few data points in it. We're just interested in
// the current temperature.
System.println("payload");
data.currentTemp = parseCurrentTemp(payload);
} // parse

hidden function parseCurrentTemp(payload)
{
System.println("parseCurrentTemp");

var currentTemp = payload[7];
System.println(currentTemp);
return currentTemp;
}
} // end class TempeDataPage

function initialize()
{

// Get the channel
chanAssign = new Ant.ChannelAssignment(CHANNEL_TYPE_RX_ONLY,Ant.NETWORK_PLUS);

var x = GenericChannel.initialize(method(:onMessageReceived), chanAssign);

// Set the configuration
deviceCfg = new Ant.DeviceConfig( {
:deviceNumber => 0, // Wildcard (any matching device)
:deviceType => DEVICE_TYPE,
:transmissionType => 0,
:messagePeriod => PERIOD,
:radioFrequency => 57, // ANT+ Frequency
:searchTimeoutLowPriority => 10, // Timeout in 25s
:searchTimeoutHighPriority => 2, // Timeout in 5s
:searchThreshold => 0//,
//:networkKey64Bit => ["0xB9","0xA5","0x21","0xFB","0xBD","0x72","0xC3","0x45"],
} ); // Pair w/all sensors

GenericChannel.setDeviceConfig(deviceCfg);

data = new TempeData();
searching = true;
System.println("init");
}

function open()
{
// Open the channel
GenericChannel.open();
data = new TempeData();
searching = true;
System.println("open");
}

function closeSensor()
{
System.println("close");
GenericChannel.close();
}

function onMessageReceived(msg)
{
// see: forums.garmin.com/.../150229-background-scanning-for-ant-devices
System.println("device number: " + msg.deviceNumber + " device type: " + msg.deviceType);

// Parse the payload
var payload = msg.getPayload();

if( Ant.MSG_ID_BROADCAST_DATA == msg.messageId )
{
System.println(payload);
System.println(msg.messageID);

var dp = new TempeDataPage();
dp.parse(msg.getPayload(),data);
tempDataAvailable = true;

if( TempeDataPage.PAGE_NUMBER == (payload[0].toNumber() & 0xFF) )
{
// Were we searching?
if(searching)
{
searching = false;
// Update our device configuration primarily to see the
// device number of the sensor we paired to
deviceCfg = GenericChannel.getDeviceConfig();
}
//var dp = new TempeDataPage();
//dp.parse(msg.getPayload(), data);
//tempDataAvailable = true;
}
} // end broadcast data
else if( Ant.MSG_ID_CHANNEL_RESPONSE_EVENT == msg.messageId )
{
if( Ant.MSG_ID_RF_EVENT == (payload[0] & 0xFF) )
{
if( Ant.MSG_CODE_EVENT_CHANNEL_CLOSED == (payload[1] & 0xFF) )
{
System.println("closed, so try to open");
open();
}
else if( Ant.MSG_CODE_EVENT_RX_FAIL_GO_TO_SEARCH == (payload[1] & 0xFF) )
{
System.println("Searching");
searching = true;
}
}
else
{
//It is a channel response.
}
} // end channel response event
} // end on message
}

  • Couple questions:
    1. Could you try uncommenting where you set the network key (networkKey64Bit) in the DeviceConfig?
    This is the likely culprit for your issue.
    You also will want to specify the 128bit network key if you plan on porting this app to other devices. Some devices have radios that use the 64bit key and other use the 128 bit key. It's a good idea to specify both for compatibility.
    To get the 128 bit network key, create an account at thisisant.com.

    2. Is your 935 already paired with the HRM-Tri?
    If so, the 935 could connect to the HRM with it's built in implementation of the ANT+ HR Profile. If the 935 already has an ANT channel tracking the HRM, this would prevent your ANT channel in your app from being able to connect to the HRM.

    3. Is 'onMessageReceived' not being called at all?
    As a minimum, it should be called after you open the channel. You should be getting channel responses coming back (MSG_ID_CHANNEL_RESPONSE_EVENT ) as the GenericChannel is configuring and opening the channel.

    4. Is GenericChannel.open() returning TRUE?
    TRUE indicates the channel was opened successfully.
  • Thank you for the reply. Here are my comments:
    1. I have tried with uncommenting the network key and there is no change. Actually when the program worked I didn't have that line in at all. My understanding is that I don't need the network key if I specify Ant.NETWORK_PLUS anyway. I am currently not interested in making this code to work with other devices - I am trying to learn the basics however, it is good to know and keep in mind.
    2. Yes my 935 is already paired. I have it actually switched off right not to test the code and this make no difference. My understanding is that the Ant+ devices i.e. my HRM-tri can send data to multiple devices at the same time.
    3. The onMessageReceived is not called at all - and this is the part that used to work but for some bizarre reason it does not work any more. As you say it should be called once I open the channel.
    4. Yes GenericChannel.open() returns true - i have just put a breakpoint over there. :-\

    I'm not sure what else to check!
  • You might want to recheck the #2 issue. If the sensor is paired in the native part of the device, I don't think it will connect as a Generic ANT device (even if its not currently connected as a native device). You need to remove it from the list of paired sensors on the native part of the devices. Go in the menu to Sensors->Remove Device to remove it.

    I don't think this would cause the onMessageReceived to not be called at all though.

    One thing that did catch my eye is your ANT channel assignment. Mine looks like below. I'm not sure if this is relevant.

    var channelAssignment = new Ant.ChannelAssignment(
    Ant.CHANNEL_TYPE_RX_NOT_TX,
    Ant.NETWORK_PLUS);
  • Thank you MoxyRoger, I'll check you suggestions.