1) In the onMessage function, it tries to use a variable from a class before the class is called. Strangely, this code worked in early versions of the SDK and then stopped working later. I fixed this by declaring a static constant in the MO2Sensor Class that is available when it's needed.
2) In the onMessage function, it was calling getPayload 2 times when it only needed to call it once. This caused a large blip in memory usage that crashed my app with an out-of-memory error in the simulator. This change is shown in the code below.
3) Also in the onMessage function, I removed the Ui.requestUpdate() when new data is received. Instead, I created a timer that requested an update once per second all of the time. This was needed to have clock displays and data from native ANT sensors like heart rate or power to get updated in case the Generic ANT channel wasn't paired or was updated less frequently than once per second. This is probably an application dependent choice but it my opinion, it was more pleasant looking to have all of the data fields I was displaying updating in unison once per second.
class MO2Sensor extends Ant.GenericChannel
{
const DEVICE_TYPE = 31;
const PERIOD = 8192;
static const MODP_PAGE_NUMBER = 1;
...
...
function onMessage(msg)
{
// Parse the payload
var payload = msg.getPayload();
if( Ant.MSG_ID_BROADCAST_DATA == msg.messageId )
{
if( MODP_PAGE_NUMBER == (payload[0].toNumber() & 0xFF) ) //original code was MuscleOxygenDataPage.PAGE_NUMBER
{
// 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 MuscleOxygenDataPage();
dp.parse(payload, data); // original code was: dp.parse(msg.getPayload(), data);
// Check if the data has changed and we need to update the ui
if(pastEventCount != data.eventCount)
{
// Removed the line Ui.requestUpdate();
pastEventCount = data.eventCount;
}
4) The SetTime function needed to accommodate the difference between the Garmin Epoch and the Unix Epoch and it needed some changes to the payload creation. The original function is shown below followed by what I changed it to. I don't know if the payload setup method I used is the most efficient, but it seems to function fine. The 631065600 is the number of seconds between the Garmin Epoch and the Unix Epoch. moment.value() returns seconds since the Unix epoch and the Muscle Oxygen profile requires the data to be sent relative to the Garmin epoch.
Just to clarify from some other posts I've seen on the epoch topic... The Garmin epoch appears to be Dec 31, 1989 at 0:00:00. This is the morning of the 31st so it includes 1 day in 1989. The Unix epoch is Jan 1, 1970 at 0:00:00.
function setTime()
{
if( !searching
&& ( data.utcTimeSet ) )
{
//Create and populat the data payload
var payload = new [8];
payload[0] = 0x10; //Command data page
payload[1] = 0x00; //Set time command
payload[2] = 0xFF; //Reserved
payload[3] = 0; //Signed 2's complement value indicating local time offset in 15m intervals
//Set the current time
var moment = Time.now();
for(var i = 0; i < 4; i++)
{
payload[i + 4] = ((moment.value() >> i) & 0x000000FF);
}
//Form and send the message
var message = new Ant.Message();
message.setPayload(payload);
GenericChannel.sendAcknowledge(message);
}
}
function setTime()
{
if( !searching
&& ( data.utcTimeSet ) )
{
//Create and populat the data payload
var payload = new [8];
payload[0] = 0x10; //Command data page
payload[1] = 0x00; //Set time command
payload[2] = 0xFF; //Reserved
payload[3] = 0; //Signed 2's complement value indicating local time offset in 15m intervals
//Set the current time
var moment = Time.now();
var secsGarEpoch = moment.value() - 631065600;
payload[4] = secsGarEpoch % 256;
payload[5] = (secsGarEpoch / 256) % 256;
payload[6] = (secsGarEpoch / 65536) % 256;
payload[7] = (secsGarEpoch / 16777216) % 256;
//Form and send the message
var message = new Ant.Message();
message.setPayload(payload);
GenericChannel.sendAcknowledge(message);
}
}