Help! Weird crash on Vivoactive HR

Former Member
Former Member
Yesterday I released SmartCycle and a user reported an immediate crash on the vivoactive HR. VivoactiveHRGuy was kind enough to try it out on his device and the error is:
UnexpectedTypeException: Expected String, given
compute in source\SmartCycleView.mc:549
Note "Expected String, given " - given what, exactly???

Also CIQ_LOG.TXT reports:
ERROR: Unhandled Exception
DETAILS: Failed invoking <symbol>
STORE_ID: 00000000000000000000000000000000
CALLSTACK:

WARNING: Failed in data field compute
STORE_ID: 00000000000000000000000000000000


Now the line in question that was reported, line 549, is in my compute(info) function (the line is "power = info.currentPower;"):
function compute(info) {
avgSpeed = info.averageSpeed;
if (avgSpeed == null) {
activityStarted = false;
} else {
avgSpeed *= $.speedConversionFactor;
activityStarted = avgSpeed > 0;
}
speed = info.currentSpeed;
if (speed != null && speed != 0) {
speed *= $.speedConversionFactor;
showStats = false; //???stats
} else {
showStats = activityStarted; //???stats
}
cadence = info.currentCadence;
heartRate = info.currentHeartRate;
hrZones.compute(heartRate, ! activityStarted, activityStarted && ! showStats);
heading = info.currentHeading;
power = info.currentPower;
distance = info.elapsedDistance;
if (distance != null) {
distance *= $.distanceConversionFactor;
}

if (showStats && stats != null) {
stats.compute(info);
}
}

That line looks pretty innocuous, it's just getting the power data. If currentPower isn't available, it should return null right? That's the way it works on my FR735XT.

Any ideas?
  • Per the api doc for currentPower, it's supported on only these devices:

    Supported Devices:
    Forerunner 735xt/920XT
    fenix 3/3 HR
    Quatix 3
    D2 Bravo/Titanium
    epix
    All Edges

    It looks like you need to use "has" to see if it's available before referencing it, so that your code will run on devices that don't support it.

    BTW, "has" will always be true for this in the sim, but will protect your code on real devices. If you want to test this in the sim, maybe include a "&& false" or something in the conditional for testing.

    Update:

    Here's how you do the "has"
    if(info has :currentPower) {
    //you may also want to check for null before using it
    }
  • Former Member
    Former Member
    That was my first thought as well .. that the VAHR is not in that list. So I would expect him to get a null in that case .. and surely the reason for the crash.
  • Former Member
    Former Member
    That was my first thought as well .. that the VAHR is not in that list. So I would expect him to get a null in that case .. and surely the reason for the crash.


    Jim is right, I'm not using "has". My code expects to get null sometimes, but the problem was I assumed that if power isn't available I would always get null. On the Vivoactive HR, it throws a strange error instead. Interestingly it is a DIFFERENT error than if I had just referenced a field that doesn't exist, for example info.currentPowerXXX throws an error that explicitly states that currentPowerXXX doesn't exist. On the Vivoactive HR, referencing info.currentPower gives the weird error "UnexpectedTypeException: Expected String, given ". Sigh
  • Former Member
    Former Member
    I think it's fixed now. Thanks everyone.
  • WPWOODJR - for stuff like this, you always want to use "has", as if a value isn't there in the watch, you won't get a null value if it's not available. It's simply not there and there is no value. (this also allows running on older FW when something new is added, on the same device)

    I simplified my "has" a bit, as what I generally do, is that in initialize() I do the "has" for things that may or may not be available and set a boolean, so the "has" doesn't have to be done all the time (it's a bit faster to check).

    Oh, and why you didn't see the symbol? This was probably a download from the app store - it's a release version and debug symbols are stripped. With a side-load that is a debug build, you'll see it.
  • Former Member
    Former Member
    Good to know .. thanks Jim.
  • "has" is really useful if you support multiple devices (more so even now, with devices having 1.3.x and 2.1.x VMs), and to be honest, a bit understated in the Programmer's guide! :)

    However, if you ever use anything with a list of "supported devices", or "Since "2.1.0", and want to support multiple devices, it should be near the top of your toolkit! Even today the "J" (APAC) versions of some watches have a 1.2.x VM, so what works on a "xyz" device might not work on a "xyzJ" watch...

    I'm porting some things I did for watches to Edge devices right now, and on those, even things that were always there for watches like "ActiviyMonitor" don't exist. (no 24/7 tracking at all!), and am using "has" there too!
  • Former Member
    Former Member
    WPWOODJR - for stuff like this, you always want to use "has", as if a value isn't there in the watch, you won't get a null value if it's not available. It's simply not there and there is no value. (this also allows running on older FW when something new is added, on the same device)

    I simplified my "has" a bit, as what I generally do, is that in initialize() I do the "has" for things that may or may not be available and set a boolean, so the "has" doesn't have to be done all the time (it's a bit faster to check).

    Oh, and why you didn't see the symbol? This was probably a download from the app store - it's a release version and debug symbols are stripped. With a side-load that is a debug build, you'll see it.


    Thanks Jim.

    Actually it was a debug version that VivoactiveHRGuy kindly side loaded and ran for me. It seems that info.currentPower is somehow different than info.currentPowerXXX on devices like the vivoactive HR that don't support currentPower.
  • It might be that he didn't forward the earlier part of the ciq_log.txt where the symbol was named. It tried a test a few hours back, and I saw the symbol, and it was a bit before with the line number reference, etc.. (ciq_log.txt files can be a bit hard to sort out if you let them grow :) )