background scanning for Ant+ devices

Has anyone tried doing background scanning for Ant+ devices (ie look for any Ant+ devices in range of any type?)

In the Ant+ pdf titled "ANT Channel Search", it seems you can configure a GenericChannel to do this search. I've set things up as follows but it never reports any devices. Am I just way off base on what I'm expecting from this? The one piece in the doc I don't understand is in the Channel Assignment it mentions setting the Extended assignment byte to 0x01.

I've tried various combinations for channel type and network, as well as the message period. I'm wondering if I'm just missing something obvious.

var chanAssign = new Ant.ChannelAssignment(
Ant.CHANNEL_TYPE_RX_NOT_TX, //CHANNEL_TYPE_RX_ONLY
Ant.NETWORK_PUBLIC);
chanAssign.setBackgroundScan(true);
GenericChannel.initialize(method(:onMessage), chanAssign);

// Set the configuration
deviceCfg = new Ant.DeviceConfig( {
:deviceNumber => 0,
:deviceType => 0,
:transmissionType => 0,
:messagePeriod => 0,
:radioFrequency => 57, //Ant+ Frequency
:searchTimeoutLowPriority => 10, //Timeout in 25s
:searchTimeoutHighPriority => 2, // Timeout in 25s
:searchThreshold => 0} ); //Pair to all transmitting sensors
GenericChannel.setDeviceConfig(deviceCfg);

  • The ANT public network is probably not what you're looking for. HRM, Power Meters, Fitness Equipment, etc all operate on the ANT+ network. This might work better for you:

    var chanAssign = new Ant.ChannelAssignment(
    Ant.CHANNEL_TYPE_RX_NOT_TX,
    Ant.NETWORK_PLUS);
    GenericChannel.initialize(method(:onMessage), chanAssign);


    I've not done scanning before but the channel assignment above works for fitness equipment and ANT+ HRM belts.
  • The ANT public network is probably not what you're looking for. HRM, Power Meters, Fitness Equipment, etc all operate on the ANT+ network. This might work better for you:

    var chanAssign = new Ant.ChannelAssignment(
    Ant.CHANNEL_TYPE_RX_NOT_TX,
    Ant.NETWORK_PLUS);
    GenericChannel.initialize(method(:onMessage), chanAssign);


    I've not done scanning before but the channel assignment above works for fitness equipment and ANT+ HRM belts.


    Thanks. Yea, I tried that first (as that's what I use elsewhere) but had read in the the doc that it should be zero. Neither seemed to make a difference.

    This is more just an exercise than a necessity as I'm just planning on using it for myself and can manually figure out what devices are around by using my Edge or Epix to get the ant+ ID's. Then hard coding them in, with a rebuild if necessary. I'm guessing there aren't a whole lot of people out there using GenericChannel and reading sensors outside of the built in interface. One of the main things I'm looking at is reading power on my 630 and adding trainer control support to both my 360 and Epix. Also often like comparing data, like power numbers between my kickr and SRM. Or between my Mio Optical HR sensor and my Garmin chest strap. So I'll actually open up multiple channels for the same kind of device.

    One interesting thing I've noticed with opening up HR channels, is that the Ant ID doesn't get set in the deviceConfig when it is opened with zero. So not sure how I'd even programatically get the id's.
  • If you are referring to the device ID or the number you might see when pairing with the watch in the sensor section you should be able to get that from the onMessage call back:

    function onMessage(msg)
    {
    Sys.println("device ID = " + msg.deviceNumber);
    }
  • pizza mini games

    If you are referring to the device ID or the number you might see when pairing with the watch in the sensor section you should be able to get that from the onMessage call back:

    function onMessage(msg)
    {
    Sys.println("device ID = " + msg.deviceNumber);
    }


    Thanks. This was helpful as I didn't know that field existed. I was always just calling GenericChannel.getDeviceConfig() and looking at the deviceNumber there. Which didn't seem to always be updated.

    Interesting that the msgDeviceNumber combines the ant+ id in the low 32 bits, and I suspect the manufacturer id as a byte in the upper 32 bits. So deviceConfig.deviceNumber == (msg.messageId & 0xffff).
  • Thanks. This was helpful as I didn't know that field existed. I was always just calling GenericChannel.getDeviceConfig() and looking at the deviceNumber there. Which didn't seem to always be updated.

    Interesting that the msgDeviceNumber combines the ant+ id in the low 32 bits, and I suspect the manufacturer id as a byte in the upper 32 bits. So deviceConfig.deviceNumber == (msg.messageId & 0xffff).


    The device number in the message payload is from the extended payload range and is defined as a unsigned short (0...65,535) or two bytes. There i no reference to message ID and the device configuration object is specific to Garmin and may not directly translate to the pages being sent back and forth so I would trust the device number in the message object. The manufacturer ID for heart rate monitors is in data page two and is 1 byte that will correspond with the ANT SDK manufacturer list. You'll need to get that from parsing the payload sent with the message.
  • Footpathquai

    I puttered around with this a little bit today.

    I modified the MoxySensor sample code to set the device number to 0 and to insert the line with the ChannelAssignment turning on the background scanning.

    chanAssign = new Ant.ChannelAssignment(Ant.CHANNEL_TYPE_RX_NOT_TX, Ant.NETWORK_PLUS);
    chanAssign.setBackgroundScan(true);
    GenericChannel.initialize(method(:onMessage), chanAssign);

    // Set the configuration
    deviceCfg = new Ant.DeviceConfig( {
    :deviceNumber => 0, // Wildcard our search
    :deviceType => 0,
    :transmissionType => 0,
    :messagePeriod => PERIOD,
    :radioFrequency => 57, // Ant+ Frequency
    :searchTimeoutLowPriority => 10, // Timeout in 25s
    :searchThreshold => 0} ); // Pair to all transmitting sensors
    GenericChannel.setDeviceConfig(deviceCfg);



    Then I put a println in onMessage

    function onMessage(msg) {
    // Parse the payload
    Sys.println("device number: " + msg.deviceNumber + " device type: " + `msg.deviceType);



    This allows the simulator to connect with either a Moxy sensor or a HR sensor, but once it connects with one, onMessage only gets called for messages from that device. It doesn't get called for all ANT messages when I had both broadcasting.

    I searched the documentation a bit, but I didn't find how this is supposed to work. I'm not sure what listener function (if any) should get called when background scanning is enabled.

    I'm not sure what enabling the background scanning actually does.
  • It looks like enabling background scanning isn't sticking so maybe this functionality isn't coded into CIQ.

    The following code always returns false from .isBackgroundScanEnabled()

    function initialize() {
    // Get the channel
    chanAssign = new Ant.ChannelAssignment(Ant.CHANNEL_TYPE_RX_NOT_TX, Ant.NETWORK_PLUS);
    chanAssign.setBackgroundScan(true);
    Sys.println("1BS Enbled " + chanAssign.isBackgroundScanEnabled());
    GenericChannel.initialize(method(:onMessage), chanAssign);
    chanAssign.setBackgroundScan(true);
    Sys.println("2BS Enbled " + chanAssign.isBackgroundScanEnabled());

    // Set the configuration
    deviceCfg = new Ant.DeviceConfig( {
    :deviceNumber => 0, // Wildcard our search
    :deviceType => 0,
    :transmissionType => 0,
    :messagePeriod => PERIOD,
    :radioFrequency => 57, // Ant+ Frequency
    :searchTimeoutLowPriority => 10, // Timeout in 25s
    :searchThreshold => 0} ); // Pair to all transmitting sensors
    GenericChannel.setDeviceConfig(deviceCfg);

    data = new MO2Data();
    searching = true;
    session = Recording.createSession({:name=>Ui.loadResource(Rez.Strings.sessionName)});
    chanAssign.setBackgroundScan(true);
    Sys.println("3BS Enbled " + chanAssign.isBackgroundScanEnabled());
    }
  • Thanks for investigating this a bit as well. I hadn't even thought to try testing if enabling background scanning was actually setting the flag. I'll probably try it later, but I assume the device it picks up is random between the two. If you kept repeating what you did, with setting the device type to zero, each time you could get either device. If that is the case, I guess you could just keep repeating that process in a loop and eventually get all devices present.

    I agree. It's not clear this functionality has ever even been used in CIQ.
  • Try changing the channel type in the ChannelAssignment object from Ant.CHANNEL_TYPE_RX_NOT_TX to Ant.CHANNEL_TYPE_RX_ONLY.

    If setBackgroundScan() is successful in changing the background scanning flag it should return true.

    var chanAssign = new Ant.ChannelAssignment(
    Ant.CHANNEL_TYPE_RX_ONLY, // Receive Only because we are not allowed to send data messages from a background scanning channel
    Ant.NETWORK_PLUS);

    // Should return true
    chanAssign.setBackgroundScan(true);

    GenericChannel.initialize(method(:onMessage), chanAssign);
  • OK, got this thing figured out. Basically, if you open a channel properly, you'll just keep seeing broadcast messages from any devices close by until you close the channel. You basically get a whole bunch of the payload pages for all the devices but I suspect you are actually losing quite a few pages. You can then look at the following fields in the onMessage(msg) call. Then use those values to present a list of available devices to the user. And from there you should have all the info you need to actually open that device.

    msg.deviceNumber
    msg.deviceType
    msg.transmissionType

    GenericChannel.getDeviceConfig() in the message handler does you no good as it just tells you zero's for the device #, type, and trans type.

    Thanks for the help on this. Good team effort. Now I can finally sleep!:)

    function initChannel()
    {
    var chanAssign = new Ant.ChannelAssignment(
    Ant.CHANNEL_TYPE_RX_ONLY,
    Ant.NETWORK_PLUS);
    chanAssign.setBackgroundScan(true);
    GenericChannel.initialize(method(:onMessage), chanAssign);

    // Set the configuration
    deviceCfg = new Ant.DeviceConfig( {
    :deviceNumber => 0,
    :deviceType => 0,
    :transmissionType => 0,
    :messagePeriod => 8192,
    :radioFrequency => 57, //Ant+ Frequency
    :searchTimeoutLowPriority => 10, //Timeout in 25s
    // :searchTimeoutHighPriority => 0, // Timeout in 25s
    :searchThreshold => 0} ); //Pair to all transmitting sensors

    GenericChannel.setDeviceConfig(deviceCfg);
    GenericChannel.open();
    }

    function onMessage(msg)
    {
    msg.deviceNumber ...
    msg.deviceType ...
    msg.transmissionType ...
    }