6 changed files with 318 additions and 87 deletions
@ -1,21 +1,28 @@
@@ -1,21 +1,28 @@
|
||||
import { BaseInterface } from "./base"; |
||||
import dbus from "dbus-next"; |
||||
import dbus, { interface as iface } from "dbus-next"; |
||||
const { property, method } = iface; |
||||
|
||||
export class Advertisement extends BaseInterface { |
||||
@dbus.interface.property({ signature: "s" }) |
||||
@property({ signature: "s" }) |
||||
Type = "peripheral"; |
||||
|
||||
@dbus.interface.property({ signature: "s" }) |
||||
@property({ signature: "s" }) |
||||
LocalName = "TestDevice"; |
||||
|
||||
@dbus.interface.property({ signature: "as" }) |
||||
ServiceUUIDs = ["139fc001-a4ed-11ed-b9df-0242ac120003"]; |
||||
//ServiceUUIDs = ["1816", "1818", "1826"];
|
||||
@property({ signature: "as" }) |
||||
ServiceUUIDs = []; |
||||
|
||||
@dbus.interface.method({ inSignature: "", outSignature: "" }) |
||||
@property({ signature: "a{sv}" }) |
||||
ServiceData = { 1826: new dbus.Variant("ay", [0x01, 0x20, 0x00]) }; |
||||
|
||||
@property({ signature: "as" }) |
||||
Includes = ["tx-power"]; |
||||
|
||||
@method({ inSignature: "", outSignature: "" }) |
||||
Release() {} |
||||
|
||||
constructor(bus, path) { |
||||
constructor(bus, path, uuids) { |
||||
super(bus, path, "org.bluez.LEAdvertisement1"); |
||||
this.ServiceUUIDs = uuids; |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,137 @@
@@ -0,0 +1,137 @@
|
||||
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); |
||||
} |
||||
} |
||||
@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
import { BaseInterface } from "./base"; |
||||
import { BaseService, BaseCharacteritic, BaseApplication } from "./bluez-gatt"; |
||||
|
||||
export class HRService extends BaseService { |
||||
UUID = "0000180d-0000-1000-8000-00805f9b34fb"; |
||||
Primary = true; |
||||
|
||||
constructor(bus, path) { |
||||
super(bus, path); |
||||
this.addCharacteristic(new HRMeasure(bus, this.path + "/char0", this)); |
||||
//this.addCharacteristic(new WriteChar(bus, "/eu/atoy/hrservice/char1", this));
|
||||
//this.addCharacteristic(new NotifChar(bus, "/eu/atoy/hrservice/char2", this));
|
||||
} |
||||
} |
||||
|
||||
class HRMeasure extends BaseCharacteritic { |
||||
constructor(bus, path, service) { |
||||
super(bus, path, service, "00002a37-0000-1000-8000-00805f9b34fb", [ |
||||
"notify", |
||||
]); |
||||
} |
||||
|
||||
startNotify() { |
||||
if (this.Notifying) { |
||||
return; |
||||
} |
||||
|
||||
this.Notifying = true; |
||||
|
||||
this.interval = setInterval(() => { |
||||
console.log("HR Notify"); |
||||
this.notify([0x06, Math.round(120 + Math.random() * 10)]); |
||||
}, 1000); |
||||
} |
||||
|
||||
stopNotify() { |
||||
if (!this.Notifying) { |
||||
return; |
||||
} |
||||
|
||||
this.Notifying = false; |
||||
|
||||
clearInterval(this.interval); |
||||
} |
||||
} |
||||
@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
import { BaseInterface } from "./base"; |
||||
import { BaseService, BaseCharacteritic, BaseApplication } from "./bluez-gatt"; |
||||
|
||||
export class PWRService extends BaseService { |
||||
UUID = "00001818-0000-1000-8000-00805f9b34fb"; |
||||
Primary = true; |
||||
|
||||
constructor(bus, path) { |
||||
super(bus, path); |
||||
this.addCharacteristic(new PWRMeasure(bus, this.path + "/char0", this)); |
||||
//this.addCharacteristic(new WriteChar(bus, "/eu/atoy/hrservice/char1", this));
|
||||
//this.addCharacteristic(new NotifChar(bus, "/eu/atoy/hrservice/char2", this));
|
||||
} |
||||
} |
||||
|
||||
class PWRMeasure extends BaseCharacteritic { |
||||
constructor(bus, path, service) { |
||||
super(bus, path, service, "00002a63-0000-1000-8000-00805f9b34fb", [ |
||||
"notify", |
||||
]); |
||||
} |
||||
|
||||
startNotify() { |
||||
if (this.Notifying) { |
||||
return; |
||||
} |
||||
|
||||
this.Notifying = true; |
||||
|
||||
this.interval = setInterval(() => { |
||||
console.log("Power Notify"); |
||||
this.notify([0x00, 0x00, Math.round(170 + Math.random() * 30), 0x00]); |
||||
}, 1000); |
||||
} |
||||
|
||||
stopNotify() { |
||||
if (!this.Notifying) { |
||||
return; |
||||
} |
||||
|
||||
this.Notifying = false; |
||||
|
||||
clearInterval(this.interval); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue