Acknowledged

Bug Report: Toybox.AntPlus.RunningDynamics  no longer functions in Skating Activity Type.


Garmin Forums

The Toybox.AntPlus.RunningDynamics no longer functions when a Skating Activity Type is used in a supported device.   The RunDynamics data reports all zero when using Skating Activity Type(AT), but using Run AT is ok in the same source.  The functionality was functional in previous CIQ versions but is no longer.

Fix:

1.) Renable RunningDynamics in Skating Activity Type or

2.) add Toybox.AntPlus.SkatingDynamics in the CIQ SDK

Brian 

Owner F3b software

  • I'm using 14.68 firmware and I'm using the same SDK version as you (the SDK version is irrelevant, but I matched it for good measure). I still cannot reproduce the behavior that you describe.

    I have looked at the changes in the relevant modules, and there is nothing I'm able to find that is blocking ConnectIQ access to running dynamics data based on the activity type. As a matter of fact, the activity type doesn't matter at all. You can completely remove the code to create/destroy the Session and remove the permission. You will still see the running dynamics data.

    > The 'test' code out of the box, I saw the "No Dynamics" and "No Sensor Position" at the Fenix 7x Pro watch.  

    Yes, as I mentioned previously you will see no running dynamics data until valid data is received from the sensor. I used the following procedure to ensure the device was receiving data from the sensor...

    1. Pair fenix7 to HRM-Run sensor
    2. Configure the native run activity to show the running dynamics data screen
    3. Start recording a Run activity
    4. Jog until running dynamics data is displayed (Balance is valid)

    Now we know we're getting running dynamics data from the sensor in the native run activity, I can now verify it is visible in my Skating app.

    1. Stop and discard the run activity
    2. Start Skating app
    3. Verify running dynamics are shown

    I've also had our QA team try to reproduce the problem you describe. Instead of fussing with a HRM-Run and running up and down the block like a weirdo, they tested with an ANT+ device simulator. But they still reported no problems getting Running Dynamics data from an app recording an inline skating session.

    Another test I ran was to make a copy of my Skating test app, changed it to create a SPORT_RUNNING recording session, gave it a unique UUID, and updated the AppName to "Running". I side-loaded this onto my fenix7 and can can easily flip between Skating and Running apps and verify that both show the same metrics data once valid data is received from the sensor.

    I saw no differences there either; i could start the Running app and see data, and flip over to the Skating app and see the same data. If Skating app stopped showing data, I could easily verify that Running had also stopped. Everything was consistent.

  • Travis,

    This is a follow up on your test code.  I copied and pasted into a new project and does not work on a Fenix 7x pro, 7x or 6x.  Using 

    connectiq-sdk-mac-6.3.1-2023-09-13-47b193194, I tried Fenix 7x Pro, 7x and 6x and HRM-Pro Plus (ANT+ and just in case I replaced with fresh battery)

    The 'test' code out of the box, I saw the "No Dynamics" and "No Sensor Position" at the Fenix 7x Pro watch.  

    I make one change and the data came in

    :sport => Activity.SPORT_RUNNING //.SPORT_INLINE_SKATING

    Unless you are using a prototype watch epix2pro51mm or prototype SDK, the Run Dynamics do not work with an Activity.SPORT_INLINE_SKATING stock watches and SDK.

    Brian.

    • Travis, thank you,  I will verify and see if i did something wrong, but from my testing i only changed the session activity from inlineskate to running.  Then the dynamic data came in.  
    • When I tested, I verified with both RunSafe and InlineSkate by switching the session activity type. 
      Brian.
  • I cannot reproduce the issue described using a HRM-Run and a fenix7.

    My test app creates an recording session using SPORT_INLINE_SKATING, and just polls the run dynamics data. If I start the app and run down the street for a bit, I get run dynamics data just as I'd expect. I do have to run a bit further than I'd like to for the data to start coming through, but it does appear at the same time as it does for the native run dynamics data fields in a native run activity on my epix2pro51mm.

    import Toybox.ActivityRecording;
    import Toybox.Ant;
    import Toybox.AntPlus;
    import Toybox.Application;
    import Toybox.Graphics;
    import Toybox.Lang;
    import Toybox.System;
    import Toybox.Timer;
    import Toybox.WatchUi;
    
    class RunningDynamicsSampleView extends WatchUi.View {
        private var _runningDynamics;
        private var _uiTimer;
    
        function initialize() {
            View.initialize();
        }
    
        hidden var _centerX;
        hidden var _centerY;
        hidden var _font;
        hidden var _fontHeight;
    
        function onLayout(dc as Dc) as Void {
            _centerX = dc.getWidth() / 2;
            _centerY = dc.getHeight() / 2;
    
            _font = Graphics.FONT_XTINY;
            _fontHeight = Graphics.getFontHeight(_font);
        }
    
        function onShow() as Void {
            if (_uiTimer == null) {
                _uiTimer = new Timer.Timer();
                _uiTimer.start(method(:updateScreen), 1000, true);
            }
    
            _runningDynamics = new AntPlus.RunningDynamics(null);
        }
    
        function onUpdate(dc as Dc) as Void {
            var justification = Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER;
            var cx = _centerX;
            var cy = _centerY;
    
            dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
            dc.clear();
    
            cy -= ((11 - 1) * _fontHeight) / 2;
    
            var data;
    
            data = _runningDynamics.getRunningDynamics();
            if (data != null) {
    
                dc.drawText(cx, cy, _font, Lang.format("Cadence: $1$", [ data.cadence ]), justification);
                cy += _fontHeight;
    
                dc.drawText(cx, cy, _font, Lang.format("GCTBal: $1$%", [ data.groundContactBalance ]), justification);
                cy += _fontHeight;
    
                dc.drawText(cx, cy, _font, Lang.format("GCTime: $1$ms", [ data.groundContactTime ]), justification);
                cy += _fontHeight;
    
                dc.drawText(cx, cy, _font, Lang.format("STime: $1$%", [ data.stanceTime ]),  justification);
                cy += _fontHeight;
    
                dc.drawText(cx, cy, _font, Lang.format("StpCnt: $1$ steps", [ data.stepCount ]), justification);
                cy += _fontHeight;
    
                dc.drawText(cx, cy, _font, Lang.format("StpLen: $1$mm", [ data.stepLength ]), justification);
                cy += _fontHeight;
    
                dc.drawText(cx, cy, _font, Lang.format("VrtOsc: $1$mm", [ data.verticalOscillation ]), justification);
                cy += _fontHeight;
    
                dc.drawText(cx, cy, _font, Lang.format("VrtRat: $1$%", [ data.verticalRatio ]), justification);
                cy += _fontHeight;
    
                dc.drawText(cx, cy, _font, Lang.format("Wlkng: $1$", [ data.walkingFlag ]), justification);
                cy += _fontHeight;
            } else {
                dc.drawText(cx, cy, _font, "No Dynamics", justification);
                cy += _fontHeight;
            }
    
            data = _runningDynamics.getSensorPosition();
            if (data != null) {
    
                dc.drawText(cx, cy, _font, Lang.format("BLoc: $1$", [ data.bodyLocation ]), justification);
                cy += _fontHeight;
    
                dc.drawText(cx, cy, _font, Lang.format("Orntn: $1$", [ data.orientation ]), justification);
                cy += _fontHeight;
            } else {
                dc.drawText(cx, cy, _font, "No Sensor Position", justification);
                cy += _fontHeight;
            }
        }
    
        function onHide() as Void {
            _runningDynamics = null;
    
            if (_uiTimer != null) {
                _uiTimer.stop();
                _uiTimer = null;
            }
        }
    
        function updateScreen() as Void {
            WatchUi.requestUpdate();
        }
    }
    
    
    class RunningDynamicsSampleApp extends Application.AppBase {
        function initialize() {
            AppBase.initialize();
        }
    
        hidden var _session;
    
        function onStart(state as Dictionary?) as Void {
            if (_session == null) {
                _session = ActivityRecording.createSession({
                    :name => "Test",
                    :sport => Activity.SPORT_INLINE_SKATING
                });
            }
        }
    
        function onStop(state as Dictionary?) as Void {
            if (_session != null) {
                _session.discard();
                _session = null;
            }
        }
    
        function getInitialView() as Array<Views or InputDelegates>? {
            return [new RunningDynamicsSampleView()];
        }
    }
    

    Based on this testing, I don't understand how you arrived at the conclusion that running dynamics are disabled for the skating activity type. If you have some test procedure or sample code that I could use to reproduce your findings, I'd be happy to take another look.