SimpleDataField Question and Side loading onto device.

Former Member
Former Member
Hi

I have used the simpledata field example and have modified it to calculate the estimated finish times for a number of distances. I have obviously done something wrong or missed something out - although it compiles and makes a prg file ok, but when I load it on to the device I can select it in the activity settings data fields but it then crashes the device. In the simulator it runs ok and scrolls through the screens, the only issue I have had is if I don't start the data simulation before running the app.

what am I doing wrong/

using Toybox.WatchUi as Ui;
using Toybox.WatchUi as Ui;
using Toybox.Application as App;
using Toybox.System as Sys;
using Toybox.Time as Time;

class CHetcView extends Ui.SimpleDataField
{
var counter;
var fin5k;
var fin10k;

//! Constructor
function initialize()
{
label = "Dist, 5km, 10km";
counter = 0;
}

//! Handle the update event
function compute(info)
{
var value_picked = null;
var miles = info.elapsedDistance * 0.5;

//Cycle between distance, 5km time(duration), and 10km (Duration)
if (activity.
if( counter == 0 )
{
if( info.elapsedDistance != null )
{
value_picked = info.elapsedDistance / 1000;
}
}
if( counter == 1 )
{
if( info.elapsedDistance <= 5000 )
{
//elapsedTime is in ms.
var options = { :seconds => ((5000 - info.elapsedDistance) / info.currentSpeed) + (info.elapsedTime / 1000) };
fin5k = info.elapsedTime / 1000;
value_picked = Time.Gregorian.duration( options );
}
if ( info.elapsedDistance > 1000 )
{
//elapsedTime is in ms.
var option = { :seconds => (fin5k) };
value_picked = Time.Gregorian.duration ( option );
}
}
if( counter == 2 )
{
if( info.elapsedDistance <= 10000 )
{
//elapsedTime is in ms.
var options = { :seconds => ((10000 - info.elapsedDistance) / info.currentSpeed) + (info.elapsedTime / 1000) };
fin10k = info.elapsedTime / 1000;
value_picked = Time.Gregorian.duration( options );
}
if ( info.elapsedDistance > 10000 )
{
//elapsedTime is in ms.
var option = { :seconds => (fin10k) };
value_picked = Time.Gregorian.duration ( option );
}
}
counter += 1;
if( counter > 2 )
{
counter = 0;
}

return value_picked;
}

}


and the App.mc looks like this:

using Toybox.Application as App;

class CHetcApp extends App.AppBase {

//! onStart() is called on application start up
function onStart() {
}

//! onStop() is called when your application is exiting
function onStop() {
}

//! Return the initial view of your application here
function getInitialView() {
return [ new CHetcView() ];
}

}


I have tried running the following command to launch the simulator:

monkeydo c:\ADT\connectiq\mine\CHetc.prg fr920xt

and I get the following:

File pushed successfully
Connection Finished
Closing shell and port
Found Transport: tcp
Connecting...
Connecting to device...
Device Version 0.1.0
Device id 1 name "A garmin device"
Shell Version 0.1.0
Failed invoking <symbol>
Unexpected Type Error
@PC = 0x10000030
Unexpected Type Error
Unexpected Type Error

It also seems that if I run the code before start simulate data on the device it crashes.
  • It also seems that if I run the code before start simulate data on the device it crashes.


    This is the problem. You need to check that the fields of info are not null. You are making the check in the first if block, but not in any of the others.
  • Just to expand a little on what Travis said, you need to check it when you initialize your 'miles' variable. If info.elapsedDistance is null, it'll die right there.
  • Former Member
    Former Member over 10 years ago
    I have changed the code and basically added this to the if statements


    if( info.elapsedDistance !=null and info.elapsedDistance <= 10000 )
  • Former Member
    Former Member over 10 years ago
    Thanks - I have removed the miles variable as I was thinking about adding that in then forgot about it. Removing this and then changing the code as to the post below it works.

    I am relatively new to programming and appreciate the help with this.
  • Your program will crash if you read from a variable that is null (other than to compare it against null). This means that every place you access one of the members of info is a potential point of failure. Instead of adding a check before every single expression involving those variables, you could just do one check once near the top and bail out early. If one of those variables is null, you aren't going to be able to display anything useful anyway, right?

    The following code is a bit pedantic in that it checks the validity of every data member that is accessed. It is extremely likely that if one field is null, all of them are null, but this will should just fine.

    //! Handle the update event
    function compute(info)
    {

    if (info == null || info.elapsedDistance == null || info.elapsedTime == null || info.currentSpeed == null) {
    return null; // i'm not certain that you can do this, but i think it will work out fine.
    }

    var value_picked = null;
    var miles = info.elapsedDistance * 0.5;

    //Cycle between distance, 5km time(duration), and 10km (Duration)
    if( counter == 0 )
    {
    value_picked = info.elapsedDistance / 1000;
    }
    if( counter == 1 )
    {
    if( info.elapsedDistance <= 5000 )
    {
    //elapsedTime is in ms.
    var options = { :seconds => ((5000 - info.elapsedDistance) / info.currentSpeed) + (info.elapsedTime / 1000) };
    fin5k = info.elapsedTime / 1000;
    value_picked = Time.Gregorian.duration( options );
    }
    if ( info.elapsedDistance > 1000 )
    {
    //elapsedTime is in ms.
    var option = { :seconds => (fin5k) };
    // value_picked = fin5k
    value_picked = Time.Gregorian.duration ( option );
    }
    }


    Additionally, you need to be careful with code like this...

    ((5000 - info.elapsedDistance) / info.currentSpeed) + (info.elapsedTime / 1000)


    With this code, if the user stops moving (current speed becomes very small), the result of the first sub-expression can become very large. As the speed goes to zero, the result of the expression goes toward infinity. I'm not absolutely certain what how the ConnectIQ programming language handles this, but most programming languages generate the special value in this case, and it could cause weird results to be displayed. It is also possible that an exception would be raised, and that could cause your program to crash.

    This last item might require some testing or maybe some feedback from the ConnectIQ team.
  • If your SimpleDataField.compute() method returns the result of 1 / 0.0, the value displayed in the simulator is 1.#.1.