Writing to FIT File before Auto-Pause

Interesting challenge.... Like most cyclists, I use Auto-Pause. This causes the Device to stop writing to the FIT file when Pause is triggered. This often means the last record written to the FIT file during the STOP time has non-zero values for some metrics like RPM (4rpm), SPEED (1mph), etc.

That has never been an issue before, but I'm playing with a really cool program called Telemetry Overlay. Creating action videos from my rides that sync FIT telemetry with GoPro timestamps. The issue is.... the developer retiains the last FIT telemetry values during the stop time. So the metrics show say 4rpm and 1mph for the footage while stopped.

One easy solution is to write User FIT values for these problematic metrics and assign the User Data to the metric overlays. And inside onTimerPause and onTimeStop, I write a FIT value of zero.

What I'm concerned about it a race condition. I think I've read that FIT writes are async. Meaning my "setValue" method in onTimePause won't actually get written, because the Device stops writing to the FIT file when Auto-Pause triggers, so my async setValue won't actually write my data value until possibly after I start riding again.

Any insight into how this works or a way to flush the write buffer to the file?

  • What I'm concerned about it a race condition. I think I've read that FIT writes are async. Meaning my "setValue" method in onTimePause won't actually get written, because the Device stops writing to the FIT file when Auto-Pause triggers, so my async setValue won't actually write my data value until possibly after I start riding again.

    Minor nitpick: the CIQ API call in question is Toybox.FitContributor.Field.setData(), not setValue(). (Yes, I realize setValue() is the name of *your* function, but keep in mind that people who are trying to answer your question / learn from your post in the future would be better served by knowing the name of the standard API function that you're using, not the random name of your own functin.)

    [https://developer.garmin.com/connect-iq/api-docs/Toybox/FitContributor/Field.html#setData-instance_function]

    setData() isn’t async per se, because it doesn’t do what you imply it does. It doesn’t write data to the FIT file, it sets the next value to be written, which is why it’s called setData() and not writeData(). To make this clearer, if you call setValue() 20 times in one second, 20 values won’t be written, 1 value will be written (since FIT files aren’t written to more than once per second.) The value that’s actually written will be the value provided to the last call to setValue() before the field was written to the FIT file.

    So you really can’t control when FIT data will be written via CIQ, only the next value to be written. The one sort-of exception to this is that data won’t be written until the *first* call to setData(). Another exception would be that if smart recording is enabled, the frequency at which you call setData() may affect the frequency at which data is actually written.

    Regardless, you don’t have direct control over when FIT data is actually written. setData() simply tells the firmware that data is available, and the firmware decides when that data will be written.

    I think the docs explain this fairly well:

    A Field records custom FIT data from an Application or Data Field to a FIT file on the device's file system.

    Once a Field is created with the createField() method, you can submit the next Field value with setData(), which will get written to the FIT file at the next opportunity. Depending on the device, writes to the FIT file may occur once per second or when new data is available (Smart Recording). Best practice is to only call setData() when values have changed to accommodate Smart Recording.

    If setData() is called before the previous data is written out, the previous value will be lost and replaced by the current data. For this reason, we do not recommend using this feature for time-sensitive data requiring sub-second granularity.

    And inside onTimerPause and onTimeStop, I write a FIT value of zero.

    If these functions work like onTimerLap(), then they’re called after the timer has actually paused or stopped, which means it’s too late, as you said.

    I think the only thing you can do is attempt to guess within your app when auto-pause will kick in (based on speed), and write something to the FIT file before it happens. That’s obviously a terrible idea, but I can’t think of any other solution.

    What I'm concerned about it a race condition.

    I wouldn’t call this a race condition, given that setData() doesn’t actually perform an “async write”. A race condition would be when the order of events is unpredictable or unknowable, but you need one specific order for things to work. In this case, you know what the order of events is, it’s just that due to the way the system works, you’re unable to implement the behavior you want.