Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[(Probably) since Garmin Edge 1040 Solar Firmware Update] Uncaught TypeError: end(): Argument #1 ($array) must be of type array, null given #71

Open
akberlin opened this issue Sep 4, 2023 · 9 comments

Comments

@akberlin
Copy link

akberlin commented Sep 4, 2023

Hi Adrian, hi community,
seems like Garmin have extended/changed something in the file format with a firmware update. (Or my Edge 1040 Solar is producing crap because of the new firmware. - Not sure actually!) Since then I happen to see these errors when importing FIT-files:

First obstacle was this:

[04-Sep-2023 20:30:59 Europe/Berlin] PHP Fatal error: Uncaught TypeError: end(): Argument #1 ($array) must be of type array, null given in /var/www/html/_tools/php-FIT-File-Analysis/20200728/src/phpFITFileAnalysis.php:2478
Stack trace:
#0 /var/www/html/_tools/php-FIT-File-Analysis/20200728/src/phpFITFileAnalysis.php(2478): end()
#1 /var/www/html/_tools/php-FIT-File-Analysis/20200728/src/phpFITFileAnalysis.php(2653): adriangibbons\phpFITFileAnalysis->isPaused()
#2 /var/www/html/xxx.php(308): adriangibbons\phpFITFileAnalysis->gearChanges()
#3 /var/www/html/xxx.php(68): addGarmin()
#4 /var/www/html/xxx.php(24): addGarminTraining()
#5 {main}
thrown in /var/www/html/_tools/php-FIT-File-Analysis/20200728/src/phpFITFileAnalysis.php on line 2478

when commenting out the section about gear changes (don't need them actually anyways) I see the same problem with pauses - but those I'd like to import...

[04-Sep-2023 20:43:16 Europe/Berlin] PHP Fatal error: Uncaught TypeError: end(): Argument #1 ($array) must be of type array, null given in /var/www/html/_tools/php-FIT-File-Analysis/20200728/src/phpFITFileAnalysis.php:2478
Stack trace:
#0 /var/www/html/_tools/php-FIT-File-Analysis/20200728/src/phpFITFileAnalysis.php(2478): end()
#1 /var/www/html/xxx.php(344): adriangibbons\phpFITFileAnalysis->isPaused()
#2 /var/www/html/xxx.php(68): addGarmin()
#3 /var/www/html/xxx.php(24): addGarminTraining()
#4 {main}
thrown in /var/www/html/_tools/php-FIT-File-Analysis/20200728/src/phpFITFileAnalysis.php on line 2478

My current bypass is using the "Fit File Repair Tool" - which seems to see this assumed file format extension as an error or correctly interprets the existing error and cleans the FIT-file which then runs smoothly.

Would be willing to provide original and repaired files but not as an attachment here... (home address visible)

Adrian, thanks for your superb framework and the support... Regards from Germany Andreas

@akberlin
Copy link
Author

Dropping in my latest finding (and still hoping for this issue to relive): With the Edge Firmware mentioned my Garmin device now generates V2 FIT-files - previously those were V1. When I import and export them in/from Fit File Repair Tool they are converted to V1 - which seems to be what makes them parsable by php-fit-file-analysis...

@adriangibbons
Copy link
Owner

Hi @akberlin - this repo isn't really maintained any more. But let's see...

The error appears to be with line 2478, i.e. $is_paused[$last_ts] = end($this->data_mesgs['record']['speed']) == 0 ? true : false; and that null was supplied to the end() function and not an array.

Makes me suspect that $this->data_mesgs['record']['speed'] is null.

What happens if you comment out the offending line and instead var_dump() the array? i.e.

var_dump($this->data_mesgs['record']['speed']);
// $is_paused[$last_ts] = end($this->data_mesgs['record']['speed']) == 0 ? true : false;

@akberlin
Copy link
Author

Hi @adriangibbons - thanks for getting back.... I'll give it a try on wednesday... am in the process of reinstalling my webserver after a faulty WD SSD went dead with my Ubuntu system on it... I'll signal my findings with the var_dump...

@akberlin
Copy link
Author

akberlin commented Dec 5, 2023

Hi again @adriangibbons - sorry for the late answer, not my style usually. Had some troubles buying the replacement SSD - NVMe-SSDs seem to be hard to get at the moment... server is up and running again.... sooooo:

Yep, your assumption is right. With the V2 original file created by my Edge 1040 $this->data_mesgs['record']['speed'] is null whereas with my converted V1 of that file it's an array of floats.

@adriangibbons
Copy link
Owner

@akberlin If you take a look at the arrays of data, do you see an array that looks like speed?

// Option 1. Iterate through the $pFFA->data_mesgs array
foreach ($pFFA->data_mesgs as $mesg_key => $mesg) {  // Iterate the array and output the messages
    echo "<strong>Found Message: $mesg_key</strong><br>";
    foreach ($mesg as $field_key => $field) {  // Iterate each message and output the fields
        echo " - Found Field: $mesg_key -> $field_key<br>";
    }
    echo "<br>";
}

// Option 2. Show the debug information
$pFFA->showDebugInfo();  // Quite a lot of info...

@akberlin
Copy link
Author

akberlin commented Dec 5, 2023

@adriangibbons I did both options for both files (V2 originally created, V1 converted). Seemed to be easier to render the results into a PDF (see enclosed).
Garmin Fit V1.pdf
Garmin Fit V2.pdf

@adriangibbons
Copy link
Owner

@akberlin It seems that the V1 file uses speed and altitude:
image

Whereas the V2 file uses enhanced_speed and enhanced_altitude, which are very similar but different.
image

So the code on/around line 2478 needs to be enhanced to work out which to use. Maybe something like (quick hack):

$tmp_speed = $this->data_mesgs['record']['speed'];
if ($tmp_speed === null) {
    $tmp_speed = $this->data_mesgs['record']['enhanced_speed'];
}
$is_paused[$last_ts] = end($tmp_speed) == 0 ? true : false;

/* or maybe the below in PHP >= 7.4 */
$this->data_mesgs['record']['speed'] ??= $this->data_mesgs['record']['enhanced_speed'];
$is_paused[$last_ts] = end($this->data_mesgs['record']['speed']) == 0 ? true : false;  // line 2478 unchanged, inserted the above

@adriangibbons
Copy link
Owner

I'd probably insert the below around line 1576 (i.e. the end of readDataRecords()

        // Copy enhanced_xxx fields to plain boring non-enhanced records if they're not already set.
        $this->data_mesgs['record']['speed'] ??= $this->data_mesgs['record']['enhanced_speed'];
        $this->data_mesgs['record']['altitude'] ??= $this->data_mesgs['record']['enhanced_altitude'];

@akberlin
Copy link
Author

akberlin commented Dec 6, 2023

@adriangibbons Wow. You're fast. I used your second suggestion and inserted the code right at the end of the function. This does prevent the exception from happening because speed and altitude are now filled and available. But when I try to access the session`s (and probably also lap's) avg_speed and max_speed they are NULL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants