Processing Settings Best Practices?

Hi, 

I am working on a datafield that can aid in race planning. For this purpose the user can input the length and target pace of each "lap" and the  datafield keeps track how far ahead or behind the person is during the activity. My issue is that I need an array of distances and an array of times to be input. Distances could be either in km or miles, and times should be in a m:ss format (maybe even h:mm:ss, but not supporting this right now). 

The best (only?) solution I have come up with is the following: In my Settings I have two "String" Properties that need to be filled in with something "1.2, 3.4, 0.8" for the distances and "10:30, 23:32, 8:03" for the times. I then parse these strings in my "initialize" method, and convert them to arrays stat store the distances in meters and the times in milliseconds (taking care to convert everything to integers so as to save memory) and then I use these in my watchface code to do what it needs to do. 

I am looking for better solutions to this.

My holy grail would be to be able to by some magic have the "Settings Processing" done in the Garmin Connect App on the Phone or PC rather than on the device itself. Is there any way to something like that?

Alternatively could I write a 'companion' IQ App that somehow reads the Settings and creates the data structures for the Datafield? This would require an additonal step by the user, but would allow the datafield itself to be much leaner. 

And less ambitiously, is there an efficient way to do the above? Forcing the user to convert miles to meters, and m:sec to millisecs seems a pain, but might be an option, but I would still need to convert a string to an array. Just for reference, here is what I am currently doing:

        var string = (Application.getApp().getProperty("lapTimes").toString());
		
 		var index = string.find(",");
		while (index != null) {
			var item = string.substring(0,index);
 			var length = string.length();
 			string = string.substring(index+1,length);
 			lapTimesArray.add(stringToMs(item));
 			index = string.find(",");
 		}
 		lapTimesArray.add(stringToMs(string));

The "stringToMs" method is defined as follows:

	function stringToMs (string) {
		var index = string.find(":");
		var ms;
		if (index != null) {
			var minString = string.substring(0,index);
			var mins = minString.toNumber();
			minString = null;
			var secString = string.substring(index+1,string.length());
			var sec = secString.toNumber();
			secString = null;
			ms = (mins*60+sec)*1000;
		} else {
			var mins = string.toNumber();
			ms = mins*60*1000;
		}
		return ms;
	}

Clearly, I must also have a msToString task that converts ms times to strings, for display purposes:

	function msToString (timeInms) {
		var negative = timeInms < 0;
		timeInms = negative ? -(timeInms) : timeInms;  
		var totalsecs = timeInms/1000;
		var hours = Math.floor(totalsecs/3600);
		var mins = Math.floor((totalsecs-hours*3600)/60);
		var secs = Math.floor(totalsecs-hours*3600-mins*60);
		var outstring = "";
		var signString = negative ? "-" : "";
		if (hours == 0) {
			outstring = signString+mins.format("%0d")+":"+secs.format("%02d");
		} else {
			outstring = signString+hours.format("%d")+":"+mins.format("%02d")+":"+secs.format("%02d");
		}
		return outstring;
	}

It seems that a lot of what a datafield or watchface will be doing is convert times to strings,  so I was wondering if there is something more efficient (built in??) than what I am doing.

Thanks for any suggestions!

  • You can simply your msToString a bit, like this:

        function msToString(ms) {
            var sign=(ms<0) ? "-" : "";
            var secs=(ms/1000).abs();
        	var hr = secs/3600;
        	var min = (secs-(hr*3600))/60;
        	var sec = secs%60;
        	if(hr==0) {return sign+min.format("02d")+":"+sec.format("%02d");}
        	else {return sign+hr.format("%02d")+":"+min.format("02d")+":"+sec.format("%02d");}
        }

    No need for the Math.floor() calls, and a bit less going on as far as vars.

    As far as the settings, do you have a realistic max for the number of laps?  Instead of having two arrays, you have say 10 lap/time pairs.

    <property id="lapdistance0"....

    <property id="laptime0"..

    <property id="lapdistance1"...

    <property id="laptime1"...

    etc.....

    and then let settings handle at least some of the type/range checking

    then when reading them, something like

    var d[maxlaps],t[maxlaps];
    
    for(var i=0;i<maxlaps;i++) {
        d[i]=Application.Property.getValue("latdistance+i); //maybe do conversions here
        t[i]=Application.Property.getValue("laptime"+i);    //and here
    }

    It simplifies parcing of the settings some, and with the arrays, it might be easier for the user to make an error

  • Thank you! I like your clean up for the msToString(), and I will use it. Regarding the max number of laps, I could easily see 27 laps (Marathon is 26 miles + 0.2) but in that case I could get away with only one value for distance (1 for all of them, the last one doesn't matter in my case). However I am trying to use one datafield for two slightly different use cases: road races typically have accurately placed mile markers for every mile, so laps == miles and life is simple. For trail races this is typically not true and I was envisioning this as distance between Aid Stations or other easily identifiable locations (intersections, peaks, bridges). In those cases 10 might actually be a reasonable number. So maybe it makes sense to have two different datafields, optimized for the two cases. 

    In any case, thank you for the help!

    Gerald