Skip to content

Commit 3305144

Browse files
committed
fit: Added support for dynamic subfields
1 parent bc1bee1 commit 3305144

File tree

10 files changed

+429
-95
lines changed

10 files changed

+429
-95
lines changed

format/fit/README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,4 @@
1010
4. Run `npm install` if it's your first time
1111
5. Run `node index.js t /PathToSDK/Profile.xlsx > ../../mappers/types_generated.go`
1212
6. Run `node index.js m /PathToSDK/Profile.xlsx > ../../mappers/messages_generated.go`
13-
7. Edit `messages_generated.go` and remove the incorrect "Scale" from line ~461
14-
8. Correct spelling of farenheit->fahrenheit and bondary->boundary to please Go linter
13+
8. Correct formating and spelling of farenheit->fahrenheit and bondary->boundary in generated files to please Go linter

format/fit/fit.go

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,15 @@ type fileDescriptionContext struct {
7171
nativeMsgNo uint64
7272
}
7373

74+
type valueType struct {
75+
value uint64
76+
typ string
77+
}
78+
7479
type devFieldDefMap map[uint64]map[uint64]mappers.FieldDef
75-
type localFieldDefMap map[uint64]map[uint64]mappers.FieldDef
80+
type localFieldDefMap map[uint64]map[uint64]mappers.LocalFieldDef
7681
type localMsgIsDevDef map[uint64]bool
82+
type valueMap map[string]valueType
7783

7884
// "Magic" numbers
7985
const (
@@ -133,7 +139,7 @@ func fitDecodeDefinitionMessage(d *decode.D, drc *dataRecordContext, lmfd localF
133139
isDevMap[drc.localMessageType] = messageNo == developerFieldDescMesgNo
134140

135141
numFields := d.FieldU8("fields")
136-
lmfd[drc.localMessageType] = make(map[uint64]mappers.FieldDef, numFields)
142+
lmfd[drc.localMessageType] = make(map[uint64]mappers.LocalFieldDef, numFields)
137143

138144
d.FieldArray("field_definitions", func(d *decode.D) {
139145
for i := uint64(0); i < numFields; i++ {
@@ -146,18 +152,21 @@ func fitDecodeDefinitionMessage(d *decode.D, drc *dataRecordContext, lmfd localF
146152
fDefLookup, isSet := mappers.FieldDefMap[messageNo][fieldDefNo]
147153
if isSet {
148154
var foundName = fDefLookup.Name
149-
lmfd[drc.localMessageType][i] = mappers.FieldDef{
150-
Name: foundName,
151-
Type: typ,
152-
Size: size,
153-
Format: fDefLookup.Type,
154-
Unit: fDefLookup.Unit,
155-
Scale: fDefLookup.Scale,
156-
Offset: fDefLookup.Offset,
155+
lmfd[drc.localMessageType][i] = mappers.LocalFieldDef{
156+
Name: foundName,
157+
Type: typ,
158+
Size: size,
159+
Format: fDefLookup.Type,
160+
Unit: fDefLookup.Unit,
161+
Scale: fDefLookup.Scale,
162+
Offset: fDefLookup.Offset,
163+
GlobalFieldDef: fDefLookup,
164+
GlobalMessageNo: messageNo,
165+
GlobalFieldDefNo: fieldDefNo,
157166
}
158167
} else {
159168
var foundName = fmt.Sprintf("UNKNOWN_%d", fieldDefNo)
160-
lmfd[drc.localMessageType][i] = mappers.FieldDef{
169+
lmfd[drc.localMessageType][i] = mappers.LocalFieldDef{
161170
Name: foundName,
162171
Type: typ,
163172
Size: size,
@@ -181,7 +190,7 @@ func fitDecodeDefinitionMessage(d *decode.D, drc *dataRecordContext, lmfd localF
181190

182191
if isSet {
183192
var foundName = fDefLookup.Name
184-
lmfd[drc.localMessageType][i] = mappers.FieldDef{
193+
lmfd[drc.localMessageType][i] = mappers.LocalFieldDef{
185194
Name: foundName,
186195
Type: fDefLookup.Type,
187196
Size: size,
@@ -191,7 +200,7 @@ func fitDecodeDefinitionMessage(d *decode.D, drc *dataRecordContext, lmfd localF
191200
}
192201
} else {
193202
var foundName = fmt.Sprintf("UNKNOWN_%d", fieldDefNo)
194-
lmfd[drc.localMessageType][i] = mappers.FieldDef{
203+
lmfd[drc.localMessageType][i] = mappers.LocalFieldDef{
195204
Name: foundName,
196205
Type: "UNKNOWN",
197206
Size: size,
@@ -202,10 +211,9 @@ func fitDecodeDefinitionMessage(d *decode.D, drc *dataRecordContext, lmfd localF
202211
}
203212
})
204213
}
205-
206214
}
207215

208-
func fieldUint(fieldFn func(string, ...scalar.UintMapper) uint64, expectedSize uint64, fDef mappers.FieldDef, uintFormatter scalar.UintFn, fdc *fileDescriptionContext) {
216+
func fieldUint(fieldFn func(string, ...scalar.UintMapper) uint64, expectedSize uint64, fDef mappers.LocalFieldDef, uintFormatter scalar.UintFn, fdc *fileDescriptionContext, valMap valueMap) {
209217
var val uint64
210218

211219
if fDef.Size != expectedSize {
@@ -214,11 +222,33 @@ func fieldUint(fieldFn func(string, ...scalar.UintMapper) uint64, expectedSize u
214222
fieldFn(fmt.Sprintf("%s_%d", fDef.Name, i), uintFormatter)
215223
}
216224
} else {
217-
if uintFormatter != nil {
218-
val = fieldFn(fDef.Name, uintFormatter)
225+
if fDef.GlobalFieldDef.HasSubField {
226+
var found = false
227+
if subFieldValueMap, ok := mappers.SubFieldDefMap[fDef.GlobalMessageNo][fDef.GlobalFieldDefNo]; ok {
228+
for k := range subFieldValueMap {
229+
if subFieldDef, ok := subFieldValueMap[k][mappers.TypeDefMap[valMap[k].typ][valMap[k].value].Name]; ok {
230+
subUintFormatter := mappers.GetUintFormatter(mappers.LocalFieldDef{
231+
Name: subFieldDef.Name,
232+
Type: fDef.Type,
233+
Size: fDef.Size,
234+
Format: subFieldDef.Type,
235+
Unit: subFieldDef.Unit,
236+
Scale: subFieldDef.Scale,
237+
Offset: subFieldDef.Offset,
238+
})
239+
val = fieldFn(subFieldDef.Name, subUintFormatter)
240+
found = true
241+
continue
242+
}
243+
}
244+
}
245+
if !found { // SubField conditions could not be resolved
246+
val = fieldFn(fDef.Name, uintFormatter)
247+
}
219248
} else {
220-
val = fieldFn(fDef.Name)
249+
val = fieldFn(fDef.Name, uintFormatter)
221250
}
251+
valMap[fDef.Name] = valueType{value: val, typ: fDef.Format}
222252

223253
// Save developer field definitions
224254
switch fDef.Name {
@@ -236,22 +266,18 @@ func fieldUint(fieldFn func(string, ...scalar.UintMapper) uint64, expectedSize u
236266
}
237267
}
238268

239-
func fieldSint(fieldFn func(string, ...scalar.SintMapper) int64, expectedSize uint64, fDef mappers.FieldDef, sintFormatter scalar.SintFn) {
269+
func fieldSint(fieldFn func(string, ...scalar.SintMapper) int64, expectedSize uint64, fDef mappers.LocalFieldDef, sintFormatter scalar.SintFn) {
240270
if fDef.Size != expectedSize {
241271
arrayCount := fDef.Size / expectedSize
242272
for i := uint64(0); i < arrayCount; i++ {
243273
fieldFn(fmt.Sprintf("%s_%d", fDef.Name, i), sintFormatter)
244274
}
245275
} else {
246-
if sintFormatter != nil {
247-
fieldFn(fDef.Name, sintFormatter)
248-
} else {
249-
fieldFn(fDef.Name)
250-
}
276+
fieldFn(fDef.Name, sintFormatter)
251277
}
252278
}
253279

254-
func fieldFloat(fieldFn func(string, ...scalar.FltMapper) float64, expectedSize uint64, fDef mappers.FieldDef, floatFormatter scalar.FltFn) {
280+
func fieldFloat(fieldFn func(string, ...scalar.FltMapper) float64, expectedSize uint64, fDef mappers.LocalFieldDef, floatFormatter scalar.FltFn) {
255281
if fDef.Size != expectedSize {
256282
arrayCount := fDef.Size / expectedSize
257283
for i := uint64(0); i < arrayCount; i++ {
@@ -262,7 +288,7 @@ func fieldFloat(fieldFn func(string, ...scalar.FltMapper) float64, expectedSize
262288
}
263289
}
264290

265-
func fieldString(d *decode.D, fDef mappers.FieldDef, fdc *fileDescriptionContext) {
291+
func fieldString(d *decode.D, fDef mappers.LocalFieldDef, fdc *fileDescriptionContext) {
266292
val := d.FieldUTF8NullFixedLen(fDef.Name, int(fDef.Size), scalar.StrMapDescription{"": "Invalid"})
267293

268294
// Save developer field definitions
@@ -276,6 +302,7 @@ func fieldString(d *decode.D, fDef mappers.FieldDef, fdc *fileDescriptionContext
276302

277303
func fitDecodeDataMessage(d *decode.D, drc *dataRecordContext, lmfd localFieldDefMap, dmfd devFieldDefMap, isDevMap localMsgIsDevDef) {
278304
var fdc fileDescriptionContext
305+
valMap := make(valueMap, len(lmfd[drc.localMessageType]))
279306
keys := make([]int, len(lmfd[drc.localMessageType]))
280307
i := 0
281308
for k := range lmfd[drc.localMessageType] {
@@ -295,13 +322,13 @@ func fitDecodeDataMessage(d *decode.D, drc *dataRecordContext, lmfd localFieldDe
295322

296323
switch fDef.Type {
297324
case "enum", "uint8", "uint8z", "byte":
298-
fieldUint(d.FieldU8, 1, fDef, uintFormatter, &fdc)
325+
fieldUint(d.FieldU8, 1, fDef, uintFormatter, &fdc, valMap)
299326
case "uint16", "uint16z":
300-
fieldUint(d.FieldU16, 2, fDef, uintFormatter, &fdc)
327+
fieldUint(d.FieldU16, 2, fDef, uintFormatter, &fdc, valMap)
301328
case "uint32", "uint32z":
302-
fieldUint(d.FieldU32, 4, fDef, uintFormatter, &fdc)
329+
fieldUint(d.FieldU32, 4, fDef, uintFormatter, &fdc, valMap)
303330
case "uint64", "uint64z":
304-
fieldUint(d.FieldU64, 8, fDef, uintFormatter, &fdc)
331+
fieldUint(d.FieldU64, 8, fDef, uintFormatter, &fdc, valMap)
305332
case "sint8":
306333
fieldSint(d.FieldS8, 1, fDef, sintFormatter)
307334
case "sint16":

format/fit/fit.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
### Limitations
22

3-
- "compressed_speed_distance" field on globalMessageNumber 20 is not represented correctly.
3+
- Fields with subcomponents, such as "compressed_speed_distance" field on globalMessageNumber 20 is not represented correctly.
44
The field is read as 3 separate bytes where the first 12 bits are speed and the last 12 bits are distance.
55
- There are still lots of UNKOWN fields due to gaps in Garmins SDK Profile documentation. (Currently FIT SDK 21.126)
6-
- Dynamically referenced fields are named incorrectly and lacks scaling, offset and units (just raw values)
76
- Compressed timestamp messages are not accumulated against last known full timestamp.
87

98
### Convert stream of data messages to JSON array

format/fit/mappers/messages.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,26 @@ import (
55
)
66

77
type FieldDef struct {
8-
Name string
9-
Type string
10-
Format string
11-
Unit string
12-
Scale float64
13-
Offset int64
14-
Size uint64
8+
Name string
9+
Type string
10+
Unit string
11+
Scale float64
12+
Offset int64
13+
Size uint64
14+
HasSubField bool
15+
}
16+
17+
type LocalFieldDef struct {
18+
Name string
19+
Type string
20+
Format string
21+
Unit string
22+
Scale float64
23+
Offset int64
24+
Size uint64
25+
GlobalFieldDef FieldDef
26+
GlobalMessageNo uint64
27+
GlobalFieldDefNo uint64
1528
}
1629

1730
type fieldDefMap map[uint64]FieldDef

0 commit comments

Comments
 (0)