Send Data to an ANT+ Device

Former Member
Former Member
Hi

I have managed to cobble enough code together to talk to an ANT+ device not supported by the current SDK. I want to now be able to send data to this device.

I assume I need to use the GenericChannel.sendBroadcast(data) function ? If so, does anyone have an example of how to send 8 bytes using this function ? This is more a MonkeyC question I suppose.

Thanks!

J
  • Former Member
    Former Member over 8 years ago
    Hi

    It looks like this:

    ..
    const DEVICE_TYPE = 17;
    const PERIOD = 8192;
    ..

    function initialize() {
    // Get the channel

    System.println("Initializing..");
    chanAssign = new Ant.ChannelAssignment(Ant.CHANNEL_TYPE_RX_NOT_TX, Ant.NETWORK_PLUS);
    GenericChannel.initialize(method(:onMessage), chanAssign);

    // Set the configuration
    deviceCfg = new Ant.DeviceConfig( {
    :deviceNumber => 0, // Wildcard our search
    :deviceType => DEVICE_TYPE,
    :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 FECData();
    searching = true;
    }



    J
  • Former Member
    Former Member over 8 years ago
    Hi

    I am still debugging this without any luck.. If anyone has any tips or suggestions of what I should be trying, I am all ears.

    Thanks

    J
  • Hi Stiple,

    I'm not able to see what's not working with your code.

    I just put this together. It compiles and runs. It receives the cadence from the FEC and sends target power back. I don't know anything about FEC so this might not make any sense but I think this is close to what you are trying to accomplish. I used SimulANT to test it.

    This is the complete code for a functioning data field. Maybe this will help you find the problem.

    using Toybox.WatchUi as Ui;
    using Toybox.Application as App;
    using Toybox.System as Sys;
    using Toybox.Time as Time;
    using Toybox.Activity as Act;
    using Toybox.Graphics as Gfx;
    using Toybox.Ant as Ant;

    class FECField extends Ui.DataField {
    var mSensor;

    function initialize(sensor) {
    DataField.initialize();
    mSensor = sensor;
    }

    function compute(info) {
    }

    function onLayout(dc) {
    }

    function onUpdate(dc) {
    var bgColor = getBackgroundColor();
    var fgColor = Gfx.COLOR_WHITE;

    if (bgColor == Gfx.COLOR_WHITE) {
    fgColor = Gfx.COLOR_BLACK;
    }

    dc.setColor(fgColor, bgColor);
    dc.clear();

    dc.setColor(fgColor, Gfx.COLOR_TRANSPARENT);
    var locX = dc.getWidth()/2;
    var locY = dc.getHeight()/2;

    if (mSensor == null) {
    dc.drawText(locX, locY, Gfx.FONT_LARGE, "No Channel!", Gfx.TEXT_JUSTIFY_CENTER | Gfx.TEXT_JUSTIFY_VCENTER);
    } else if (true == mSensor.searching) {
    dc.drawText(locX, locY, Gfx.FONT_LARGE, "Searching...", Gfx.TEXT_JUSTIFY_CENTER | Gfx.TEXT_JUSTIFY_VCENTER);
    } else {
    dc.drawText(locX, locY, Gfx.FONT_LARGE, mSensor.FECdata.format("%.2f"), Gfx.TEXT_JUSTIFY_CENTER | Gfx.TEXT_JUSTIFY_VCENTER);
    }
    }
    }

    class FECDataField extends App.AppBase {
    var mSensor;

    function initialize() {
    AppBase.initialize();
    }

    // onStart is the primary start point for a Monkeybrains application
    function onStart(state) {
    try {
    //Create the sensor object and open it
    mSensor = new FECSensor();
    mSensor.open();
    } catch(e instanceof Ant.UnableToAcquireChannelException) {
    Sys.println(e.getErrorMessage());
    mSensor = null;
    }
    }

    function getInitialView() {
    return [new FECField(mSensor)];
    }

    function onStop(state) {
    return false;
    }
    }

    class FECSensor extends Ant.GenericChannel {

    hidden var chanAssign;

    var searching;
    var FECdata = 0;
    var deviceCfg;

    function initialize() {

    // Get the channel
    chanAssign = new Ant.ChannelAssignment(
    Ant.CHANNEL_TYPE_RX_NOT_TX,
    Ant.NETWORK_PLUS);
    GenericChannel.initialize(method(:onMessage), chanAssign);

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

    searching = true;
    }

    function open() {
    GenericChannel.open();
    searching = true;
    }

    function closeSensor() {
    GenericChannel.close();
    }

    function onMessage(msg) {
    var payload = msg.getPayload();

    if( Ant.MSG_ID_BROADCAST_DATA == msg.messageId ) {
    if( 0x19 == (payload[0].toNumber() & 0xFF) ) {
    if (searching) {
    searching = false;
    deviceCfg = GenericChannel.getDeviceConfig();
    }
    FECdata = payload[2];
    }
    } 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)) {
    // Channel closed, re-open
    open();
    } else if( Ant.MSG_CODE_EVENT_RX_FAIL_GO_TO_SEARCH == (payload[1] & 0xFF) ) {
    searching = true;
    }
    } else {
    //It is a channel response.
    }
    }
    var msgload = new [8];
    msgload[0] = 0x31; //Power Data Page
    msgload[1] = 0xFF;
    msgload[2] = 0xFF;
    msgload[3] = 0xFF;
    msgload[4] = 0xFF;
    msgload[5] = 0xFF;
    msgload[6] = 0x00;
    msgload[7] = 0x05;
    var message = new Ant.Message();
    message.setPayload(msgload);
    GenericChannel.sendAcknowledge(message);
    }
    }
  • Former Member
    Former Member over 8 years ago
    Problem solved !!!

    Your code actually helped me in that it made me realize that the bug was that I had inner classes. Your code did not. Once I adjusted all my brackets the code ran fan.

    Unbelievable.

    Thanks again for all the help everyone.

    Don't tell my wife, but solving a stupid bug like this is better then sex. ;-)

    J
  • the bug was that I had inner classes.


    I just filed a bug about this last night. Nested classes used to work just fine at one time, but appears to have broken.

    Travis
  • I'm now trying to send a command to my RTL510 device. From the bike radar profile, it is supposed to be looking at page 0x01 (device status) or 0x02 (device command) and should be pay attention on Payload[1] whereby bits 0-1 would be the one asking for shutdown or abort shutdown

    0 - abort shutdown

    1 - shutdown

    I tried the following code, inserted at the same location as example above.

    		var msgload = new[8];
    
    		msgload[0] = 0x02; // this is okay as it is
    		msgload[1] = 0x01;
    		msgload[2] = 0xFF;
    		msgload[3] = 0xFF;
    		msgload[4] = 0xFF;
    		msgload[5] = 0xFF;
    		msgload[6] = 0xFF;
    		msgload[7] = 0xFF;
    		
    		var message = new Ant.Message();
    		Sys.println("POP");
    		message.setPayload(msgload);
    		Ant.GenericChannel.sendAcknowledge(message);
    //		Ant.GenericChannel.sendBroadcast(message);		       	

    and all I get back from the device are:

    TOD:18:09 :[1, 2, 255, 255, 255, 255, 255, 255] msg:78
    POP
    TOD:18:09 :[1, 5, 0, 0, 0, 0, 0, 0] msg:64

    The light doesn't actually shut down (even after waiting for > 10 secs)

  • I don't understand the data that you are getting back from the device.  The POP looks like it's the console output from your Sys.println().

    The first line looks like it might be a Device Status page 1 from the Bike Radar device but I don't see what printed it.  The Byte 0 is 0x01 so that indicates a Device Status page.  However Byte 1 is a 0x02 which is not correct according to table 6-7 in the standard.

    The third line also looks like a Device Status page 1 but Bytes 1-7 look wrong.  It's not clear to me what the msg:78 and msg:64 meanat the ends of lines 1 and 3.

    I'd recommend using Simulant+ to debug this if you aren't already.  That lets you see the data pages going back and forth very easily.  The code you posted looks correct to me.  This will make the watch send a data page 2 to the bike radar device after the watch receives the next message from the bike radar device.  Are you sure your app is receiving messages properly?

  • sorry about that. the POP is just for me to know that codes are being executed (like a flow)

    The TOD output is another println to see what is coming back from the radar.

       function onMessage(msg) {
            // Parse the payload
            var payload = msg.getPayload();       
    //       if ( payload[0] != 80 && payload[0] != 81 && payload[0] != 82 ) {  
    		if ( payload[0] != 48) {
    			Sys.println("TOD:" + TimeOfDay() + " :" + payload + " msg:" + msg.messageId);
    		}	
     

    msg: 64 and 78 are just returned from msg. According to the developer docs - 

    78 = MSG_ID_BROADCAST_DATA = 0x4E

    64 = MSG_ID_CHANNEL_RESPONSE_EVENT = 0x40

    I can't use simulANT+ as I do not have a windows box :-( I am working on this on a Mac. Is there any ability to use it on a Mac or what software is available for usage on a Mac?

    "are you sure my app is receiving message properly" -

    I should think so as I am able to get data pages 48 and 82 which are the vehicles Tracked Page and the Battery status pages and all of them works (since Im just receiving data and not sending any payload)

  • I don't know if this will help you, but here's a screen shot fro Simulant simulating a Moxy sensor.  On a different PC, I'm running eclipse simulating a Garmin watch running the Moxy Data Field code with the acknowledge message code in it that's just like what you are showing.  This shows that the data field code is sending the acknowledge message to the sensor.

  • I finally managed to locate a windows computer which was not my 10yr old laptop running windows XP which is not supported by simulant+

    anyways - i tried simulating a radar display and connect it to the radar. Seems to work well, I can see the threats / the location / the speed etc. Then I tried to send a shutdown command like the below, but the sensor keep not turning off (aborted shutdown)

    571228 : Sending CommandPage
     Command: Shutdown
    571244 : ... sent page 2
    571353 : Tx success
    571603 :    Sensor has aborted shutdown.
    571852 :    Sensor has aborted shutdown.
    572102 :    Sensor has aborted shutdown.
    572352 :    Sensor has aborted shutdown.
    572601 :    Sensor has aborted shutdown.

    This is the output it gives, 

    571104 : Rx: [30][00][00][00][00][00][00][00]
    571228 : Rx: [30][00][00][00][00][00][00][00]
    571244 : Tx (Ack): [02][FD][FF][FF][FF][FF][FF][FF]
    571353 : Rx: [30][00][00][00][00][00][00][00]
    571369 : Transfer Tx completed
    571478 : Rx: [30][00][00][00][00][00][00][00]
    571603 : Rx: [01][02][FF][FF][FF][FF][FF][FF]

    Weird thing is that when I connect to the radar using my watch, it _will_ turn off when I request it to turn off. What gives I have no clue.