-
Notifications
You must be signed in to change notification settings - Fork 4
/
keiserParser.js
102 lines (88 loc) · 3.27 KB
/
keiserParser.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//exact copy of repo
global.atob = require("atob");
const encodeStringToBytes = (rawString) => {
let data = atob(rawString)
let bytes = new Uint8Array(data.length)
for (let i = 0; i < bytes.length; i++) {
bytes[i] = data.charCodeAt(i)
}
return bytes
}
const getAdvertisingData = (response) => {
let advertisingData;
if (typeof response.advertisement !== 'string') {
let advertisement = encodeStringToBytes(response.advertisement.manufacturerData)
advertisingData = [].slice.call(advertisement, 2)
} else {
let advertisement = encodeStringToBytes(response.advertisement)
if (advertisement.length > 17) {
advertisingData = [].slice.call(advertisement, 11)
} else {
advertisingData = Array.from(advertisement)
}
}
return advertisingData
}
const buildValueConvert = (value) => {
return parseInt(value.toString(16), 10)
}
const twoByteConcat = (lower, higher) => {
return (higher << 8) | lower
}
var parseAdvertisement = function(response) {
let data = getAdvertisingData(response)
let broadcast = {
takenAt: (new Date()).getTime(),
ordinalId: 0,
buildMajor: 0,
buildMinor: 0,
interval: 0,
realTime: false,
cadence: 0,
ftmscadence: 0,
heartRate: 0,
power: 0,
caloricBurn: 0,
duration: 0,
gear: null,
distance: 0
}
let index = 0
broadcast.buildMajor = buildValueConvert(data[index++])
if (broadcast.buildMajor !== 6) {
throw new Error('Invalid build major')
}
broadcast.buildMinor = buildValueConvert(data[index++])
if (broadcast.buildMajor === 6 && data.length > (index + 13)) {
let dataType = data[index]
if (dataType === 0 || dataType === 255) {
broadcast.interval = 0
} else if (dataType > 128 && dataType < 255) {
broadcast.interval = dataType - 128
}
broadcast.realTime = dataType === 0 || (dataType > 128 && dataType < 255)
broadcast.ordinalId = data[index + 1]
if (broadcast.ordinalId < 0 || broadcast.ordinalId > 200) {
throw new Error('Invalid machine id')
}
broadcast.cadence = Math.round(twoByteConcat(data[index + 2], data[index + 3]) / 10) // reduce to 1 rpm resolution from 0.1 reported by M3i
broadcast.ftmscadence = Math.round(twoByteConcat(data[index + 2], data[index + 3]) / 5) // FTMS expects 0.5 rpm resolution
broadcast.heartRate = Math.round(twoByteConcat(data[index + 4], data[index + 5]) / 10) || null
broadcast.power = twoByteConcat(data[index + 6], data[index + 7])
broadcast.caloricBurn = twoByteConcat(data[index + 8], data[index + 9])
broadcast.duration = data[index + 10] * 60 + data[index + 11]
broadcast.distance = twoByteConcat(data[index + 12], data[index + 13])
if ((broadcast.distance & 32768) !== 0) {
// Metric
broadcast.distance = broadcast.distance / 10
} else {
// Imperial (to Metric)
broadcast.distance = ((broadcast.distance & 32767) / 10) * 1.60934
}
if (broadcast.buildMinor >= 21 && data.length > (index + 14)) {
broadcast.gear = data[index + 14]
}
}
return broadcast
}
module.exports.parseAdvertisement = parseAdvertisement