Activity.Info fields not working?

Hi,

I am trying to access some of the 'newer' fields of Activity.Info inside of a complex data field and having no luck. For example, when the following code is run in the simulator on a Fenix 3, it crashes with a 'Symbol Not Found Error'.

class a extends Ui.DataField
{
...

function compute(info)
{
System.println("track: " + info.track);
}

....
}


As far as I am aware the 'track' attribute has been available since 1.2.10 (according to the docs http://developer.garmin.com/connect-iq/api-docs/) and I am using SDK 2.1.2. Same goes for the other attributes available since 1.2.10. I'm guessing I'm probably doing something dumb or just haven't read the latest post about using these attributes :confused:?

While I'm at it, does info.currentCadence give the walking cadence for a walking activity, or the running cadence for a running activity, or, if not, is there a way to get these values?
  • Former Member
    Former Member over 8 years ago
    The simulator doesn't support all info data (course data for instance), but the devices also do not support all the info data. Some of the fields list supported devices in the documentation (though most do not). This doesn't answer your question, but you should check to see if the data exists in the code before using it in the field. There is an example somewhere. I end up having to test all the newer data fields on the actual device with a side load...
  • info.track might be just not supported like the new navigation properties in Activity.Info(elevation/distance at/to the next waipoint etc.)
  • For any field that hasn't been around for a long time, you should be safe and check that the field exists before referencing it...

    if (info has :track) {
    // the platform has support for the track attribute

    if (info.track != null) {
    // the attribute has a value

    }
    }


    The simulator should fail the has check if the feature is not yet supported, and the attribute may be null if the device isn't in a state where that attribute makes sense (track could be null if not currently using navigation features).

    The currentCadence should give a value for the current activity type. A device that supplies cadence data will be necessary (HRM-Run, FootPod, Power Meter, or sometimes built in to the device).
  • As Travis said, "has" for things should be used if there is any question. There are also things where "has" will fail in the sim, but work fine on some actual watches, BTW

    An example is "mag" in Sensors.. It's not there in the sim, but is on the va-hr and 735 (for example), so you really have to test "mag" things with a sideload. (it's easier than trying to spin your computer around though! :) )
  • If you are in the situation that you want to test something that isn't available in the simulator, you can easily do something like this...

    const debug = true;

    function get_track(info) {
    if (debug) {
    // generate a value to test...
    }
    else if (info has :track) {
    return info.track;
    }

    return null;
    }


    Every place you access the info.track variable, you'd just call get_track(info).

    There are many things you can do to generate reasonable test values. The following is something similar to what I've used in the past, but I just wrote it from scratch here at work. I'm not sure if it compiles or is even correct (I'll test it tonight), but it should be close to working...

    // generate a value on the range [0, 1) with the given period in milliseconds. the values
    // returned will appear to follow a sawtooth wave over time.
    //
    // | . . . .
    // | . . . .
    // | . . . .
    // | . . . . .
    // |. . . . .
    // +------------------------------------
    //
    class SawtoothGenerator
    {
    using Toybox.System as Sys;

    hidden var period;

    function initialize(period) {
    self.period = period;
    }

    function get() {

    // this counter increases with time
    var now = Sys.getTimer();

    // get a value in the range [0, 1) that represents the fraction
    // of the current period
    return (now % period).toFloat() / period;
    }
    }

    // generate a value on the range [0, 1) with the given period in milliseconds. the values
    // returned will appear to follow a sin wave over time.
    //
    // | . .
    // | . . . .
    // | . . . .
    // | . . . .
    // | . . . .
    // +------------------------------------
    class WaveGenerator
    {
    using Toybox.System as Sys;
    using Toybox.Math as Math;

    hidden var period;

    function initialize(period) {
    self.period = period;
    }

    function get() {
    // this counter increases with time
    var now = Sys.getTimer();

    // get a value in the range [0, 1) as a sawtooth
    var value_0to1 = (now % period).toFloat() / period;

    // map that value onto an angle from [0, 360)
    var angle_0to360 = (Math.PI * 2) * value_0to1;

    // map the angle back to the x coordinate on a circle plot
    // which is on the range [-1, 1)
    var value_n1_to_p1 = Math.sin(angle_0to360);

    // map that value to the range [0, 1)
    return (value_n1_to_p1 + 1) / 2;
    }
    }

    // generate a value by taking the product of the values returned by multiple
    // generators. if each generator give a value on the range [0, 1), this generator
    // will give a result on the range [0, 1).
    class CompositeGenerator
    {
    hidden var generators;

    function initialize(generators) {
    self.generators = generators;
    }

    function get() {
    var value = 1.0f;

    for (var i = 0; i < j; ++i) {
    value *= generators.get();
    }

    return value;
    }
    }

    // scale the result of a given generator
    class ScaledGenerator
    {
    hidden var generator;
    hidden var scale;

    function initialize(generator, scale) {
    self.generator = generator;
    self.scale = scale;
    }

    function get() {
    return generator.get() * scale;
    }
    }

    // offet the result of a given generator
    class OffsetGenerator
    {
    hidden var generator;
    hidden var offset;

    function initialize(generator, offset) {
    self.generator = generator;
    self.offset = offset;
    }

    function get() {
    return offset + generator.get();
    }
    }
    [/code]

    // will produce values from [0, 39) degrees (in radians)
    var track_generator = new CompositeGenerator([
    new ScaleGenerator(new WaveGenerator( 60000), Math.PI / 20), // generate a value that varies by 9 degrees every 1 minute
    new ScaleGenerator(new WaveGenerator(600000), Math.PI / 6) // generate a value that varies by 30 degrees every 10 minutes
    ]);

    function get_track(info) {
    if (debug) {
    return track_generator.get();
    }

    // snip...
    }


    If you are a real design nerd, you'd write up something like this...

    class ActivityTrackProvider
    {
    function initialize() {
    }

    function get_track(info) {
    if (info has :track) {
    return info.track;
    }
    return null;
    }
    }

    class GeneratedTrackProvider
    {
    hidden var generator;

    function initialize() {

    // could take configuration parameters to constructor, but I've hard-coded these ones
    generator = new CompositeGenerator([
    new ScaleGenerator(new WaveGenerator( 60000), Math.PI / 20), // generate a value that varies by 9 degrees every 1 minute
    new ScaleGenerator(new WaveGenerator(600000), Math.PI / 6) // generate a value that varies by 30 degrees every 10 minutes
    ]);
    }

    function get_track(info) {
    return generator.get();
    }
    }


    Then you'd pass the appropriate track provider to your view (or whatever).

    class MyApp extends App.AppBase
    {
    function getInitialView() {

    var trackProvider;
    if (debug) {
    trackProvider = new GeneratedTrackProvider();
    }
    else {
    trackProvider = new ActivityTrackProvider();
    }

    return [ new MyView(trackProvider) ];
    }
    }
  • Travis these are great examples, but the problem is there is no info.track in simulator neither in fenix3(even if api says it is there).
  • Yes, I totally understand the situation. It is just as was described on 8/31... A method or data is documented as part of the API and it is not available in the simulator or with one or more devices. This is not unheard of. Just because something is documented as part of the API does not mean that it is is available on all devices, even if the firmware on that device meets the minimum version for the feature.

    That said, I believe the track member is available on some devices with navigation features. The functionality may come to other devices over time.

    I posted the example code to demonstrate how to generate fake data so that a developer could continue writing an application even though the simulator and devices used for testing don't support the functionality.