What is the purpose of Toybox.Activity.Info.offCourseDistance?

I have a Garmin Edge 1030. When I am riding a course, the data field Dist. to Next shows the remaining distance to the next course point (situation 1). When I am riding off course, this data field shows a value that I think is the smallest distance between my current location and the nearest point on the course (situation 2). There is no documentation on the behavior of situation 2 in the Edge 1030 manual, but from experience, I believe that this is indeed the case. When I am riding off course, the value in this field decreases as I am nearing the course, and becomes 0 when I am back on course.

According to the API documentation, the attribute offCourseDistance in class Toybox.Activity.Info contains the distance to the nearest point on the current course in meters. Therefore, I assume that this attribute contains the value that is displayed in the data field Dist. to Next when I am riding off course (situation 2). I have tested this with a data field that shows info.offCourseDistance (in fact, it logs info.offCourseDistance with a System.println statement). However, the value of offCourseDistance is always null. It is even null when I am riding a course and I deliberately go off course. In this case, the data field Dist. to Next shows the distance between my location and the nearest point on the course, and I expected info.offCourseDistance to contain the same value. But obviously it does not.

Is this a bug? Is this intended behavior? If so, when does offCourseDistance have a non-null value? Does it matter if the Off Course Warnings setting on the Edge is on or off?

(As a side note, the API documentation is sometimes very minimal. For example, it would be useful if the documentation on e.g. the offCourseDistance attribute indicated when the value equals 0.0, and when the value equals null (for example, if there is no course, or whatever). The simulator does not help in these cases, in the simulator offCourseDistance is always 0. The simulator does not simulate the Edge 1030 in this case.

The lack of useful documentation is not limited to offCourseDistance. For example, from trial and error I have learned that info.elapsedDistance equals null when the timer on my Edge is not active, but info.timerTime equals 0 in this case. I am sure that there is a good reason for elapsedDistance to be null instead of 0 and for timerTime to be 0 instead of null, but I cannot think of one. Documentation on the values of attributes that a developer can expect in certain situations would be a great improvement.)

  • +1. The distance thing is interesting because the native distance field shows 0.00 before the activity has started, not “—“ (which is typically shown for null values, like when you don’t have HR or Power data). My only guess is that you could use the null distance value to determine that the activity has not started, although there are other ways to do that of course.
  • As far as the nulls, the API doc for Activity.Info does have a general statement in the overview that values should be null checked, as yes, it can occur at various times for various things.

    Rule of thumb is always null check. And for some things, you may also want to use Jungles or "has" to adapt for devices that may not support that value.

    Testing for things like offCourseDistance, you really want to do on a real device and not the sim, as I'm not sure how you'd even do it in the sim. And when you do go off course, you may have to be a minimum distance off course for it to show anying. GPS is at best accurate within a certain distance and not exact (you can see this while watching distance with a device just sitting on a table, where distance can increase). So you want to get a ways off course to see what happens (maybe 50-100 feet?). Instead of using println, I'd display it in the DF in some way (even just for debugging), as that way you can see what's happening as it's happening in more real time. Go 20' off course, then 50', then 100' for example, and maybe give it a bit of time to detect you are off course..
  • As far as the nulls, the API doc for Activity.Info does have a general statement in the overview that values should be null checked, as yes, it can occur at various times for various things.

    Rule of thumb is always null check. And for some things, you may also want to use Jungles or "has" to adapt for devices that may not support that value.


    Absolutely. I do test for existence of attributes (has) and null values. I am just curious why in identical cases some values are null, and some are 0. More elaborate documentation would be useful, I think.

    Go 20' off course, then 50', then 100' for example, and maybe give it a bit of time to detect you are off course..


    I was more than 200 meters off course. The native data field Dist. to Next also showed this value (situation 2) instead of the real value to the next course point (situation 1), which was several kilometers away. So the device had properly detected that I was off course. Only offCourseDistance was still null.
  • Generate a simple test case for the off course thing and post about it in the bug report forum.

    For null vs zero, you mean between the sim and device, or at different times in the sim or different times on the device? Or just different fields? With null checks, I admit I don't pay attention to null vs 0, and just treat both as 0.
  • Generate a simple test case for the off course thing and post about it in the bug report forum.


    Will do. I wanted to make sure that it is indeed a bug, and not something I overlooked, before I post in the bug report forum.

    For null vs zero, you mean between the sim and device, or at different times in the sim or different times on the device? Or just different fields? With null checks, I admit I don't pay attention to null vs 0, and just treat both as 0.


    No, I mean the difference between two (in my opinion) similar attributes, on my device, in the same circumstance. For example, on my device, when the timer is not yet active (I haven't pressed the Start button yet), info.elapsedDistance is null, but info.timerTime is 0. Why are they not both null or both 0? And, as FlowState remarked, why is the native Distance data field showing 0 instead of _.__, even though info.elapsedDistance is null and not 0?

    I am looking for consistency, and this behavior seems random to me. Apart from that, it is not a big issue. Just wondering. And I think the API documentation could be more elaborate on these subjects.
  • Yes the time/distance consistency question is the exact same question I asked myself (and the forum) when I started coding CIQ for fun. And I got similar answers along the lines of “why does it matter”, “what are you trying to accomplish” and “that’s just the way it is”.

    If you look at some of the bug reports regarding language design, you will see a pattern. For example, “if (0)” is false, but “if (0.0)” is true, although “0 == 0.0” is true. There are many examples of this and nobody can answer why except “that’s the way it is, deal with it”.

    Really, the only answer is that you will have to do a lot of testing to discover and guard against all the surprises. And lots of forum searching to discover things like “VA3 cannot detect KEY in a widget” or “230/235/730/920/630 cannot detect long press but newer watches can”.
  • That's really up to the FW, as that's where the data is generated. If you think about it, elapsedDistantce=null vs elapsedDistance=0 are two different cases. Null means there is no distance (it's unknown-recording hasn't started), 0 means you are recording and just haven't gone anywhere yet. How you display that (0 or --) is up to you.

    elapsedTime=0 if you've not started recording. I'm not sure null would be useful there.

    One other thing to consider, is even after you start recording, things can still be null for a bit. I think averageSpeed is an example of that, but I'd have to check. Again, I just null check pretty much everything in Activity.Info per the API doc.
  • Yes the explanation for distance makes sense and is the first thing I thought of. After all your distance could be zero for the whole activity if you stand still. But it’s not clear why that argument would apply to distance and not time.

    Lots of things can be null while you’re recording. Like power or HR if your power sensor is not connected or you’re not wearing the optical HR sensor.

    I think the question is why is this specific thing null....
  • A null distance means there is no distance. A time of zero makes sense where a null might not. You'll also see null for things that don't make sense in the current context. For example, an activity that doesn't use GPS has null for currentLocation (there is no currentLocation even when recording). And I'm sure there are things that are sport type specific that will be null for other sports, recording or not.
  • Yes I understand the concept of null. I could argue that if the activity hasn’t started, then time could also be null. The exact same logic as a distance of null.
    Q: “How long have you been running?”
    A: ”I haven’t started yet”
    A: “I’ve been running for zero milliseconds”
    Those two answers are subtly different (*) although to be fair, there is no practical difference at all. Except of course in the second case you could’ve started running at that instant. Certainly if time was expressed in minutes, there would be a huge difference between saying time is null and time is 0 minutes.
    (* What if the actual timer resolution was so fine that it could return a value of 0 when you’ve been running for 0.49 milliseconds? Or what if you get an initial reading of 0 at the instant you start running?)

    I will concede that there is a real difference between time and distance in the sense that some activities may have no distance at all, like strength, while every activity has time once you start it. However, I haven’t checked to see if distance is always null in a strength activity, although now I want to....