You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
3.4 KiB
138 lines
3.4 KiB
|
4 days ago
|
import { BaseInterface } from "./base";
|
||
|
|
import { BaseService, BaseCharacteritic, BaseApplication } from "./bluez-gatt";
|
||
|
|
|
||
|
|
export class FTMSService extends BaseService {
|
||
|
|
UUID = "00001826-0000-1000-8000-00805f9b34fb";
|
||
|
|
Primary = true;
|
||
|
|
|
||
|
|
constructor(bus, path) {
|
||
|
|
super(bus, path);
|
||
|
|
this.addCharacteristic(new FTMSFeature(bus, this.path + "/char0", this));
|
||
|
|
this.addCharacteristic(new IndoorBikeData(bus, this.path + "/char1", this));
|
||
|
|
this.addCharacteristic(
|
||
|
|
new FTMSControlPoint(bus, this.path + "/char2", this)
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class FTMSFeature extends BaseCharacteritic {
|
||
|
|
constructor(bus, path, service) {
|
||
|
|
super(bus, path, service, "00002acc-0000-1000-8000-00805f9b34fb", ["read"]);
|
||
|
|
}
|
||
|
|
|
||
|
|
read() {
|
||
|
|
console.log("read FTMS Feature");
|
||
|
|
// 32bits features + 32bits target supported
|
||
|
|
// 0x0a 0x44 = feature: cadence (1), inclinaison (3), hr (10), power (14)
|
||
|
|
// 0x0a 0x20 = target: inclinaison (1), power (3), simulation parameters (13)
|
||
|
|
return [0x0a, 0x44, 0x00, 0x00, 0x0a, 0x20, 0x00, 0x00];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class FTMSControlPoint extends BaseCharacteritic {
|
||
|
|
wind = 0;
|
||
|
|
grade = 0;
|
||
|
|
crr = 0;
|
||
|
|
cw = 0;
|
||
|
|
|
||
|
|
constructor(bus, path, service) {
|
||
|
|
super(bus, path, service, "00002ad9-0000-1000-8000-00805f9b34fb", [
|
||
|
|
"write",
|
||
|
|
"indicate",
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
write(value, options) {
|
||
|
|
console.log("FTMS Write Control Point");
|
||
|
|
console.log(value);
|
||
|
|
const arraybuf = value.buffer.slice(
|
||
|
|
value.byteOffset,
|
||
|
|
value.byteOffset + value.byteLength
|
||
|
|
);
|
||
|
|
const view = new DataView(arraybuf);
|
||
|
|
|
||
|
|
if (value[0] === 0x00) {
|
||
|
|
// take control
|
||
|
|
this.notify([0x80, 0x00, 0x01]);
|
||
|
|
} else if (value[0] === 0x01) {
|
||
|
|
// reset machine
|
||
|
|
this.notify([0x80, 0x01, 0x01]);
|
||
|
|
} else if (value[0] === 0x07) {
|
||
|
|
// start/resume
|
||
|
|
this.notify([0x80, 0x07, 0x01]);
|
||
|
|
} else if (value[0] === 0x11) {
|
||
|
|
// set simulations param (wind, grade, etc)
|
||
|
|
const wind = view.getInt16(1, true);
|
||
|
|
const grade = view.getInt16(3, true);
|
||
|
|
const crr = view.getUint8(5);
|
||
|
|
const cw = view.getUint8(6);
|
||
|
|
|
||
|
|
this.wind = wind * 0.001;
|
||
|
|
this.grade = grade * 0.01;
|
||
|
|
this.crr = crr * 0.001;
|
||
|
|
this.cw = cw * 0.01;
|
||
|
|
|
||
|
|
console.log(wind * 0.001);
|
||
|
|
console.log(grade * 0.01);
|
||
|
|
console.log(crr * 0.0001);
|
||
|
|
console.log(cw * 0.01);
|
||
|
|
|
||
|
|
this.notify([0x80, 0x11, 0x01]);
|
||
|
|
} else {
|
||
|
|
console.log("FTMS Control point op code " + value[0] + "not supported");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
startNotify() {
|
||
|
|
console.log("FTMS Start Notify CP");
|
||
|
|
}
|
||
|
|
|
||
|
|
stopNotify() {
|
||
|
|
console.log("FTMS Stop Notify CP");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class IndoorBikeData extends BaseCharacteritic {
|
||
|
|
constructor(bus, path, service) {
|
||
|
|
super(bus, path, service, "00002ad2-0000-1000-8000-00805f9b34fb", [
|
||
|
|
"notify",
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
startNotify() {
|
||
|
|
if (this.Notifying) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
this.Notifying = true;
|
||
|
|
|
||
|
|
this.interval = setInterval(() => {
|
||
|
|
console.log("FTMS Notif Indoor Bike");
|
||
|
|
// 0x44 0x02 = fields included: cadence (2), power (6), hr (9)
|
||
|
|
// 0x00 0x00 = average speed, always included
|
||
|
|
// cadence is *2 (resolution 0.5 s^-1)
|
||
|
|
this.notify([
|
||
|
|
0x44,
|
||
|
|
0x02,
|
||
|
|
0x00,
|
||
|
|
0x00,
|
||
|
|
Math.round(160 + Math.random() * 10),
|
||
|
|
0x00,
|
||
|
|
Math.round(160 + Math.random() * 40),
|
||
|
|
0x00,
|
||
|
|
Math.round(120 + Math.random() * 10),
|
||
|
|
]);
|
||
|
|
}, 1000);
|
||
|
|
}
|
||
|
|
|
||
|
|
stopNotify() {
|
||
|
|
if (!this.Notifying) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
this.Notifying = false;
|
||
|
|
|
||
|
|
clearInterval(this.interval);
|
||
|
|
}
|
||
|
|
}
|