grimbough / FITfileR

R package for reading data from FIT files using only native R code, rather than relying on external libraries.
https://msmith.de/FITfileR
50 stars 13 forks source link

Another object 'res' not found error #41

Closed sje30 closed 4 months ago

sje30 commented 4 months ago

hi again Mike!

trying this with another device (this time my watch, a Coros pace 3).

> file <- "/Users/stephen/Downloads/460155033541967877.fit"
> run <- readFitFile(file)
Error in (function (fieldType, sizes, definition, con)  : 
  object 'res' not found
> traceback()
5: (function (fieldType, sizes, definition, con) 
   {
       if (definition@is_little_endian) {
           endian <- "little"
       }
       else {
           endian <- "big"
       }
       readInfo <- data_type_lookup[[fieldType]]
       single_size <- prod(readInfo$size, readInfo$n)
       n_values <- sizes%/%single_size
       if (fieldType == 8L) {
           suppressWarnings(res <- readChar(con = con, nchars = n_values, 
               useBytes = TRUE))
       }
       else {
           for (j in seq_len(n_values)) {
               dat <- readBin(con, what = readInfo$what, signed = readInfo$signed, 
                   size = readInfo$size, n = readInfo$n, endian = endian)
               if (fieldType == 7L || fieldType == 13L) {
                   if (definition@is_little_endian) {
                     bits <- as.logical(rawToBits(dat[1:4]))
                   }
                   else {
                     bits <- as.logical(rawToBits(dat[4:1]))
                   }
                   dat <- sum(2^(.subset(0:31, bits)))
               }
               else if (fieldType == 14L) {
                   dat <- as.integer(dat)
               }
               else if (fieldType %in% c(15L, 16L)) {
                   dat <- .rawToInt64(raw = dat)
               }
               if (n_values == 1) {
                   res <- dat
               }
               else {
                   if (j == 1) {
                     res <- list(dat)
                   }
                   else {
                     res[[1]] <- c(res[[1]], dat)
                   }
               }
           }
       }
       return(res)
   })(dots[[1L]][[5L]], dots[[2L]][[5L]], definition = new("FitDefinitionMessage", 
       header = as.raw(0x40), is_little_endian = TRUE, global_message_number = 21L, 
       field_defs = list(field_def_num = c(253L, 0L, 1L, 4L, 3L), 
           size = c(4L, 1L, 1L, 1L, 1L), base_type = c(6L, 0L, 0L, 
           2L, 6L)), dev_field_defs = NULL), con = structure(3L, class = c("file", 
   "connection"), conn_id = <pointer: 0x206>))
4: mapply(FUN = .readFields, fieldTypes, sizes, MoreArgs = list(definition = definition, 
       con = con), SIMPLIFY = FALSE, USE.NAMES = FALSE)
3: .readMessage_data(con = con, header = record_header, definition = definition)
2: .readFile(fileName, preallocate = TRUE)
1: readFitFile(file)
> 

the file is attached in a zip again. It opens okay in https://www.fitfileviewer.com

Screenshot 2024-04-27 at 20 36 14

coros.zip

grimbough commented 4 months ago

Thanks Steven. As you noted this was also reported in #38 with another file from a Coros watch. It seems the 'start' event i.e. when you press start on the watch, has a data field that doesn't actually contain any values. It claims to be a UINT32 but also states it's of size 1 bytes. The package was hitting that inconsistency and didn't know what to do, hence the missing res object. It will now read the single byte and that seems sufficient to proceed with the rest of the file.

Since these two characteristics are inconsistent it's not clear what to do with the data, so for now I've included an NA value in this place as you can see below.

library(FITfileR)

## download and extract the example file
destfile = tempfile(fileext = ".zip")
url = "https://github.com/grimbough/FITfileR/files/15139616/coros.zip"
dl = download.file(url = url, destfile = destfile)
example_file = unzip(destfile, exdir = tempdir())

## read and extract the events
fitFile <- readFitFile(example_file[1])
events(fitFile)
#> $event_1
#> # A tibble: 3 × 4
#>   timestamp           event event_type event_group
#>   <dttm>              <chr> <chr>            <int>
#> 1 2024-04-27 08:07:54 timer start                0
#> 2 2024-04-27 08:32:51 timer stop_all             0
#> 3 2024-04-27 08:32:53 timer stop_all             0
#> 
#> $event_2
#> # A tibble: 1 × 5
#>   timestamp           event event_type event_group data 
#>   <dttm>              <chr> <chr>            <int> <lgl>
#> 1 2024-04-27 08:32:53 timer start                0 NA