Acknowledged

Edge 530 Data Field Generic ANT Channel Freezes after Sleep

On the Edge 530, the Generic ANT channel freezes after waking from sleep.  To view the problem:

  • Set up a Data Field with a generic ANT Channel
  • Insert the Data Field into a Ride
  • Go into a ride with the Data Field showing but don't start the ride
  • Wait 5 minutes for the Edge to go to sleep.
  • The Generic ANT channel will not work when the Edge is woke up.

This video shows the details.

https://youtu.be/00gkoML7SnA

A work around requires first detecting that it happened and then programmatically resetting the ANT channel so it works again.  Detection is not simple because the data field doesn't get any indication when the Edge goes to sleep or wakes up.  It's also difficult to distinguish between a frozen ANT channel and a channel that is just searching for  a sensor.  I have not come up with a sequence to programmatically reset the channel yet, but I will keep trying.

This seems like it might be a rare occurrence, but our customers run into quite frequently and it appears to them like it's a random bug.  They assume the problem is on the Moxy side and they try powering it off and hard resetting it and trying to change the sensor settings.

I have firmware 9.73 on the Edge 530.

Please let me know if I can provide more information about the problem.

Roger

  • Dear Roger,

    Thank you so much, you saved me Slight smile

  • I added in a freeze detection algorithm as a work around.

    1) I reduced the low priority search timeout to 5 seconds (it was 25 seconds).  This causes the channel to close and reopen if the channel is working but just not connected to a sensor yet.  This close and reopen causes calls to onMessage to occur so the freeze detector doesn't get tripped by simply not getting connected to a sensor.

    var deviceConfig = new Ant.DeviceConfig({
                :deviceNumber              => deviceNumber,
                :deviceType                => 31,
                :transmissionType          => 0,
                :messagePeriod             => 8192,
                :radioFrequency            => 57,
                :searchTimeoutLowPriority  => 2,  // 2.5 seconds per unit
                :searchTimeoutHighPriority => 0,
                :searchThreshold           => 0
            });

    2) I added a msg_timer variable inside of onMessage that keeps track of the last time.now() that onMessage was called.

       function onMessage(msg as Message) as Void {
            var payload = msg.getPayload();
    		msg_timer = Time.now().value(); // Freeze Detector
            if (Ant.MSG_ID_CHANNEL_RESPONSE_EVENT == msg.messageId) {
    
                if (Ant.MSG_ID_RF_EVENT == payload[0]) {...

    3) Then I added a function inside of compute() that detects if the ANT channel is frozen (i.e. onMessage is not getting called).  freeze_count needs to be > 5 to determine that it is frozen.

    	function compute(info) {									// Called Once Per Second
    		if (mSensor != null) {
    			if (Time.now().value() - mSensor.msg_timer >= 2) {  // Not getting new messagaes
    				freeze_count = freeze_count+1;
    				mSensor.reset();        // Stops displaying data
    			}
    			else {
    				freeze_count = 0;
    			}
    			if (!mSensorConnected) {
    				if (mSensor._eventCount != null) {
    					mFitContributor = new MO2FitContributor(self, mSensor);
    					mFitContributor.setDeviceInfo(mSensor.getDeviceInfo());
    					mSensorConnected = true;
    				}
    			}
    			if (mSensorConnected) {
    				mFitContributor.compute(mSensor);
    				if (mSensor.updateDeviceInfo == true) {
    					mFitContributor.setDeviceInfo(mSensor.getDeviceInfo());
    				}
    			}
    		}
    		else {
    			freeze_count = freeze_count+1;
    		}
    		if (freeze_count > 5) {									//  Want this to take longer than the search timeout
    			App.getApp().restartSensor();   // destroys the ANT channel and recreates it
            	freeze_count = 0;
            }
        }
    

    4) The restartSensor() function destroys the ANT channel and recreates it.

    function restartSensor() {
    
            if((mSensor != null) && (mSyncedDeviceNumber == 0))
            {//update if it hasn't previously been set.
    
            mSyncedDeviceNumber = mSensor.syncedDeviceNumber; //Grab old device number and use if it has been synced
            }
          mSensor.release();
          mSensor = null;
          acquireSensor();
          mToggle = getProperty("DispToggle");
          mView.setSensor(mSensor, mToggle);
        }    		

  • Hi Roger,

    Have you solved this problem? I am facing the same now...

  • Hi Roger,

    as for the detection can you

    - add log in close()

    - add log of different ANT messages in onMessage()

    and can you also post your onMessage (at least the part that looks for all the other types of messages that are not containing data, but can be important in detecting disconnects, etc

    When I debugged my DF I had something like this:

    function logPayload(msg as Message, payload as Array<Number>, txt as String) as Void {
        if (LOG && LOG2 && LOG_ANT) {
            var hex = payload2hex(payload);
            log2("ANT: " + msg.timestamp + ": 0x" + (msg.messageId as Number).format("%02X") + hex + ", r:" + msg.rssi + ", t:" + msg.transmissionType + ", l:" + msg.length + "; " + txt);
        }
    }
    
    function payload2hex(payload as Array<Number>) as String {
        var hex = "[";
        for (var i = 0; i < payload.size(); i++) {
            if (i > 0) {
                hex += ",";
            }
            hex += (payload[i] & 0xFF).format("%02X");
        }
        hex += "]";
        return hex;
    }
    

        public function onMessage(msg as Message) as Void {
            // Parse the payload
            var payload = msg.getPayload() as Array<Number>;
    
            if (Ant.MSG_ID_BROADCAST_DATA == msg.messageId
                || Ant.MSG_ID_ACKNOWLEDGED_DATA == msg.messageId
                // || Ant.BURST_DATA == msg.messageId
                ) {
                paired(msg);
                data.parse(msg, payload);
            } else if (Ant.MSG_ID_CHANNEL_ID == msg.messageId) {
                if (LOG_ANT) { logPayload(msg, payload, "CHANNEL_ID " + ", txType: " + msg.transmissionType); }
                paired(msg);
            } else if (Ant.MSG_ID_CHANNEL_RESPONSE_EVENT == msg.messageId) {
                var msgId = payload[0] & 0xFF;
                if (Ant.MSG_ID_RF_EVENT == msgId) {
                    var msgCode = payload[1] & 0xFF;
                    if (Ant.MSG_CODE_EVENT_CHANNEL_CLOSED == msgCode) {
                        // Channel closed, re-open
                        if (LOG_ANT) { logPayload(msg, payload, "RE:RF.CHANNEL_CLOSED"); }
                        open();
                    } else if (Ant.MSG_CODE_EVENT_RX_FAIL_GO_TO_SEARCH == msgCode) {
                        searching = deviceCfg.deviceNumber;
                        if (LOG_ANT) { logPayload(msg, payload, "RE:RF.GO_TO_SEARCH, searching: " + searching); }
                    } else if (LOG_ANT) {
                        if (Ant.MSG_CODE_EVENT_RX_SEARCH_TIMEOUT == msgCode) { logPayload(msg, payload, "RE:RF.RX_SEARCH_TIMEOUT"); }
                        else if (Ant.MSG_CODE_EVENT_RX_FAIL == msgCode) { logPayload(msg, payload, "RE:RF.RX_FAIL"); }
                        else if (Ant.MSG_CODE_EVENT_TRANSFER_TX_COMPLETED  == msgCode) { logPayload(msg, payload, "RE:RF.TX_COMPLETED"); }
                        else if (Ant.MSG_CODE_EVENT_TRANSFER_TX_FAILED  == msgCode) { logPayload(msg, payload, "RE:RF.TX_FAILED"); }
                        else { logPayload(msg, payload, "RE:RF.ELSE: msgCode: 0x" + msgCode.format("%02X")); }
                    }
    

                } else if (LOG_ANT) {
                    //It is a channel response.
                    if (msgId == 0x41) { logPayload(msg, payload, "RE:Unassign Channel"); }
                    else if (msgId == 0x42) { logPayload(msg, payload, "RE:Assign Channel"); }
                    else if (msgId == 0x43) { logPayload(msg, payload, "RE:Channel Period"); }
                    else if (msgId == 0x44) { logPayload(msg, payload, "RE:Search Timeout"); }
                    else if (msgId == 0x45) { logPayload(msg, payload, "RE:Channel RF Frequesncy"); }
                    else if (msgId == 0x4B) { logPayload(msg, payload, "RE:Open Channel"); }
                    else if (msgId == 0x51) { logPayload(msg, payload, "RE:Channel ID"); }
                    else if (msgId == 0x63) { logPayload(msg, payload, "RE:Low Priority Search Timeout"); }
                    else if (msgId == 0x6E) { logPayload(msg, payload, "RE:Lib Config"); }
                    else if (msgId == 0x71) { logPayload(msg, payload, "RE:Proximity Search"); }
                    else { logPayload(msg, payload, "RE:ELSE: msgId: 0x" + msgId.format("%02X")); }
                }
            } else if (LOG_ANT) {
                if (Ant.MSG_ID_NETWORK_KEY == msg.messageId) { logPayload(msg, payload, "NETWORK_KEY"); }
                else if (Ant.MSG_ID_LOW_PRIORITY_SEARCH_TIMEOUT == msg.messageId) { logPayload(msg, payload, "SEARCH_TIMEOUT"); }
                else { logPayload(msg, payload, "ELSE messageId: " + msg.messageId); }
            }
        }
    
    

    Sorry I had to cut it in pieces because the forum didn't let me to post in one piece.

    As you see I also log the msg.timestamp which I thought would mean when the message was either sent by the sensor or received by the device. In my case it never got any value though.