forked from espruino/BangleApps
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ble_advert.ts
136 lines (121 loc) · 3.98 KB
/
ble_advert.ts
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
declare let exports: any;
//declare let BLE_DEBUG: undefined | true;
type BleAdvertObj = { [key: string | number]: number[] };
type BleAdvert = BleAdvertObj | number[];
type BangleWithAdvert = (typeof Bangle) & { bleAdvert?: BleAdvert | BleAdvert[]; };
type SetAdvertisingOptions = typeof NRF.setAdvertising extends (data: any, options: infer Opts) => any ? Opts : never;
const advertise = (options: SetAdvertisingOptions) => {
const clone = (obj: any): any => {
// just for our use-case
if(Array.isArray(obj)){
return obj.map(clone);
}else if(typeof obj === "object"){
const r = {};
for(const k in obj){
// @ts-expect-error implicitly
r[k] = clone(obj[k]);
}
return r;
}
return obj;
};
// clone the object, to avoid firmware behaving like so:
// bleAdvert = [Uint8Array, { [0x180f]: ... }]
// ^ ^
// | |
// | +- added by this call
// +- modified from a previous setAdvertising()
//
// The firmware (jswrap_ble_setAdvertising) will convert arrays within
// the advertising array to Uint8Array, but if this has already been done,
// we get iterator errors. So we clone the object to avoid these mutations
// taking effect for later calls.
//
// This also allows us to identify previous adverts correctly by id.
NRF.setAdvertising(clone((Bangle as BangleWithAdvert).bleAdvert), options);
};
const manyAdv = (bleAdvert: BleAdvert | BleAdvert[] | undefined): bleAdvert is BleAdvert[] => {
return Array.isArray(bleAdvert) && typeof bleAdvert[0] === "object";
};
exports.set = (id: string | number, advert: number[], options?: SetAdvertisingOptions) => {
const bangle = Bangle as BangleWithAdvert;
if(manyAdv(bangle.bleAdvert)){
let found = false;
let obj;
for(let ad of bangle.bleAdvert){
if(Array.isArray(ad)) continue;
obj = ad;
if(ad[id]){
ad[id] = advert;
found = true;
// if(typeof BLE_DEBUG !== "undefined")
// console.log(`bleAdvert is array, found existing entry for ${id}, replaced`)
break;
}
}
if(!found){
if(obj)
obj[id] = advert;
else
bangle.bleAdvert.push({ [id]: advert });
// if(typeof BLE_DEBUG !== "undefined")
// console.log(`bleAdvert is array, no entry for ${id}, created`)
}
}else if(bangle.bleAdvert){
// if(typeof BLE_DEBUG !== "undefined")
// console.log(`bleAdvert is object, ${id} entry ${id in bangle.bleAdvert ? "replaced" : "created"}`);
if(Array.isArray(bangle.bleAdvert)){
bangle.bleAdvert = [bangle.bleAdvert, { [id]: advert }];
}else{
bangle.bleAdvert[id] = advert;
}
}else{
// if(typeof BLE_DEBUG !== "undefined")
// console.log(`bleAdvert not present, created`);
bangle.bleAdvert = { [id]: advert };
}
// if(typeof BLE_DEBUG !== "undefined")
// console.log(`NRF.setAdvertising({ ${Object.keys(bangle.bleAdvert).join(", ")} }, ${JSON.stringify(options)})`);
advertise(options);
};
exports.push = (adv: number[], options?: SetAdvertisingOptions) => {
const bangle = Bangle as BangleWithAdvert;
if(manyAdv(bangle.bleAdvert)){
bangle.bleAdvert.push(adv);
}else if(bangle.bleAdvert){
bangle.bleAdvert = [bangle.bleAdvert, adv];
}else{
// keep a second entry for normal/original advertising as well as this extra one
bangle.bleAdvert = [adv, {}];
}
advertise(options);
};
/*
exports.remove = (id: string | number, options?: SetAdvertisingOptions) => {
const bangle = Bangle as BangleWithAdvert;
// if(typeof BLE_DEBUG !== "undefined")
// console.log(`ble_advert.remove(${id}, ${JSON.stringify(options)})`);
if(manyAdv(bangle.bleAdvert)){
let i = 0;
for(const ad of bangle.bleAdvert){
if(Array.isArray(ad)) continue;
if(ad[id]){
delete ad[id];
let empty = true;
// eslint-disable-next-line no-unused-vars
for(const _ in ad){
empty = false;
break;
}
if(empty) bangle.bleAdvert.splice(i, 1);
break;
}
i++;
}
}else if(bangle.bleAdvert){
if(!Array.isArray(bangle.bleAdvert))
delete bangle.bleAdvert[id];
}
advertise(options);
};
*/