Skip to content

Instantly share code, notes, and snippets.

@aravindanve
Created March 20, 2023 14:20
Show Gist options
  • Save aravindanve/bf6c663c3f6b33055873f847cad49a73 to your computer and use it in GitHub Desktop.
Save aravindanve/bf6c663c3f6b33055873f847cad49a73 to your computer and use it in GitHub Desktop.
package main
// This script reads a modified fit file (source.fit) and computes the correct
// crc16 value and writes the output to a new file (output.fit)
import (
"encoding/binary"
"encoding/hex"
"fmt"
"io"
"log"
"os"
"strconv"
)
// https://developer.garmin.com/fit/protocol/#crc
func getFitCRC16(crc uint16, b uint8) uint16 {
var crc_table = []uint16{
0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400,
}
var tmp uint16
// compute checksum of lower four bits of byte
tmp = crc_table[crc&0xF]
crc = (crc >> 4) & 0x0FFF
crc = crc ^ tmp ^ crc_table[b&0xF]
// now compute checksum of upper four bits of byte
tmp = crc_table[crc&0xF]
crc = (crc >> 4) & 0x0FFF
crc = crc ^ tmp ^ crc_table[(b>>4)&0xF]
return crc
}
func main() {
// open source src
// source.fit is the modified fit file with bad crc
src, err := os.Open("source.fit")
if err != nil {
fmt.Println("Error opening source file! " + err.Error())
}
defer src.Close()
srcStat, err := src.Stat()
if err != nil {
fmt.Println("Error reading source file! " + err.Error())
}
srcSize := srcStat.Size()
srcCrcB := []byte{}
outSize := int64(0)
// open output file
// output.fit is the modified fit file with computed crc
out, err := os.Create("output.fit")
if err != nil {
fmt.Println("Error opening output file! " + err.Error())
}
defer out.Close()
// create buffer
buf := make([]byte, 1)
var crc uint16
for {
_, err := src.Read(buf)
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
break
}
// only process bytes before crc
if outSize < srcSize-2 {
_, err = out.Write(buf)
if err != nil {
log.Fatal(err)
}
crc = getFitCRC16(crc, buf[0])
outSize++
} else {
srcCrcB = append(srcCrcB, buf[0])
}
}
outCrcB := []byte{}
outCrcB = binary.LittleEndian.AppendUint16(outCrcB, crc)
// write crc to output
_, err = out.Write(outCrcB)
if err != nil {
log.Fatal(err)
}
outSize += 2
fmt.Println("src size: " + strconv.FormatInt(srcSize, 10))
fmt.Println("src crc16: " + hex.EncodeToString(srcCrcB))
fmt.Println("out size: " + strconv.FormatInt(outSize, 10))
fmt.Println("out crc16: " + hex.EncodeToString(outCrcB))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment