@neurosity/sdk 6.3.0 → 6.4.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/neurosity.iife.js +1550 -1536
- package/dist/browser/neurosity.js +15 -15
- package/dist/browser/neurosity.js.map +1 -1
- package/dist/cjs/Neurosity.d.ts +5 -0
- package/dist/cjs/Neurosity.js +20 -6
- package/dist/cjs/api/bluetooth/BluetoothClient.d.ts +2 -0
- package/dist/cjs/api/bluetooth/BluetoothClient.js +35 -30
- package/dist/cjs/api/bluetooth/BluetoothTransport.d.ts +2 -2
- package/dist/cjs/api/bluetooth/react-native/ReactNativeTransport.d.ts +2 -3
- package/dist/cjs/api/bluetooth/react-native/ReactNativeTransport.js +37 -45
- package/dist/cjs/api/bluetooth/utils/osHasBluetoothSupport.d.ts +2 -2
- package/dist/cjs/api/bluetooth/utils/osHasBluetoothSupport.js +4 -2
- package/dist/cjs/api/bluetooth/web/WebBluetoothTransport.d.ts +2 -3
- package/dist/cjs/api/bluetooth/web/WebBluetoothTransport.js +35 -41
- package/dist/cjs/api/index.d.ts +3 -1
- package/dist/cjs/api/index.js +4 -0
- package/dist/electron/index.js +10 -10
- package/dist/electron/index.js.map +1 -1
- package/dist/esm/Neurosity.d.ts +5 -0
- package/dist/esm/Neurosity.js +20 -6
- package/dist/esm/api/bluetooth/BluetoothClient.d.ts +2 -0
- package/dist/esm/api/bluetooth/BluetoothClient.js +36 -31
- package/dist/esm/api/bluetooth/BluetoothTransport.d.ts +2 -2
- package/dist/esm/api/bluetooth/react-native/ReactNativeTransport.d.ts +2 -3
- package/dist/esm/api/bluetooth/react-native/ReactNativeTransport.js +33 -41
- package/dist/esm/api/bluetooth/utils/osHasBluetoothSupport.d.ts +2 -2
- package/dist/esm/api/bluetooth/utils/osHasBluetoothSupport.js +4 -2
- package/dist/esm/api/bluetooth/web/WebBluetoothTransport.d.ts +2 -3
- package/dist/esm/api/bluetooth/web/WebBluetoothTransport.js +33 -39
- package/dist/esm/api/index.d.ts +3 -1
- package/dist/esm/api/index.js +4 -0
- package/dist/esm/neurosity.mjs +1550 -1536
- package/dist/examples/neurosity.iife.js +1550 -1536
- package/dist/examples/neurosity.js +15 -15
- package/dist/examples/neurosity.mjs +1550 -1536
- package/package.json +1 -1
|
@@ -43004,6 +43004,7 @@ class CloudClient {
|
|
|
43004
43004
|
this.firebaseUser = new FirebaseUser(this.firebaseApp);
|
|
43005
43005
|
this._selectedDevice.next(undefined);
|
|
43006
43006
|
this.status$ = heartbeatAwareStatus(this.observeNamespace("status").pipe(share())).pipe(filterInternalKeys(), shareReplay(1));
|
|
43007
|
+
this.osVersion$ = this.observeNamespace("info/osVersion").pipe(shareReplay(1));
|
|
43007
43008
|
this.firebaseUser.onAuthStateChanged().subscribe((user) => {
|
|
43008
43009
|
this.user = user;
|
|
43009
43010
|
});
|
|
@@ -43037,6 +43038,9 @@ class CloudClient {
|
|
|
43037
43038
|
.asObservable()
|
|
43038
43039
|
.pipe(filter((value) => value !== undefined));
|
|
43039
43040
|
}
|
|
43041
|
+
osVersion() {
|
|
43042
|
+
return this.osVersion$;
|
|
43043
|
+
}
|
|
43040
43044
|
// Automatically select device when user logs in
|
|
43041
43045
|
setAutoSelectedDevice() {
|
|
43042
43046
|
return __awaiter$b(this, void 0, void 0, function* () {
|
|
@@ -45747,577 +45751,412 @@ const DEFAULT_ACTION_RESPONSE_TIMEOUT = 1000 * 60; // 1 minute
|
|
|
45747
45751
|
// Reverse BLUETOOTH_CHARACTERISTICS key/values for easy lookup
|
|
45748
45752
|
const CHARACTERISTIC_UUIDS_TO_NAMES = Object.fromEntries(Object.entries(BLUETOOTH_CHARACTERISTICS).map((entries) => entries.reverse()));
|
|
45749
45753
|
|
|
45750
|
-
|
|
45751
|
-
|
|
45752
|
-
|
|
45753
|
-
|
|
45754
|
-
|
|
45755
|
-
) ? (
|
|
45756
|
-
|
|
45757
|
-
|
|
45758
|
-
var debug_1 = debug;
|
|
45759
|
-
|
|
45760
|
-
// Note: this is the semver.org version of the spec that it implements
|
|
45761
|
-
// Not necessarily the package version of this code.
|
|
45762
|
-
const SEMVER_SPEC_VERSION = '2.0.0';
|
|
45763
|
-
|
|
45764
|
-
const MAX_LENGTH = 256;
|
|
45765
|
-
const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||
|
|
45766
|
-
/* istanbul ignore next */ 9007199254740991;
|
|
45767
|
-
|
|
45768
|
-
// Max safe segment length for coercion.
|
|
45769
|
-
const MAX_SAFE_COMPONENT_LENGTH = 16;
|
|
45770
|
-
|
|
45771
|
-
var constants = {
|
|
45772
|
-
SEMVER_SPEC_VERSION,
|
|
45773
|
-
MAX_LENGTH,
|
|
45774
|
-
MAX_SAFE_INTEGER,
|
|
45775
|
-
MAX_SAFE_COMPONENT_LENGTH,
|
|
45754
|
+
var __awaiter$d = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
45755
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
45756
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
45757
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
45758
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
45759
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
45760
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
45761
|
+
});
|
|
45776
45762
|
};
|
|
45777
|
-
|
|
45778
|
-
|
|
45779
|
-
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
|
45780
|
-
}
|
|
45781
|
-
|
|
45782
|
-
var re_1 = createCommonjsModule(function (module, exports) {
|
|
45783
|
-
const { MAX_SAFE_COMPONENT_LENGTH } = constants;
|
|
45784
|
-
|
|
45785
|
-
exports = module.exports = {};
|
|
45786
|
-
|
|
45787
|
-
// The actual regexps go on exports.re
|
|
45788
|
-
const re = exports.re = [];
|
|
45789
|
-
const src = exports.src = [];
|
|
45790
|
-
const t = exports.t = {};
|
|
45791
|
-
let R = 0;
|
|
45792
|
-
|
|
45793
|
-
const createToken = (name, value, isGlobal) => {
|
|
45794
|
-
const index = R++;
|
|
45795
|
-
debug_1(name, index, value);
|
|
45796
|
-
t[name] = index;
|
|
45797
|
-
src[index] = value;
|
|
45798
|
-
re[index] = new RegExp(value, isGlobal ? 'g' : undefined);
|
|
45763
|
+
const defaultOptions$1 = {
|
|
45764
|
+
autoConnect: true
|
|
45799
45765
|
};
|
|
45800
|
-
|
|
45801
|
-
|
|
45802
|
-
|
|
45803
|
-
|
|
45804
|
-
|
|
45805
|
-
|
|
45806
|
-
|
|
45807
|
-
|
|
45808
|
-
|
|
45809
|
-
|
|
45810
|
-
|
|
45811
|
-
|
|
45812
|
-
|
|
45813
|
-
|
|
45814
|
-
|
|
45815
|
-
|
|
45816
|
-
|
|
45817
|
-
|
|
45818
|
-
|
|
45819
|
-
|
|
45820
|
-
|
|
45821
|
-
|
|
45822
|
-
|
|
45823
|
-
|
|
45824
|
-
|
|
45825
|
-
|
|
45826
|
-
|
|
45827
|
-
|
|
45828
|
-
// A numeric identifier, or a non-numeric identifier.
|
|
45829
|
-
|
|
45830
|
-
createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NUMERICIDENTIFIER]
|
|
45831
|
-
}|${src[t.NONNUMERICIDENTIFIER]})`);
|
|
45832
|
-
|
|
45833
|
-
createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NUMERICIDENTIFIERLOOSE]
|
|
45834
|
-
}|${src[t.NONNUMERICIDENTIFIER]})`);
|
|
45835
|
-
|
|
45836
|
-
// ## Pre-release Version
|
|
45837
|
-
// Hyphen, followed by one or more dot-separated pre-release version
|
|
45838
|
-
// identifiers.
|
|
45839
|
-
|
|
45840
|
-
createToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER]
|
|
45841
|
-
}(?:\\.${src[t.PRERELEASEIDENTIFIER]})*))`);
|
|
45842
|
-
|
|
45843
|
-
createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]
|
|
45844
|
-
}(?:\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`);
|
|
45845
|
-
|
|
45846
|
-
// ## Build Metadata Identifier
|
|
45847
|
-
// Any combination of digits, letters, or hyphens.
|
|
45848
|
-
|
|
45849
|
-
createToken('BUILDIDENTIFIER', '[0-9A-Za-z-]+');
|
|
45850
|
-
|
|
45851
|
-
// ## Build Metadata
|
|
45852
|
-
// Plus sign, followed by one or more period-separated build metadata
|
|
45853
|
-
// identifiers.
|
|
45854
|
-
|
|
45855
|
-
createToken('BUILD', `(?:\\+(${src[t.BUILDIDENTIFIER]
|
|
45856
|
-
}(?:\\.${src[t.BUILDIDENTIFIER]})*))`);
|
|
45857
|
-
|
|
45858
|
-
// ## Full Version String
|
|
45859
|
-
// A main version, followed optionally by a pre-release version and
|
|
45860
|
-
// build metadata.
|
|
45861
|
-
|
|
45862
|
-
// Note that the only major, minor, patch, and pre-release sections of
|
|
45863
|
-
// the version string are capturing groups. The build metadata is not a
|
|
45864
|
-
// capturing group, because it should not ever be used in version
|
|
45865
|
-
// comparison.
|
|
45866
|
-
|
|
45867
|
-
createToken('FULLPLAIN', `v?${src[t.MAINVERSION]
|
|
45868
|
-
}${src[t.PRERELEASE]}?${
|
|
45869
|
-
src[t.BUILD]}?`);
|
|
45870
|
-
|
|
45871
|
-
createToken('FULL', `^${src[t.FULLPLAIN]}$`);
|
|
45872
|
-
|
|
45873
|
-
// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
|
|
45874
|
-
// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
|
|
45875
|
-
// common in the npm registry.
|
|
45876
|
-
createToken('LOOSEPLAIN', `[v=\\s]*${src[t.MAINVERSIONLOOSE]
|
|
45877
|
-
}${src[t.PRERELEASELOOSE]}?${
|
|
45878
|
-
src[t.BUILD]}?`);
|
|
45879
|
-
|
|
45880
|
-
createToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`);
|
|
45881
|
-
|
|
45882
|
-
createToken('GTLT', '((?:<|>)?=?)');
|
|
45883
|
-
|
|
45884
|
-
// Something like "2.*" or "1.2.x".
|
|
45885
|
-
// Note that "x.x" is a valid xRange identifer, meaning "any version"
|
|
45886
|
-
// Only the first item is strictly required.
|
|
45887
|
-
createToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`);
|
|
45888
|
-
createToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\*`);
|
|
45889
|
-
|
|
45890
|
-
createToken('XRANGEPLAIN', `[v=\\s]*(${src[t.XRANGEIDENTIFIER]})` +
|
|
45891
|
-
`(?:\\.(${src[t.XRANGEIDENTIFIER]})` +
|
|
45892
|
-
`(?:\\.(${src[t.XRANGEIDENTIFIER]})` +
|
|
45893
|
-
`(?:${src[t.PRERELEASE]})?${
|
|
45894
|
-
src[t.BUILD]}?` +
|
|
45895
|
-
`)?)?`);
|
|
45896
|
-
|
|
45897
|
-
createToken('XRANGEPLAINLOOSE', `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` +
|
|
45898
|
-
`(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +
|
|
45899
|
-
`(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +
|
|
45900
|
-
`(?:${src[t.PRERELEASELOOSE]})?${
|
|
45901
|
-
src[t.BUILD]}?` +
|
|
45902
|
-
`)?)?`);
|
|
45903
|
-
|
|
45904
|
-
createToken('XRANGE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`);
|
|
45905
|
-
createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`);
|
|
45906
|
-
|
|
45907
|
-
// Coercion.
|
|
45908
|
-
// Extract anything that could conceivably be a part of a valid semver
|
|
45909
|
-
createToken('COERCE', `${'(^|[^\\d])' +
|
|
45910
|
-
'(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` +
|
|
45911
|
-
`(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +
|
|
45912
|
-
`(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +
|
|
45913
|
-
`(?:$|[^\\d])`);
|
|
45914
|
-
createToken('COERCERTL', src[t.COERCE], true);
|
|
45915
|
-
|
|
45916
|
-
// Tilde ranges.
|
|
45917
|
-
// Meaning is "reasonably at or greater than"
|
|
45918
|
-
createToken('LONETILDE', '(?:~>?)');
|
|
45919
|
-
|
|
45920
|
-
createToken('TILDETRIM', `(\\s*)${src[t.LONETILDE]}\\s+`, true);
|
|
45921
|
-
exports.tildeTrimReplace = '$1~';
|
|
45922
|
-
|
|
45923
|
-
createToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`);
|
|
45924
|
-
createToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`);
|
|
45925
|
-
|
|
45926
|
-
// Caret ranges.
|
|
45927
|
-
// Meaning is "at least and backwards compatible with"
|
|
45928
|
-
createToken('LONECARET', '(?:\\^)');
|
|
45929
|
-
|
|
45930
|
-
createToken('CARETTRIM', `(\\s*)${src[t.LONECARET]}\\s+`, true);
|
|
45931
|
-
exports.caretTrimReplace = '$1^';
|
|
45932
|
-
|
|
45933
|
-
createToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`);
|
|
45934
|
-
createToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`);
|
|
45935
|
-
|
|
45936
|
-
// A simple gt/lt/eq thing, or just "" to indicate "any version"
|
|
45937
|
-
createToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`);
|
|
45938
|
-
createToken('COMPARATOR', `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`);
|
|
45939
|
-
|
|
45940
|
-
// An expression to strip any whitespace between the gtlt and the thing
|
|
45941
|
-
// it modifies, so that `> 1.2.3` ==> `>1.2.3`
|
|
45942
|
-
createToken('COMPARATORTRIM', `(\\s*)${src[t.GTLT]
|
|
45943
|
-
}\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true);
|
|
45944
|
-
exports.comparatorTrimReplace = '$1$2$3';
|
|
45945
|
-
|
|
45946
|
-
// Something like `1.2.3 - 1.2.4`
|
|
45947
|
-
// Note that these all use the loose form, because they'll be
|
|
45948
|
-
// checked against either the strict or loose comparator form
|
|
45949
|
-
// later.
|
|
45950
|
-
createToken('HYPHENRANGE', `^\\s*(${src[t.XRANGEPLAIN]})` +
|
|
45951
|
-
`\\s+-\\s+` +
|
|
45952
|
-
`(${src[t.XRANGEPLAIN]})` +
|
|
45953
|
-
`\\s*$`);
|
|
45954
|
-
|
|
45955
|
-
createToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` +
|
|
45956
|
-
`\\s+-\\s+` +
|
|
45957
|
-
`(${src[t.XRANGEPLAINLOOSE]})` +
|
|
45958
|
-
`\\s*$`);
|
|
45959
|
-
|
|
45960
|
-
// Star ranges basically just allow anything at all.
|
|
45961
|
-
createToken('STAR', '(<|>)?=?\\s*\\*');
|
|
45962
|
-
// >=0.0.0 is like a star
|
|
45963
|
-
createToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$');
|
|
45964
|
-
createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$');
|
|
45965
|
-
});
|
|
45966
|
-
var re_2 = re_1.re;
|
|
45967
|
-
var re_3 = re_1.src;
|
|
45968
|
-
var re_4 = re_1.t;
|
|
45969
|
-
var re_5 = re_1.tildeTrimReplace;
|
|
45970
|
-
var re_6 = re_1.caretTrimReplace;
|
|
45971
|
-
var re_7 = re_1.comparatorTrimReplace;
|
|
45972
|
-
|
|
45973
|
-
// parse out just the options we care about so we always get a consistent
|
|
45974
|
-
// obj with keys in a consistent order.
|
|
45975
|
-
const opts = ['includePrerelease', 'loose', 'rtl'];
|
|
45976
|
-
const parseOptions = options =>
|
|
45977
|
-
!options ? {}
|
|
45978
|
-
: typeof options !== 'object' ? { loose: true }
|
|
45979
|
-
: opts.filter(k => options[k]).reduce((o, k) => {
|
|
45980
|
-
o[k] = true;
|
|
45981
|
-
return o
|
|
45982
|
-
}, {});
|
|
45983
|
-
var parseOptions_1 = parseOptions;
|
|
45984
|
-
|
|
45985
|
-
const numeric = /^[0-9]+$/;
|
|
45986
|
-
const compareIdentifiers = (a, b) => {
|
|
45987
|
-
const anum = numeric.test(a);
|
|
45988
|
-
const bnum = numeric.test(b);
|
|
45989
|
-
|
|
45990
|
-
if (anum && bnum) {
|
|
45991
|
-
a = +a;
|
|
45992
|
-
b = +b;
|
|
45993
|
-
}
|
|
45994
|
-
|
|
45995
|
-
return a === b ? 0
|
|
45996
|
-
: (anum && !bnum) ? -1
|
|
45997
|
-
: (bnum && !anum) ? 1
|
|
45998
|
-
: a < b ? -1
|
|
45999
|
-
: 1
|
|
46000
|
-
};
|
|
46001
|
-
|
|
46002
|
-
const rcompareIdentifiers = (a, b) => compareIdentifiers(b, a);
|
|
46003
|
-
|
|
46004
|
-
var identifiers = {
|
|
46005
|
-
compareIdentifiers,
|
|
46006
|
-
rcompareIdentifiers,
|
|
46007
|
-
};
|
|
46008
|
-
|
|
46009
|
-
const { MAX_LENGTH: MAX_LENGTH$1, MAX_SAFE_INTEGER: MAX_SAFE_INTEGER$1 } = constants;
|
|
46010
|
-
const { re: re$1, t: t$1 } = re_1;
|
|
46011
|
-
|
|
46012
|
-
|
|
46013
|
-
const { compareIdentifiers: compareIdentifiers$1 } = identifiers;
|
|
46014
|
-
class SemVer {
|
|
46015
|
-
constructor (version, options) {
|
|
46016
|
-
options = parseOptions_1(options);
|
|
46017
|
-
|
|
46018
|
-
if (version instanceof SemVer) {
|
|
46019
|
-
if (version.loose === !!options.loose &&
|
|
46020
|
-
version.includePrerelease === !!options.includePrerelease) {
|
|
46021
|
-
return version
|
|
46022
|
-
} else {
|
|
46023
|
-
version = version.version;
|
|
46024
|
-
}
|
|
46025
|
-
} else if (typeof version !== 'string') {
|
|
46026
|
-
throw new TypeError(`Invalid Version: ${version}`)
|
|
46027
|
-
}
|
|
46028
|
-
|
|
46029
|
-
if (version.length > MAX_LENGTH$1) {
|
|
46030
|
-
throw new TypeError(
|
|
46031
|
-
`version is longer than ${MAX_LENGTH$1} characters`
|
|
46032
|
-
)
|
|
45766
|
+
class WebBluetoothTransport {
|
|
45767
|
+
constructor(options = {}) {
|
|
45768
|
+
this.type = TRANSPORT_TYPE.WEB;
|
|
45769
|
+
this.characteristicsByName = {};
|
|
45770
|
+
this.connection$ = new BehaviorSubject(BLUETOOTH_CONNECTION.DISCONNECTED);
|
|
45771
|
+
this.pendingActions$ = new BehaviorSubject([]);
|
|
45772
|
+
this.logs$ = new ReplaySubject(10);
|
|
45773
|
+
this.onDisconnected$ = this._onDisconnected().pipe(share());
|
|
45774
|
+
this.connectionStream$ = this.connection$
|
|
45775
|
+
.asObservable()
|
|
45776
|
+
.pipe(filter((connection) => !!connection), distinctUntilChanged(), shareReplay(1));
|
|
45777
|
+
this._isAutoConnectEnabled$ = new ReplaySubject(1);
|
|
45778
|
+
this.options = Object.assign(Object.assign({}, defaultOptions$1), options);
|
|
45779
|
+
if (!isWebBluetoothSupported()) {
|
|
45780
|
+
const errorMessage = "Web Bluetooth is not supported";
|
|
45781
|
+
this.addLog(errorMessage);
|
|
45782
|
+
throw new Error(errorMessage);
|
|
45783
|
+
}
|
|
45784
|
+
this._isAutoConnectEnabled$.subscribe((autoConnect) => {
|
|
45785
|
+
this.addLog(`Auto connect: ${autoConnect ? "enabled" : "disabled"}`);
|
|
45786
|
+
});
|
|
45787
|
+
this._isAutoConnectEnabled$.next(this.options.autoConnect);
|
|
45788
|
+
this.connection$.asObservable().subscribe((connection) => {
|
|
45789
|
+
this.addLog(`connection status is ${connection}`);
|
|
45790
|
+
});
|
|
45791
|
+
this.onDisconnected$.subscribe(() => {
|
|
45792
|
+
this.connection$.next(BLUETOOTH_CONNECTION.DISCONNECTED);
|
|
45793
|
+
});
|
|
46033
45794
|
}
|
|
46034
|
-
|
|
46035
|
-
|
|
46036
|
-
|
|
46037
|
-
|
|
46038
|
-
// this isn't actually relevant for versions, but keep it so that we
|
|
46039
|
-
// don't run into trouble passing this.options around.
|
|
46040
|
-
this.includePrerelease = !!options.includePrerelease;
|
|
46041
|
-
|
|
46042
|
-
const m = version.trim().match(options.loose ? re$1[t$1.LOOSE] : re$1[t$1.FULL]);
|
|
46043
|
-
|
|
46044
|
-
if (!m) {
|
|
46045
|
-
throw new TypeError(`Invalid Version: ${version}`)
|
|
45795
|
+
_getPairedDevices() {
|
|
45796
|
+
return __awaiter$d(this, void 0, void 0, function* () {
|
|
45797
|
+
return yield navigator.bluetooth.getDevices();
|
|
45798
|
+
});
|
|
46046
45799
|
}
|
|
46047
|
-
|
|
46048
|
-
|
|
46049
|
-
|
|
46050
|
-
|
|
46051
|
-
|
|
46052
|
-
|
|
46053
|
-
|
|
46054
|
-
|
|
46055
|
-
|
|
46056
|
-
|
|
45800
|
+
_autoConnect(selectedDevice$) {
|
|
45801
|
+
return this._isAutoConnectEnabled$.pipe(switchMap((isAutoConnectEnabled) => isAutoConnectEnabled
|
|
45802
|
+
? merge(selectedDevice$, this.onDisconnected$.pipe(switchMap(() => selectedDevice$)))
|
|
45803
|
+
: NEVER), switchMap((selectedDevice) => __awaiter$d(this, void 0, void 0, function* () {
|
|
45804
|
+
var _a;
|
|
45805
|
+
const { deviceNickname } = selectedDevice;
|
|
45806
|
+
if (this.isConnected()) {
|
|
45807
|
+
this.addLog(`Auto connect: ${deviceNickname} is already connected. Skipping auto connect.`);
|
|
45808
|
+
return;
|
|
45809
|
+
}
|
|
45810
|
+
const [devicesError, devices] = yield this._getPairedDevices()
|
|
45811
|
+
.then((devices) => [null, devices])
|
|
45812
|
+
.catch((error) => [error, null]);
|
|
45813
|
+
if (devicesError) {
|
|
45814
|
+
throw new Error(`failed to get devices: ${(_a = devicesError === null || devicesError === void 0 ? void 0 : devicesError.message) !== null && _a !== void 0 ? _a : devicesError}`);
|
|
45815
|
+
}
|
|
45816
|
+
this.addLog(`Auto connect: found ${devices.length} devices ${devices
|
|
45817
|
+
.map(({ name }) => name)
|
|
45818
|
+
.join(", ")}`);
|
|
45819
|
+
// @important - Using `findLast` instead of `find` because somehow the browser
|
|
45820
|
+
// is finding multiple peripherals with the same name
|
|
45821
|
+
const device = devices.findLast((device) => device.name === deviceNickname);
|
|
45822
|
+
if (!device) {
|
|
45823
|
+
throw new Error(`couldn't find selected device in the list of paired devices.`);
|
|
45824
|
+
}
|
|
45825
|
+
this.addLog(`Auto connect: ${deviceNickname} was detected and previously paired`);
|
|
45826
|
+
return device;
|
|
45827
|
+
})), tap(() => {
|
|
45828
|
+
this.connection$.next(BLUETOOTH_CONNECTION.SCANNING);
|
|
45829
|
+
}), switchMap((device) => onAdvertisementReceived(device)), switchMap((advertisement) => __awaiter$d(this, void 0, void 0, function* () {
|
|
45830
|
+
this.addLog(`Advertisement received for ${advertisement.device.name}`);
|
|
45831
|
+
return yield this.getServerServiceAndCharacteristics(advertisement.device);
|
|
45832
|
+
})));
|
|
46057
45833
|
}
|
|
46058
|
-
|
|
46059
|
-
|
|
46060
|
-
throw new TypeError('Invalid minor version')
|
|
45834
|
+
enableAutoConnect(autoConnect) {
|
|
45835
|
+
this._isAutoConnectEnabled$.next(autoConnect);
|
|
46061
45836
|
}
|
|
46062
|
-
|
|
46063
|
-
|
|
46064
|
-
throw new TypeError('Invalid patch version')
|
|
45837
|
+
addLog(log) {
|
|
45838
|
+
this.logs$.next(log);
|
|
46065
45839
|
}
|
|
46066
|
-
|
|
46067
|
-
|
|
46068
|
-
|
|
46069
|
-
this.prerelease = [];
|
|
46070
|
-
} else {
|
|
46071
|
-
this.prerelease = m[4].split('.').map((id) => {
|
|
46072
|
-
if (/^[0-9]+$/.test(id)) {
|
|
46073
|
-
const num = +id;
|
|
46074
|
-
if (num >= 0 && num < MAX_SAFE_INTEGER$1) {
|
|
46075
|
-
return num
|
|
46076
|
-
}
|
|
46077
|
-
}
|
|
46078
|
-
return id
|
|
46079
|
-
});
|
|
45840
|
+
isConnected() {
|
|
45841
|
+
const connection = this.connection$.getValue();
|
|
45842
|
+
return connection === BLUETOOTH_CONNECTION.CONNECTED;
|
|
46080
45843
|
}
|
|
46081
|
-
|
|
46082
|
-
|
|
46083
|
-
this.format();
|
|
46084
|
-
}
|
|
46085
|
-
|
|
46086
|
-
format () {
|
|
46087
|
-
this.version = `${this.major}.${this.minor}.${this.patch}`;
|
|
46088
|
-
if (this.prerelease.length) {
|
|
46089
|
-
this.version += `-${this.prerelease.join('.')}`;
|
|
45844
|
+
connection() {
|
|
45845
|
+
return this.connectionStream$;
|
|
46090
45846
|
}
|
|
46091
|
-
|
|
46092
|
-
|
|
46093
|
-
|
|
46094
|
-
|
|
46095
|
-
|
|
46096
|
-
|
|
46097
|
-
|
|
46098
|
-
|
|
46099
|
-
|
|
46100
|
-
|
|
46101
|
-
|
|
46102
|
-
return 0
|
|
46103
|
-
}
|
|
46104
|
-
other = new SemVer(other, this.options);
|
|
45847
|
+
connect(deviceNickname) {
|
|
45848
|
+
return __awaiter$d(this, void 0, void 0, function* () {
|
|
45849
|
+
try {
|
|
45850
|
+
// requires user gesture
|
|
45851
|
+
const device = yield this.requestDevice(deviceNickname);
|
|
45852
|
+
yield this.getServerServiceAndCharacteristics(device);
|
|
45853
|
+
}
|
|
45854
|
+
catch (error) {
|
|
45855
|
+
return Promise.reject(error);
|
|
45856
|
+
}
|
|
45857
|
+
});
|
|
46105
45858
|
}
|
|
46106
|
-
|
|
46107
|
-
|
|
46108
|
-
|
|
45859
|
+
requestDevice(deviceNickname) {
|
|
45860
|
+
return __awaiter$d(this, void 0, void 0, function* () {
|
|
45861
|
+
try {
|
|
45862
|
+
this.addLog("Requesting Bluetooth Device...");
|
|
45863
|
+
const prefixes = BLUETOOTH_DEVICE_NAME_PREFIXES.map((namePrefix) => ({
|
|
45864
|
+
namePrefix
|
|
45865
|
+
}));
|
|
45866
|
+
// Ability to only show selectedDevice if provided
|
|
45867
|
+
const filters = deviceNickname
|
|
45868
|
+
? [
|
|
45869
|
+
{
|
|
45870
|
+
name: deviceNickname
|
|
45871
|
+
}
|
|
45872
|
+
]
|
|
45873
|
+
: prefixes;
|
|
45874
|
+
const device = yield window.navigator.bluetooth.requestDevice({
|
|
45875
|
+
filters: [
|
|
45876
|
+
...filters,
|
|
45877
|
+
{
|
|
45878
|
+
manufacturerData: [
|
|
45879
|
+
{
|
|
45880
|
+
companyIdentifier: BLUETOOTH_COMPANY_IDENTIFIER_HEX
|
|
45881
|
+
}
|
|
45882
|
+
]
|
|
45883
|
+
}
|
|
45884
|
+
],
|
|
45885
|
+
optionalServices: [BLUETOOTH_PRIMARY_SERVICE_UUID_HEX]
|
|
45886
|
+
});
|
|
45887
|
+
return device;
|
|
45888
|
+
}
|
|
45889
|
+
catch (error) {
|
|
45890
|
+
return Promise.reject(error);
|
|
45891
|
+
}
|
|
45892
|
+
});
|
|
46109
45893
|
}
|
|
46110
|
-
|
|
46111
|
-
|
|
46112
|
-
|
|
46113
|
-
|
|
46114
|
-
|
|
46115
|
-
|
|
46116
|
-
|
|
45894
|
+
getServerServiceAndCharacteristics(device) {
|
|
45895
|
+
return __awaiter$d(this, void 0, void 0, function* () {
|
|
45896
|
+
try {
|
|
45897
|
+
this.device = device;
|
|
45898
|
+
const isConnecting = this.connection$.getValue() === BLUETOOTH_CONNECTION.CONNECTING;
|
|
45899
|
+
if (!isConnecting) {
|
|
45900
|
+
this.connection$.next(BLUETOOTH_CONNECTION.CONNECTING);
|
|
45901
|
+
}
|
|
45902
|
+
this.server = yield device.gatt.connect();
|
|
45903
|
+
this.addLog(`Getting service...`);
|
|
45904
|
+
this.service = yield this.server.getPrimaryService(BLUETOOTH_PRIMARY_SERVICE_UUID_HEX);
|
|
45905
|
+
this.addLog(`Got service ${this.service.uuid}, getting characteristics...`);
|
|
45906
|
+
const characteristicsList = yield this.service.getCharacteristics();
|
|
45907
|
+
this.addLog(`Got characteristics`);
|
|
45908
|
+
this.characteristicsByName = Object.fromEntries(characteristicsList.map((characteristic) => [
|
|
45909
|
+
CHARACTERISTIC_UUIDS_TO_NAMES[characteristic.uuid],
|
|
45910
|
+
characteristic
|
|
45911
|
+
]));
|
|
45912
|
+
this.connection$.next(BLUETOOTH_CONNECTION.CONNECTED);
|
|
45913
|
+
}
|
|
45914
|
+
catch (error) {
|
|
45915
|
+
return Promise.reject(error);
|
|
45916
|
+
}
|
|
45917
|
+
});
|
|
46117
45918
|
}
|
|
46118
|
-
|
|
46119
|
-
|
|
46120
|
-
|
|
46121
|
-
|
|
46122
|
-
|
|
46123
|
-
|
|
46124
|
-
}
|
|
46125
|
-
|
|
46126
|
-
comparePre (other) {
|
|
46127
|
-
if (!(other instanceof SemVer)) {
|
|
46128
|
-
other = new SemVer(other, this.options);
|
|
45919
|
+
_onDisconnected() {
|
|
45920
|
+
return this.connection$
|
|
45921
|
+
.asObservable()
|
|
45922
|
+
.pipe(switchMap((connection) => connection === BLUETOOTH_CONNECTION.CONNECTED
|
|
45923
|
+
? fromDOMEvent(this.device, "gattserverdisconnected")
|
|
45924
|
+
: NEVER));
|
|
46129
45925
|
}
|
|
46130
|
-
|
|
46131
|
-
|
|
46132
|
-
|
|
46133
|
-
|
|
46134
|
-
|
|
46135
|
-
|
|
46136
|
-
|
|
46137
|
-
|
|
45926
|
+
disconnect() {
|
|
45927
|
+
var _a, _b;
|
|
45928
|
+
return __awaiter$d(this, void 0, void 0, function* () {
|
|
45929
|
+
const isDeviceConnected = (_b = (_a = this === null || this === void 0 ? void 0 : this.device) === null || _a === void 0 ? void 0 : _a.gatt) === null || _b === void 0 ? void 0 : _b.connected;
|
|
45930
|
+
if (isDeviceConnected) {
|
|
45931
|
+
this.device.gatt.disconnect();
|
|
45932
|
+
}
|
|
45933
|
+
});
|
|
46138
45934
|
}
|
|
46139
|
-
|
|
46140
|
-
|
|
46141
|
-
|
|
46142
|
-
|
|
46143
|
-
|
|
46144
|
-
|
|
46145
|
-
|
|
46146
|
-
|
|
46147
|
-
|
|
46148
|
-
return
|
|
46149
|
-
|
|
46150
|
-
|
|
46151
|
-
} else if (a === b) {
|
|
46152
|
-
continue
|
|
46153
|
-
} else {
|
|
46154
|
-
return compareIdentifiers$1(a, b)
|
|
46155
|
-
}
|
|
46156
|
-
} while (++i)
|
|
46157
|
-
}
|
|
46158
|
-
|
|
46159
|
-
compareBuild (other) {
|
|
46160
|
-
if (!(other instanceof SemVer)) {
|
|
46161
|
-
other = new SemVer(other, this.options);
|
|
45935
|
+
/**
|
|
45936
|
+
*
|
|
45937
|
+
* Bluetooth GATT attributes, services, characteristics, etc. are invalidated
|
|
45938
|
+
* when a device disconnects. This means your code should always retrieve
|
|
45939
|
+
* (through getPrimaryService(s), getCharacteristic(s), etc.) these attributes
|
|
45940
|
+
* after reconnecting.
|
|
45941
|
+
*/
|
|
45942
|
+
getCharacteristicByName(characteristicName) {
|
|
45943
|
+
var _a;
|
|
45944
|
+
return __awaiter$d(this, void 0, void 0, function* () {
|
|
45945
|
+
return (_a = this.characteristicsByName) === null || _a === void 0 ? void 0 : _a[characteristicName];
|
|
45946
|
+
});
|
|
46162
45947
|
}
|
|
46163
|
-
|
|
46164
|
-
|
|
46165
|
-
|
|
46166
|
-
|
|
46167
|
-
|
|
46168
|
-
|
|
46169
|
-
|
|
46170
|
-
|
|
46171
|
-
|
|
46172
|
-
|
|
46173
|
-
|
|
46174
|
-
return -1
|
|
46175
|
-
} else if (a === b) {
|
|
46176
|
-
continue
|
|
46177
|
-
} else {
|
|
46178
|
-
return compareIdentifiers$1(a, b)
|
|
46179
|
-
}
|
|
46180
|
-
} while (++i)
|
|
46181
|
-
}
|
|
46182
|
-
|
|
46183
|
-
// preminor will bump the version up to the next minor release, and immediately
|
|
46184
|
-
// down to pre-release. premajor and prepatch work the same way.
|
|
46185
|
-
inc (release, identifier) {
|
|
46186
|
-
switch (release) {
|
|
46187
|
-
case 'premajor':
|
|
46188
|
-
this.prerelease.length = 0;
|
|
46189
|
-
this.patch = 0;
|
|
46190
|
-
this.minor = 0;
|
|
46191
|
-
this.major++;
|
|
46192
|
-
this.inc('pre', identifier);
|
|
46193
|
-
break
|
|
46194
|
-
case 'preminor':
|
|
46195
|
-
this.prerelease.length = 0;
|
|
46196
|
-
this.patch = 0;
|
|
46197
|
-
this.minor++;
|
|
46198
|
-
this.inc('pre', identifier);
|
|
46199
|
-
break
|
|
46200
|
-
case 'prepatch':
|
|
46201
|
-
// If this is already a prerelease, it will bump to the next version
|
|
46202
|
-
// drop any prereleases that might already exist, since they are not
|
|
46203
|
-
// relevant at this point.
|
|
46204
|
-
this.prerelease.length = 0;
|
|
46205
|
-
this.inc('patch', identifier);
|
|
46206
|
-
this.inc('pre', identifier);
|
|
46207
|
-
break
|
|
46208
|
-
// If the input is a non-prerelease version, this acts the same as
|
|
46209
|
-
// prepatch.
|
|
46210
|
-
case 'prerelease':
|
|
46211
|
-
if (this.prerelease.length === 0) {
|
|
46212
|
-
this.inc('patch', identifier);
|
|
46213
|
-
}
|
|
46214
|
-
this.inc('pre', identifier);
|
|
46215
|
-
break
|
|
46216
|
-
|
|
46217
|
-
case 'major':
|
|
46218
|
-
// If this is a pre-major version, bump up to the same major version.
|
|
46219
|
-
// Otherwise increment major.
|
|
46220
|
-
// 1.0.0-5 bumps to 1.0.0
|
|
46221
|
-
// 1.1.0 bumps to 2.0.0
|
|
46222
|
-
if (
|
|
46223
|
-
this.minor !== 0 ||
|
|
46224
|
-
this.patch !== 0 ||
|
|
46225
|
-
this.prerelease.length === 0
|
|
46226
|
-
) {
|
|
46227
|
-
this.major++;
|
|
46228
|
-
}
|
|
46229
|
-
this.minor = 0;
|
|
46230
|
-
this.patch = 0;
|
|
46231
|
-
this.prerelease = [];
|
|
46232
|
-
break
|
|
46233
|
-
case 'minor':
|
|
46234
|
-
// If this is a pre-minor version, bump up to the same minor version.
|
|
46235
|
-
// Otherwise increment minor.
|
|
46236
|
-
// 1.2.0-5 bumps to 1.2.0
|
|
46237
|
-
// 1.2.1 bumps to 1.3.0
|
|
46238
|
-
if (this.patch !== 0 || this.prerelease.length === 0) {
|
|
46239
|
-
this.minor++;
|
|
46240
|
-
}
|
|
46241
|
-
this.patch = 0;
|
|
46242
|
-
this.prerelease = [];
|
|
46243
|
-
break
|
|
46244
|
-
case 'patch':
|
|
46245
|
-
// If this is not a pre-release version, it will increment the patch.
|
|
46246
|
-
// If it is a pre-release it will bump up to the same patch version.
|
|
46247
|
-
// 1.2.0-5 patches to 1.2.0
|
|
46248
|
-
// 1.2.0 patches to 1.2.1
|
|
46249
|
-
if (this.prerelease.length === 0) {
|
|
46250
|
-
this.patch++;
|
|
46251
|
-
}
|
|
46252
|
-
this.prerelease = [];
|
|
46253
|
-
break
|
|
46254
|
-
// This probably shouldn't be used publicly.
|
|
46255
|
-
// 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction.
|
|
46256
|
-
case 'pre':
|
|
46257
|
-
if (this.prerelease.length === 0) {
|
|
46258
|
-
this.prerelease = [0];
|
|
46259
|
-
} else {
|
|
46260
|
-
let i = this.prerelease.length;
|
|
46261
|
-
while (--i >= 0) {
|
|
46262
|
-
if (typeof this.prerelease[i] === 'number') {
|
|
46263
|
-
this.prerelease[i]++;
|
|
46264
|
-
i = -2;
|
|
45948
|
+
subscribeToCharacteristic({ characteristicName, manageNotifications = true }) {
|
|
45949
|
+
const data$ = defer(() => this.getCharacteristicByName(characteristicName)).pipe(switchMap((characteristic) => __awaiter$d(this, void 0, void 0, function* () {
|
|
45950
|
+
var _a;
|
|
45951
|
+
if (this.isConnected() && manageNotifications) {
|
|
45952
|
+
try {
|
|
45953
|
+
yield characteristic.startNotifications();
|
|
45954
|
+
this.addLog(`Started notifications for ${characteristicName} characteristic`);
|
|
45955
|
+
}
|
|
45956
|
+
catch (error) {
|
|
45957
|
+
this.addLog(`Attemped to stop notifications for ${characteristicName} characteristic: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
45958
|
+
}
|
|
46265
45959
|
}
|
|
46266
|
-
|
|
46267
|
-
|
|
46268
|
-
|
|
46269
|
-
|
|
46270
|
-
|
|
46271
|
-
|
|
46272
|
-
|
|
46273
|
-
|
|
46274
|
-
|
|
46275
|
-
|
|
46276
|
-
|
|
46277
|
-
|
|
45960
|
+
return characteristic;
|
|
45961
|
+
})), switchMap((characteristic) => {
|
|
45962
|
+
return fromDOMEvent(characteristic, "characteristicvaluechanged", () => __awaiter$d(this, void 0, void 0, function* () {
|
|
45963
|
+
var _a;
|
|
45964
|
+
if (this.isConnected() && manageNotifications) {
|
|
45965
|
+
try {
|
|
45966
|
+
yield characteristic.stopNotifications();
|
|
45967
|
+
this.addLog(`Stopped notifications for ${characteristicName} characteristic`);
|
|
45968
|
+
}
|
|
45969
|
+
catch (error) {
|
|
45970
|
+
this.addLog(`Attemped to stop notifications for ${characteristicName} characteristic: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
45971
|
+
}
|
|
45972
|
+
}
|
|
45973
|
+
}));
|
|
45974
|
+
}), map((event) => {
|
|
45975
|
+
const buffer$$1 = event.target.value;
|
|
45976
|
+
const decoded = decode$1(this.type, buffer$$1);
|
|
45977
|
+
this.addLog(`Received chunk with buffer size of ${buffer$$1.byteLength} and decoded size ${decoded.length} for ${characteristicName} characteristic: \n${decoded}`);
|
|
45978
|
+
return decoded;
|
|
45979
|
+
}), stitchChunks({ delimiter: BLUETOOTH_CHUNK_DELIMITER }), map((payload) => {
|
|
45980
|
+
var _a;
|
|
45981
|
+
try {
|
|
45982
|
+
return JSON.parse(payload);
|
|
46278
45983
|
}
|
|
46279
|
-
|
|
46280
|
-
|
|
46281
|
-
|
|
46282
|
-
|
|
46283
|
-
|
|
46284
|
-
|
|
46285
|
-
|
|
46286
|
-
|
|
45984
|
+
catch (error) {
|
|
45985
|
+
this.addLog(`Failed to parse JSON for ${characteristicName} characteristic. Falling back to unparsed string. ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
45986
|
+
return payload;
|
|
45987
|
+
}
|
|
45988
|
+
})
|
|
45989
|
+
// when streaming at ultra-low latency, the logs will slow down rendering
|
|
45990
|
+
// tap((data) => {
|
|
45991
|
+
// this.addLog(
|
|
45992
|
+
// `Received data for ${characteristicName} characteristic: \n${JSON.stringify(
|
|
45993
|
+
// data,
|
|
45994
|
+
// null,
|
|
45995
|
+
// 2
|
|
45996
|
+
// )}`
|
|
45997
|
+
// );
|
|
45998
|
+
// })
|
|
45999
|
+
);
|
|
46000
|
+
return this.connection$.pipe(switchMap((connection) => connection === BLUETOOTH_CONNECTION.CONNECTED ? data$ : NEVER));
|
|
46287
46001
|
}
|
|
46288
|
-
|
|
46289
|
-
|
|
46290
|
-
|
|
46291
|
-
|
|
46292
|
-
|
|
46293
|
-
|
|
46294
|
-
|
|
46295
|
-
|
|
46296
|
-
|
|
46297
|
-
|
|
46298
|
-
|
|
46299
|
-
|
|
46300
|
-
|
|
46301
|
-
|
|
46302
|
-
|
|
46303
|
-
|
|
46304
|
-
|
|
46305
|
-
|
|
46306
|
-
|
|
46002
|
+
readCharacteristic(characteristicName, parse = false) {
|
|
46003
|
+
return __awaiter$d(this, void 0, void 0, function* () {
|
|
46004
|
+
try {
|
|
46005
|
+
this.addLog(`Reading characteristic: ${characteristicName}`);
|
|
46006
|
+
const characteristic = yield this.getCharacteristicByName(characteristicName);
|
|
46007
|
+
if (!characteristic) {
|
|
46008
|
+
this.addLog(`Did not fund ${characteristicName} characteristic`);
|
|
46009
|
+
return Promise.reject(`Did not find characteristic by the name: ${characteristicName}`);
|
|
46010
|
+
}
|
|
46011
|
+
const value = yield characteristic.readValue();
|
|
46012
|
+
const uint8Array = value;
|
|
46013
|
+
const decodedValue = decode$1(this.type, uint8Array);
|
|
46014
|
+
const data = parse ? JSON.parse(decodedValue) : decodedValue;
|
|
46015
|
+
this.addLog(`Received read data from ${characteristicName} characteristic: \n${data}`);
|
|
46016
|
+
return data;
|
|
46017
|
+
}
|
|
46018
|
+
catch (error) {
|
|
46019
|
+
return Promise.reject(`Error reading characteristic: ${error.message}`);
|
|
46020
|
+
}
|
|
46021
|
+
});
|
|
46307
46022
|
}
|
|
46308
|
-
|
|
46309
|
-
|
|
46310
|
-
|
|
46311
|
-
|
|
46023
|
+
writeCharacteristic(characteristicName, data) {
|
|
46024
|
+
return __awaiter$d(this, void 0, void 0, function* () {
|
|
46025
|
+
this.addLog(`Writing characteristic: ${characteristicName}`);
|
|
46026
|
+
const characteristic = yield this.getCharacteristicByName(characteristicName);
|
|
46027
|
+
if (!characteristic) {
|
|
46028
|
+
this.addLog(`Did not fund ${characteristicName} characteristic`);
|
|
46029
|
+
return Promise.reject(`Did not find characteristic by the name: ${characteristicName}`);
|
|
46030
|
+
}
|
|
46031
|
+
const encoded = encode$1(this.type, data);
|
|
46032
|
+
yield characteristic.writeValueWithResponse(encoded);
|
|
46033
|
+
});
|
|
46312
46034
|
}
|
|
46313
|
-
|
|
46314
|
-
|
|
46315
|
-
|
|
46035
|
+
_addPendingAction(actionId) {
|
|
46036
|
+
const actions = this.pendingActions$.getValue();
|
|
46037
|
+
this.pendingActions$.next([...actions, actionId]);
|
|
46038
|
+
}
|
|
46039
|
+
_removePendingAction(actionId) {
|
|
46040
|
+
const actions = this.pendingActions$.getValue();
|
|
46041
|
+
this.pendingActions$.next(actions.filter((id) => id !== actionId));
|
|
46042
|
+
}
|
|
46043
|
+
_autoToggleActionNotifications() {
|
|
46044
|
+
let actionsCharacteristic;
|
|
46045
|
+
let started = false;
|
|
46046
|
+
return this.connection$.asObservable().pipe(switchMap((connection) => connection === BLUETOOTH_CONNECTION.CONNECTED
|
|
46047
|
+
? defer(() => this.getCharacteristicByName("actions")).pipe(switchMap((characteristic) => {
|
|
46048
|
+
actionsCharacteristic = characteristic;
|
|
46049
|
+
return this.pendingActions$;
|
|
46050
|
+
}))
|
|
46051
|
+
: NEVER), tap((pendingActions) => __awaiter$d(this, void 0, void 0, function* () {
|
|
46052
|
+
var _a, _b;
|
|
46053
|
+
const hasPendingActions = !!pendingActions.length;
|
|
46054
|
+
if (hasPendingActions && !started) {
|
|
46055
|
+
started = true;
|
|
46056
|
+
try {
|
|
46057
|
+
yield actionsCharacteristic.startNotifications();
|
|
46058
|
+
this.addLog(`Started notifications for [actions] characteristic`);
|
|
46059
|
+
}
|
|
46060
|
+
catch (error) {
|
|
46061
|
+
this.addLog(`Attemped to start notifications for [actions] characteristic: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
46062
|
+
}
|
|
46063
|
+
}
|
|
46064
|
+
if (!hasPendingActions && started) {
|
|
46065
|
+
started = false;
|
|
46066
|
+
try {
|
|
46067
|
+
yield actionsCharacteristic.stopNotifications();
|
|
46068
|
+
this.addLog(`Stopped notifications for actions characteristic`);
|
|
46069
|
+
}
|
|
46070
|
+
catch (error) {
|
|
46071
|
+
this.addLog(`Attemped to stop notifications for [actions] characteristic: ${(_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error}`);
|
|
46072
|
+
}
|
|
46073
|
+
}
|
|
46074
|
+
})));
|
|
46075
|
+
}
|
|
46076
|
+
dispatchAction({ characteristicName, action }) {
|
|
46077
|
+
return __awaiter$d(this, void 0, void 0, function* () {
|
|
46078
|
+
const { responseRequired = false, responseTimeout = DEFAULT_ACTION_RESPONSE_TIMEOUT } = action;
|
|
46079
|
+
return new Promise((resolve, reject) => __awaiter$d(this, void 0, void 0, function* () {
|
|
46080
|
+
const characteristic = yield this.getCharacteristicByName(characteristicName).catch(() => {
|
|
46081
|
+
reject(`Did not find characteristic by the name: ${characteristicName}`);
|
|
46082
|
+
});
|
|
46083
|
+
if (!characteristic) {
|
|
46084
|
+
return;
|
|
46085
|
+
}
|
|
46086
|
+
const actionId = create6DigitPin(); // use to later identify and filter response
|
|
46087
|
+
const payload = JSON.stringify(Object.assign({ actionId }, action)); // add the response id to the action
|
|
46088
|
+
this.addLog(`Dispatched action with id ${actionId}`);
|
|
46089
|
+
if (responseRequired && responseTimeout) {
|
|
46090
|
+
this._addPendingAction(actionId);
|
|
46091
|
+
const timeout$$1 = timer(responseTimeout).subscribe(() => {
|
|
46092
|
+
this._removePendingAction(actionId);
|
|
46093
|
+
reject(`Action with id ${actionId} timed out after ${responseTimeout}ms`);
|
|
46094
|
+
});
|
|
46095
|
+
// listen for a response before writing
|
|
46096
|
+
this.subscribeToCharacteristic({
|
|
46097
|
+
characteristicName,
|
|
46098
|
+
manageNotifications: false
|
|
46099
|
+
})
|
|
46100
|
+
.pipe(filter((response) => (response === null || response === void 0 ? void 0 : response.actionId) === actionId), take(1))
|
|
46101
|
+
.subscribe((response) => {
|
|
46102
|
+
timeout$$1.unsubscribe();
|
|
46103
|
+
this._removePendingAction(actionId);
|
|
46104
|
+
resolve(response);
|
|
46105
|
+
});
|
|
46106
|
+
// register action by writing
|
|
46107
|
+
this.writeCharacteristic(characteristicName, payload).catch((error) => {
|
|
46108
|
+
this._removePendingAction(actionId);
|
|
46109
|
+
reject(error.message);
|
|
46110
|
+
});
|
|
46111
|
+
}
|
|
46112
|
+
else {
|
|
46113
|
+
this.writeCharacteristic(characteristicName, payload)
|
|
46114
|
+
.then(() => {
|
|
46115
|
+
resolve(null);
|
|
46116
|
+
})
|
|
46117
|
+
.catch((error) => {
|
|
46118
|
+
reject(error.message);
|
|
46119
|
+
});
|
|
46120
|
+
}
|
|
46121
|
+
}));
|
|
46122
|
+
});
|
|
46316
46123
|
}
|
|
46317
|
-
|
|
46124
|
+
}
|
|
46125
|
+
function fromDOMEvent(target, eventName, beforeRemove) {
|
|
46126
|
+
return fromEventPattern((addHandler) => {
|
|
46127
|
+
target.addEventListener(eventName, addHandler);
|
|
46128
|
+
}, (removeHandler) => __awaiter$d(this, void 0, void 0, function* () {
|
|
46129
|
+
if (beforeRemove) {
|
|
46130
|
+
yield beforeRemove();
|
|
46131
|
+
}
|
|
46132
|
+
target.removeEventListener(eventName, removeHandler);
|
|
46133
|
+
}));
|
|
46134
|
+
}
|
|
46135
|
+
function onAdvertisementReceived(device) {
|
|
46136
|
+
return new Observable((subscriber) => {
|
|
46137
|
+
const abortController = new AbortController();
|
|
46138
|
+
const { signal } = abortController;
|
|
46139
|
+
const listener = device.addEventListener("advertisementreceived", (advertisement) => {
|
|
46140
|
+
abortController.abort();
|
|
46141
|
+
subscriber.next(advertisement);
|
|
46142
|
+
subscriber.complete();
|
|
46143
|
+
}, {
|
|
46144
|
+
once: true
|
|
46145
|
+
});
|
|
46146
|
+
try {
|
|
46147
|
+
device.watchAdvertisements({ signal });
|
|
46148
|
+
}
|
|
46149
|
+
catch (error) {
|
|
46150
|
+
subscriber.error(error);
|
|
46151
|
+
}
|
|
46152
|
+
return () => {
|
|
46153
|
+
abortController.abort();
|
|
46154
|
+
device.removeEventListener("advertisementreceived", listener);
|
|
46155
|
+
};
|
|
46156
|
+
});
|
|
46318
46157
|
}
|
|
46319
46158
|
|
|
46320
|
-
var __awaiter$
|
|
46159
|
+
var __awaiter$e = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
46321
46160
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
46322
46161
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
46323
46162
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
@@ -46326,31 +46165,69 @@ var __awaiter$d = (undefined && undefined.__awaiter) || function (thisArg, _argu
|
|
|
46326
46165
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
46327
46166
|
});
|
|
46328
46167
|
};
|
|
46329
|
-
const defaultOptions$
|
|
46168
|
+
const defaultOptions$2 = {
|
|
46330
46169
|
autoConnect: true
|
|
46331
46170
|
};
|
|
46332
|
-
class
|
|
46333
|
-
constructor(options
|
|
46334
|
-
this.type = TRANSPORT_TYPE.
|
|
46171
|
+
class ReactNativeTransport {
|
|
46172
|
+
constructor(options) {
|
|
46173
|
+
this.type = TRANSPORT_TYPE.REACT_NATIVE;
|
|
46335
46174
|
this.characteristicsByName = {};
|
|
46336
46175
|
this.connection$ = new BehaviorSubject(BLUETOOTH_CONNECTION.DISCONNECTED);
|
|
46337
46176
|
this.pendingActions$ = new BehaviorSubject([]);
|
|
46338
46177
|
this.logs$ = new ReplaySubject(10);
|
|
46339
|
-
this.onDisconnected$ = this._onDisconnected().pipe(share());
|
|
46340
46178
|
this.connectionStream$ = this.connection$
|
|
46341
46179
|
.asObservable()
|
|
46342
46180
|
.pipe(filter((connection) => !!connection), distinctUntilChanged(), shareReplay(1));
|
|
46343
46181
|
this._isAutoConnectEnabled$ = new ReplaySubject(1);
|
|
46344
|
-
|
|
46345
|
-
|
|
46346
|
-
|
|
46182
|
+
if (!options) {
|
|
46183
|
+
const errorMessage = "React Native transport: missing options.";
|
|
46184
|
+
this.addLog(errorMessage);
|
|
46185
|
+
throw new Error(errorMessage);
|
|
46186
|
+
}
|
|
46187
|
+
this.options = Object.assign(Object.assign({}, defaultOptions$2), options);
|
|
46188
|
+
const { BleManager, bleManagerEmitter, platform, autoConnect } = this.options;
|
|
46189
|
+
if (!BleManager) {
|
|
46190
|
+
const errorMessage = "React Native option: BleManager not provided.";
|
|
46191
|
+
this.addLog(errorMessage);
|
|
46192
|
+
throw new Error(errorMessage);
|
|
46193
|
+
}
|
|
46194
|
+
if (!bleManagerEmitter) {
|
|
46195
|
+
const errorMessage = "React Native option: bleManagerEmitter not provided.";
|
|
46347
46196
|
this.addLog(errorMessage);
|
|
46348
46197
|
throw new Error(errorMessage);
|
|
46349
46198
|
}
|
|
46199
|
+
if (!platform) {
|
|
46200
|
+
const errorMessage = "React Native option: platform not provided.";
|
|
46201
|
+
this.addLog(errorMessage);
|
|
46202
|
+
throw new Error(errorMessage);
|
|
46203
|
+
}
|
|
46204
|
+
this.BleManager = BleManager;
|
|
46205
|
+
this.bleManagerEmitter = bleManagerEmitter;
|
|
46206
|
+
this.platform = platform;
|
|
46207
|
+
this._isAutoConnectEnabled$.next(autoConnect);
|
|
46350
46208
|
this._isAutoConnectEnabled$.subscribe((autoConnect) => {
|
|
46351
46209
|
this.addLog(`Auto connect: ${autoConnect ? "enabled" : "disabled"}`);
|
|
46352
46210
|
});
|
|
46353
|
-
|
|
46211
|
+
// We create a single listener per event type to
|
|
46212
|
+
// avoid missing events when multiple listeners are attached.
|
|
46213
|
+
this.bleEvents = {
|
|
46214
|
+
stopScan$: this._fromEvent("BleManagerStopScan"),
|
|
46215
|
+
discoverPeripheral$: this._fromEvent("BleManagerDiscoverPeripheral"),
|
|
46216
|
+
connectPeripheral$: this._fromEvent("BleManagerConnectPeripheral"),
|
|
46217
|
+
disconnectPeripheral$: this._fromEvent("BleManagerDisconnectPeripheral"),
|
|
46218
|
+
didUpdateValueForCharacteristic$: this._fromEvent("BleManagerDidUpdateValueForCharacteristic"),
|
|
46219
|
+
didUpdateState$: this._fromEvent("BleManagerDidUpdateState")
|
|
46220
|
+
};
|
|
46221
|
+
this.onDisconnected$ = this.bleEvents.disconnectPeripheral$.pipe(share());
|
|
46222
|
+
// Initializes the module. This can only be called once.
|
|
46223
|
+
this.BleManager.start({ showAlert: false })
|
|
46224
|
+
.then(() => {
|
|
46225
|
+
this.addLog(`BleManger started`);
|
|
46226
|
+
})
|
|
46227
|
+
.catch((error) => {
|
|
46228
|
+
var _a;
|
|
46229
|
+
this.addLog(`BleManger failed to start. ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
46230
|
+
});
|
|
46354
46231
|
this.connection$.asObservable().subscribe((connection) => {
|
|
46355
46232
|
this.addLog(`connection status is ${connection}`);
|
|
46356
46233
|
});
|
|
@@ -46358,191 +46235,191 @@ class WebBluetoothTransport {
|
|
|
46358
46235
|
this.connection$.next(BLUETOOTH_CONNECTION.DISCONNECTED);
|
|
46359
46236
|
});
|
|
46360
46237
|
}
|
|
46361
|
-
|
|
46362
|
-
|
|
46363
|
-
|
|
46364
|
-
|
|
46238
|
+
addLog(log) {
|
|
46239
|
+
this.logs$.next(log);
|
|
46240
|
+
}
|
|
46241
|
+
isConnected() {
|
|
46242
|
+
const connection = this.connection$.getValue();
|
|
46243
|
+
return connection === BLUETOOTH_CONNECTION.CONNECTED;
|
|
46365
46244
|
}
|
|
46366
46245
|
_autoConnect(selectedDevice$) {
|
|
46246
|
+
const selectedDeviceAfterDisconnect$ = this.onDisconnected$.pipe(switchMap(() => selectedDevice$));
|
|
46367
46247
|
return this._isAutoConnectEnabled$.pipe(switchMap((isAutoConnectEnabled) => isAutoConnectEnabled
|
|
46368
|
-
? merge(selectedDevice$,
|
|
46369
|
-
: NEVER), switchMap((selectedDevice) =>
|
|
46370
|
-
|
|
46371
|
-
|
|
46372
|
-
|
|
46373
|
-
|
|
46374
|
-
return;
|
|
46375
|
-
}
|
|
46376
|
-
const [devicesError, devices] = yield this._getPairedDevices()
|
|
46377
|
-
.then((devices) => [null, devices])
|
|
46378
|
-
.catch((error) => [error, null]);
|
|
46379
|
-
if (devicesError) {
|
|
46380
|
-
throw new Error(`failed to get devices: ${(_a = devicesError === null || devicesError === void 0 ? void 0 : devicesError.message) !== null && _a !== void 0 ? _a : devicesError}`);
|
|
46381
|
-
}
|
|
46382
|
-
this.addLog(`Auto connect: found ${devices.length} devices ${devices
|
|
46383
|
-
.map(({ name }) => name)
|
|
46384
|
-
.join(", ")}`);
|
|
46385
|
-
// @important - Using `findLast` instead of `find` because somehow the browser
|
|
46386
|
-
// is finding multiple peripherals with the same name
|
|
46387
|
-
const device = devices.findLast((device) => device.name === deviceNickname);
|
|
46388
|
-
if (!device) {
|
|
46389
|
-
throw new Error(`couldn't find selected device in the list of paired devices.`);
|
|
46390
|
-
}
|
|
46391
|
-
this.addLog(`Auto connect: ${deviceNickname} was detected and previously paired`);
|
|
46392
|
-
return device;
|
|
46393
|
-
})), tap(() => {
|
|
46394
|
-
this.connection$.next(BLUETOOTH_CONNECTION.SCANNING);
|
|
46395
|
-
}), switchMap((device) => onAdvertisementReceived(device)), switchMap((advertisement) => __awaiter$d(this, void 0, void 0, function* () {
|
|
46396
|
-
this.addLog(`Advertisement received for ${advertisement.device.name}`);
|
|
46397
|
-
return yield this.getServerServiceAndCharacteristics(advertisement.device);
|
|
46248
|
+
? merge(selectedDevice$, selectedDeviceAfterDisconnect$)
|
|
46249
|
+
: NEVER), switchMap((selectedDevice) => this.scan().pipe(switchMap((peripherals) => {
|
|
46250
|
+
const peripheralMatch = peripherals.find((peripheral) => peripheral.name === (selectedDevice === null || selectedDevice === void 0 ? void 0 : selectedDevice.deviceNickname));
|
|
46251
|
+
return peripheralMatch ? of(peripheralMatch) : NEVER;
|
|
46252
|
+
}), distinct((peripheral) => peripheral.id), take(1))), switchMap((peripheral) => __awaiter$e(this, void 0, void 0, function* () {
|
|
46253
|
+
return yield this.connect(peripheral);
|
|
46398
46254
|
})));
|
|
46399
46255
|
}
|
|
46400
46256
|
enableAutoConnect(autoConnect) {
|
|
46401
46257
|
this._isAutoConnectEnabled$.next(autoConnect);
|
|
46402
46258
|
}
|
|
46403
|
-
addLog(log) {
|
|
46404
|
-
this.logs$.next(log);
|
|
46405
|
-
}
|
|
46406
|
-
isConnected() {
|
|
46407
|
-
const connection = this.connection$.getValue();
|
|
46408
|
-
return connection === BLUETOOTH_CONNECTION.CONNECTED;
|
|
46409
|
-
}
|
|
46410
46259
|
connection() {
|
|
46411
46260
|
return this.connectionStream$;
|
|
46412
46261
|
}
|
|
46413
|
-
|
|
46414
|
-
return
|
|
46415
|
-
|
|
46416
|
-
|
|
46417
|
-
|
|
46418
|
-
|
|
46419
|
-
|
|
46420
|
-
|
|
46421
|
-
|
|
46422
|
-
}
|
|
46423
|
-
});
|
|
46262
|
+
_fromEvent(eventName) {
|
|
46263
|
+
return fromEventPattern((addHandler) => {
|
|
46264
|
+
this.bleManagerEmitter.addListener(eventName, addHandler);
|
|
46265
|
+
}, () => {
|
|
46266
|
+
this.bleManagerEmitter.removeAllListeners(eventName);
|
|
46267
|
+
}).pipe(
|
|
46268
|
+
// @important: we need to share the subscription
|
|
46269
|
+
// to avoid missing events
|
|
46270
|
+
share());
|
|
46424
46271
|
}
|
|
46425
|
-
|
|
46426
|
-
|
|
46272
|
+
scan(options) {
|
|
46273
|
+
var _a, _b, _c;
|
|
46274
|
+
const RESCAN_INTERVAL = 10000; // 10 seconds
|
|
46275
|
+
const seconds = (_a = options === null || options === void 0 ? void 0 : options.seconds) !== null && _a !== void 0 ? _a : RESCAN_INTERVAL / 1000;
|
|
46276
|
+
const once = (_b = options === null || options === void 0 ? void 0 : options.once) !== null && _b !== void 0 ? _b : false;
|
|
46277
|
+
// If we are already connected to a peripheral and start scanning,
|
|
46278
|
+
// be default, it will set the connection status to SCANNING and not
|
|
46279
|
+
// update it back if no device is connected to
|
|
46280
|
+
const skipConnectionUpdate = (_c = options === null || options === void 0 ? void 0 : options.skipConnectionUpdate) !== null && _c !== void 0 ? _c : false;
|
|
46281
|
+
const serviceUUIDs = [BLUETOOTH_PRIMARY_SERVICE_UUID_STRING];
|
|
46282
|
+
const allowDuplicates = true;
|
|
46283
|
+
const scanOptions = {};
|
|
46284
|
+
const scanOnce$ = new Observable((subscriber) => {
|
|
46285
|
+
var _a;
|
|
46427
46286
|
try {
|
|
46428
|
-
this.
|
|
46429
|
-
|
|
46430
|
-
|
|
46431
|
-
}));
|
|
46432
|
-
// Ability to only show selectedDevice if provided
|
|
46433
|
-
const filters = deviceNickname
|
|
46434
|
-
? [
|
|
46435
|
-
{
|
|
46436
|
-
name: deviceNickname
|
|
46437
|
-
}
|
|
46438
|
-
]
|
|
46439
|
-
: prefixes;
|
|
46440
|
-
const device = yield window.navigator.bluetooth.requestDevice({
|
|
46441
|
-
filters: [
|
|
46442
|
-
...filters,
|
|
46443
|
-
{
|
|
46444
|
-
manufacturerData: [
|
|
46445
|
-
{
|
|
46446
|
-
companyIdentifier: BLUETOOTH_COMPANY_IDENTIFIER_HEX
|
|
46447
|
-
}
|
|
46448
|
-
]
|
|
46449
|
-
}
|
|
46450
|
-
],
|
|
46451
|
-
optionalServices: [BLUETOOTH_PRIMARY_SERVICE_UUID_HEX]
|
|
46287
|
+
this.BleManager.scan(serviceUUIDs, seconds, allowDuplicates, scanOptions).then(() => {
|
|
46288
|
+
this.addLog(`BleManger scanning ${once ? "once" : "indefintely"}`);
|
|
46289
|
+
subscriber.next();
|
|
46452
46290
|
});
|
|
46453
|
-
return device;
|
|
46454
46291
|
}
|
|
46455
46292
|
catch (error) {
|
|
46456
|
-
|
|
46293
|
+
this.addLog(`BleManger scanning ${once ? "once" : "indefintely"} failed. ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
46294
|
+
subscriber.error(error);
|
|
46457
46295
|
}
|
|
46296
|
+
return () => {
|
|
46297
|
+
this.BleManager.stopScan();
|
|
46298
|
+
};
|
|
46458
46299
|
});
|
|
46300
|
+
const scan$ = once
|
|
46301
|
+
? scanOnce$
|
|
46302
|
+
: timer(0, RESCAN_INTERVAL).pipe(switchMap(() => scanOnce$));
|
|
46303
|
+
const peripherals$ = scan$.pipe(tap(() => {
|
|
46304
|
+
if (!skipConnectionUpdate) {
|
|
46305
|
+
this.connection$.next(BLUETOOTH_CONNECTION.SCANNING);
|
|
46306
|
+
}
|
|
46307
|
+
}), takeUntil(this.onDisconnected$), switchMap(() => this.bleEvents.discoverPeripheral$),
|
|
46308
|
+
// Filter out devices that are not Neurosity devices
|
|
46309
|
+
filter((peripheral) => {
|
|
46310
|
+
var _a, _b, _c;
|
|
46311
|
+
const peripheralName = (_c = (_b = (_a = peripheral === null || peripheral === void 0 ? void 0 : peripheral.advertising) === null || _a === void 0 ? void 0 : _a.localName) !== null && _b !== void 0 ? _b : peripheral.name) !== null && _c !== void 0 ? _c : "";
|
|
46312
|
+
if (!peripheralName) {
|
|
46313
|
+
return false;
|
|
46314
|
+
}
|
|
46315
|
+
const startsWithPrefix = BLUETOOTH_DEVICE_NAME_PREFIXES.findIndex((prefix) => peripheralName.startsWith(prefix)) !== -1;
|
|
46316
|
+
return startsWithPrefix;
|
|
46317
|
+
}), scan((acc, peripheral) => {
|
|
46318
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
46319
|
+
// normalized peripheral name for backwards compatibility
|
|
46320
|
+
// Neurosity OS v15 doesn't have peripheral.name as deviceNickname
|
|
46321
|
+
// it only has peripheral.advertising.localName as deviceNickname
|
|
46322
|
+
// and OS v16 has both as deviceNickname
|
|
46323
|
+
const peripheralName = (_c = (_b = (_a = peripheral === null || peripheral === void 0 ? void 0 : peripheral.advertising) === null || _a === void 0 ? void 0 : _a.localName) !== null && _b !== void 0 ? _b : peripheral.name) !== null && _c !== void 0 ? _c : "";
|
|
46324
|
+
const manufactureDataString = (_h = (_g = decode$1(this.type, (_f = (_e = (_d = peripheral === null || peripheral === void 0 ? void 0 : peripheral.advertising) === null || _d === void 0 ? void 0 : _d.manufacturerData) === null || _e === void 0 ? void 0 : _e.bytes) !== null && _f !== void 0 ? _f : [])) === null || _g === void 0 ? void 0 : _g.slice) === null || _h === void 0 ? void 0 : _h.call(_g, 2); // First 2 bytes are reserved for the Neurosity company code
|
|
46325
|
+
return Object.assign(Object.assign({}, acc), { [peripheral.id]: Object.assign(Object.assign({}, peripheral), { name: peripheralName, manufactureDataString }) });
|
|
46326
|
+
}, {}), distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)), map((peripheralMap) => Object.values(peripheralMap)), share());
|
|
46327
|
+
return peripherals$;
|
|
46459
46328
|
}
|
|
46460
|
-
|
|
46461
|
-
return __awaiter$
|
|
46462
|
-
|
|
46463
|
-
|
|
46464
|
-
|
|
46465
|
-
|
|
46329
|
+
connect(peripheral) {
|
|
46330
|
+
return __awaiter$e(this, void 0, void 0, function* () {
|
|
46331
|
+
return new Promise((resolve, reject) => __awaiter$e(this, void 0, void 0, function* () {
|
|
46332
|
+
try {
|
|
46333
|
+
if (!peripheral) {
|
|
46334
|
+
this.addLog("Peripheral not found");
|
|
46335
|
+
return;
|
|
46336
|
+
}
|
|
46466
46337
|
this.connection$.next(BLUETOOTH_CONNECTION.CONNECTING);
|
|
46338
|
+
yield this.BleManager.connect(peripheral.id);
|
|
46339
|
+
this.addLog(`Getting service...`);
|
|
46340
|
+
const peripheralInfo = yield this.BleManager.retrieveServices(peripheral.id, [
|
|
46341
|
+
BLUETOOTH_PRIMARY_SERVICE_UUID_STRING
|
|
46342
|
+
]);
|
|
46343
|
+
if (!peripheralInfo) {
|
|
46344
|
+
this.addLog("Could not retreive services");
|
|
46345
|
+
reject(new Error(`Could not retreive services`));
|
|
46346
|
+
return;
|
|
46347
|
+
}
|
|
46348
|
+
this.addLog(`Got service ${BLUETOOTH_PRIMARY_SERVICE_UUID_STRING}, getting characteristics...`);
|
|
46349
|
+
this.device = peripheral;
|
|
46350
|
+
this.characteristicsByName = Object.fromEntries(peripheralInfo.characteristics.map((characteristic) => [
|
|
46351
|
+
CHARACTERISTIC_UUIDS_TO_NAMES[characteristic.characteristic.toLowerCase() // react native uses uppercase
|
|
46352
|
+
],
|
|
46353
|
+
{
|
|
46354
|
+
characteristicUUID: characteristic.characteristic,
|
|
46355
|
+
serviceUUID: characteristic.service,
|
|
46356
|
+
peripheralId: peripheral.id
|
|
46357
|
+
}
|
|
46358
|
+
]));
|
|
46359
|
+
this.addLog(`Got characteristics.`);
|
|
46360
|
+
if (this.platform === "android") {
|
|
46361
|
+
yield this.BleManager.requestMTU(peripheral.id, ANDROID_MAX_MTU)
|
|
46362
|
+
.then((updatedMTU) => {
|
|
46363
|
+
this.addLog(`Successfully updated Android MTU to ${updatedMTU} bytes. Requested MTU: ${ANDROID_MAX_MTU} bytes.`);
|
|
46364
|
+
})
|
|
46365
|
+
.catch((error) => {
|
|
46366
|
+
this.addLog(`Failed to set Android MTU of ${ANDROID_MAX_MTU} bytes. Error: ${error}`);
|
|
46367
|
+
});
|
|
46368
|
+
}
|
|
46369
|
+
this.addLog(`Successfully connected to peripheral ${peripheral.id}`);
|
|
46370
|
+
this.connection$.next(BLUETOOTH_CONNECTION.CONNECTED);
|
|
46371
|
+
resolve();
|
|
46467
46372
|
}
|
|
46468
|
-
|
|
46469
|
-
|
|
46470
|
-
|
|
46471
|
-
|
|
46472
|
-
const characteristicsList = yield this.service.getCharacteristics();
|
|
46473
|
-
this.addLog(`Got characteristics`);
|
|
46474
|
-
this.characteristicsByName = Object.fromEntries(characteristicsList.map((characteristic) => [
|
|
46475
|
-
CHARACTERISTIC_UUIDS_TO_NAMES[characteristic.uuid],
|
|
46476
|
-
characteristic
|
|
46477
|
-
]));
|
|
46478
|
-
this.connection$.next(BLUETOOTH_CONNECTION.CONNECTED);
|
|
46479
|
-
}
|
|
46480
|
-
catch (error) {
|
|
46481
|
-
return Promise.reject(error);
|
|
46482
|
-
}
|
|
46373
|
+
catch (error) {
|
|
46374
|
+
reject(error);
|
|
46375
|
+
}
|
|
46376
|
+
}));
|
|
46483
46377
|
});
|
|
46484
46378
|
}
|
|
46485
|
-
_onDisconnected() {
|
|
46486
|
-
return this.connection$
|
|
46487
|
-
.asObservable()
|
|
46488
|
-
.pipe(switchMap((connection) => connection === BLUETOOTH_CONNECTION.CONNECTED
|
|
46489
|
-
? fromDOMEvent(this.device, "gattserverdisconnected")
|
|
46490
|
-
: NEVER));
|
|
46491
|
-
}
|
|
46492
46379
|
disconnect() {
|
|
46493
|
-
var _a
|
|
46494
|
-
return __awaiter$
|
|
46495
|
-
|
|
46496
|
-
|
|
46497
|
-
|
|
46380
|
+
var _a;
|
|
46381
|
+
return __awaiter$e(this, void 0, void 0, function* () {
|
|
46382
|
+
try {
|
|
46383
|
+
if (this.isConnected() && ((_a = this === null || this === void 0 ? void 0 : this.device) === null || _a === void 0 ? void 0 : _a.id)) {
|
|
46384
|
+
yield this.BleManager.disconnect(this.device.id);
|
|
46385
|
+
}
|
|
46386
|
+
}
|
|
46387
|
+
catch (error) {
|
|
46388
|
+
return Promise.reject(error);
|
|
46498
46389
|
}
|
|
46499
46390
|
});
|
|
46500
46391
|
}
|
|
46501
|
-
/**
|
|
46502
|
-
*
|
|
46503
|
-
* Bluetooth GATT attributes, services, characteristics, etc. are invalidated
|
|
46504
|
-
* when a device disconnects. This means your code should always retrieve
|
|
46505
|
-
* (through getPrimaryService(s), getCharacteristic(s), etc.) these attributes
|
|
46506
|
-
* after reconnecting.
|
|
46507
|
-
*/
|
|
46508
46392
|
getCharacteristicByName(characteristicName) {
|
|
46509
46393
|
var _a;
|
|
46510
|
-
|
|
46511
|
-
|
|
46512
|
-
}
|
|
46394
|
+
if (!(characteristicName in this.characteristicsByName)) {
|
|
46395
|
+
throw new Error(`Characteristic by name ${characteristicName} is not found`);
|
|
46396
|
+
}
|
|
46397
|
+
return (_a = this.characteristicsByName) === null || _a === void 0 ? void 0 : _a[characteristicName];
|
|
46513
46398
|
}
|
|
46514
46399
|
subscribeToCharacteristic({ characteristicName, manageNotifications = true }) {
|
|
46515
|
-
const
|
|
46400
|
+
const getData = ({ peripheralId, serviceUUID, characteristicUUID }) => defer(() => __awaiter$e(this, void 0, void 0, function* () {
|
|
46516
46401
|
var _a;
|
|
46517
|
-
if (
|
|
46402
|
+
if (manageNotifications) {
|
|
46518
46403
|
try {
|
|
46519
|
-
yield
|
|
46404
|
+
yield this.BleManager.startNotification(peripheralId, serviceUUID, characteristicUUID);
|
|
46520
46405
|
this.addLog(`Started notifications for ${characteristicName} characteristic`);
|
|
46521
46406
|
}
|
|
46522
46407
|
catch (error) {
|
|
46523
46408
|
this.addLog(`Attemped to stop notifications for ${characteristicName} characteristic: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
46524
46409
|
}
|
|
46525
46410
|
}
|
|
46526
|
-
|
|
46527
|
-
|
|
46528
|
-
|
|
46529
|
-
|
|
46530
|
-
|
|
46531
|
-
|
|
46532
|
-
yield characteristic.stopNotifications();
|
|
46533
|
-
this.addLog(`Stopped notifications for ${characteristicName} characteristic`);
|
|
46534
|
-
}
|
|
46535
|
-
catch (error) {
|
|
46536
|
-
this.addLog(`Attemped to stop notifications for ${characteristicName} characteristic: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
46537
|
-
}
|
|
46411
|
+
})).pipe(switchMap(() => this.bleEvents.didUpdateValueForCharacteristic$), finalize(() => __awaiter$e(this, void 0, void 0, function* () {
|
|
46412
|
+
var _b;
|
|
46413
|
+
if (manageNotifications) {
|
|
46414
|
+
try {
|
|
46415
|
+
yield this.BleManager.stopNotification(peripheralId, serviceUUID, characteristicUUID);
|
|
46416
|
+
this.addLog(`Stopped notifications for ${characteristicName} characteristic`);
|
|
46538
46417
|
}
|
|
46539
|
-
|
|
46540
|
-
|
|
46541
|
-
|
|
46542
|
-
|
|
46543
|
-
|
|
46544
|
-
return decoded;
|
|
46545
|
-
}), stitchChunks({ delimiter: BLUETOOTH_CHUNK_DELIMITER }), map((payload) => {
|
|
46418
|
+
catch (error) {
|
|
46419
|
+
this.addLog(`Attemped to stop notifications for ${characteristicName} characteristic: ${(_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error}`);
|
|
46420
|
+
}
|
|
46421
|
+
}
|
|
46422
|
+
})), filter(({ characteristic }) => characteristic === characteristicUUID), map(({ value }) => decode$1(this.type, value)), stitchChunks({ delimiter: BLUETOOTH_CHUNK_DELIMITER }), map((payload) => {
|
|
46546
46423
|
var _a;
|
|
46547
46424
|
try {
|
|
46548
46425
|
return JSON.parse(payload);
|
|
@@ -46551,51 +46428,40 @@ class WebBluetoothTransport {
|
|
|
46551
46428
|
this.addLog(`Failed to parse JSON for ${characteristicName} characteristic. Falling back to unparsed string. ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
46552
46429
|
return payload;
|
|
46553
46430
|
}
|
|
46554
|
-
})
|
|
46555
|
-
|
|
46556
|
-
|
|
46557
|
-
|
|
46558
|
-
// `Received data for ${characteristicName} characteristic: \n${JSON.stringify(
|
|
46559
|
-
// data,
|
|
46560
|
-
// null,
|
|
46561
|
-
// 2
|
|
46562
|
-
// )}`
|
|
46563
|
-
// );
|
|
46564
|
-
// })
|
|
46565
|
-
);
|
|
46566
|
-
return this.connection$.pipe(switchMap((connection) => connection === BLUETOOTH_CONNECTION.CONNECTED ? data$ : NEVER));
|
|
46431
|
+
}));
|
|
46432
|
+
return this.connection$.pipe(switchMap((connection) => connection === BLUETOOTH_CONNECTION.CONNECTED
|
|
46433
|
+
? getData(this.getCharacteristicByName(characteristicName))
|
|
46434
|
+
: NEVER));
|
|
46567
46435
|
}
|
|
46568
46436
|
readCharacteristic(characteristicName, parse = false) {
|
|
46569
|
-
|
|
46437
|
+
var _a;
|
|
46438
|
+
return __awaiter$e(this, void 0, void 0, function* () {
|
|
46439
|
+
this.addLog(`Reading characteristic: ${characteristicName}`);
|
|
46440
|
+
const { peripheralId, serviceUUID, characteristicUUID } = this.getCharacteristicByName(characteristicName);
|
|
46441
|
+
if (!characteristicUUID) {
|
|
46442
|
+
return Promise.reject(new Error(`Did not find characteristic matching ${characteristicName}`));
|
|
46443
|
+
}
|
|
46570
46444
|
try {
|
|
46571
|
-
this.
|
|
46572
|
-
const
|
|
46573
|
-
if (!characteristic) {
|
|
46574
|
-
this.addLog(`Did not fund ${characteristicName} characteristic`);
|
|
46575
|
-
return Promise.reject(`Did not find characteristic by the name: ${characteristicName}`);
|
|
46576
|
-
}
|
|
46577
|
-
const value = yield characteristic.readValue();
|
|
46578
|
-
const uint8Array = value;
|
|
46579
|
-
const decodedValue = decode$1(this.type, uint8Array);
|
|
46445
|
+
const value = yield this.BleManager.read(peripheralId, serviceUUID, characteristicUUID);
|
|
46446
|
+
const decodedValue = decode$1(this.type, value);
|
|
46580
46447
|
const data = parse ? JSON.parse(decodedValue) : decodedValue;
|
|
46581
46448
|
this.addLog(`Received read data from ${characteristicName} characteristic: \n${data}`);
|
|
46582
46449
|
return data;
|
|
46583
46450
|
}
|
|
46584
46451
|
catch (error) {
|
|
46585
|
-
return Promise.reject(`
|
|
46452
|
+
return Promise.reject(new Error(`readCharacteristic ${characteristicName} error. ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`));
|
|
46586
46453
|
}
|
|
46587
46454
|
});
|
|
46588
46455
|
}
|
|
46589
46456
|
writeCharacteristic(characteristicName, data) {
|
|
46590
|
-
return __awaiter$
|
|
46457
|
+
return __awaiter$e(this, void 0, void 0, function* () {
|
|
46591
46458
|
this.addLog(`Writing characteristic: ${characteristicName}`);
|
|
46592
|
-
const
|
|
46593
|
-
if (!
|
|
46594
|
-
|
|
46595
|
-
return Promise.reject(`Did not find characteristic by the name: ${characteristicName}`);
|
|
46459
|
+
const { peripheralId, serviceUUID, characteristicUUID } = this.getCharacteristicByName(characteristicName);
|
|
46460
|
+
if (!characteristicUUID) {
|
|
46461
|
+
return Promise.reject(new Error(`Did not find characteristic matching ${characteristicName}`));
|
|
46596
46462
|
}
|
|
46597
46463
|
const encoded = encode$1(this.type, data);
|
|
46598
|
-
yield
|
|
46464
|
+
yield this.BleManager.write(peripheralId, serviceUUID, characteristicUUID, encoded, REACT_NATIVE_MAX_BYTE_SIZE);
|
|
46599
46465
|
});
|
|
46600
46466
|
}
|
|
46601
46467
|
_addPendingAction(actionId) {
|
|
@@ -46606,54 +46472,40 @@ class WebBluetoothTransport {
|
|
|
46606
46472
|
const actions = this.pendingActions$.getValue();
|
|
46607
46473
|
this.pendingActions$.next(actions.filter((id) => id !== actionId));
|
|
46608
46474
|
}
|
|
46609
|
-
_autoToggleActionNotifications(
|
|
46610
|
-
|
|
46611
|
-
|
|
46612
|
-
|
|
46613
|
-
|
|
46614
|
-
|
|
46615
|
-
|
|
46616
|
-
|
|
46617
|
-
|
|
46618
|
-
|
|
46619
|
-
|
|
46620
|
-
|
|
46621
|
-
|
|
46622
|
-
started = true;
|
|
46623
|
-
try {
|
|
46624
|
-
yield actionsCharacteristic.startNotifications();
|
|
46625
|
-
this.addLog(`Started notifications for [actions] characteristic`);
|
|
46626
|
-
}
|
|
46627
|
-
catch (error) {
|
|
46628
|
-
this.addLog(`Attemped to start notifications for [actions] characteristic: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
46629
|
-
}
|
|
46475
|
+
_autoToggleActionNotifications() {
|
|
46476
|
+
let started = false;
|
|
46477
|
+
return this.connection$.asObservable().pipe(switchMap((connection) => connection === BLUETOOTH_CONNECTION.CONNECTED
|
|
46478
|
+
? this.pendingActions$
|
|
46479
|
+
: NEVER), tap((pendingActions) => __awaiter$e(this, void 0, void 0, function* () {
|
|
46480
|
+
var _a, _b;
|
|
46481
|
+
const { peripheralId, serviceUUID, characteristicUUID } = this.getCharacteristicByName("actions");
|
|
46482
|
+
const hasPendingActions = !!pendingActions.length;
|
|
46483
|
+
if (hasPendingActions && !started) {
|
|
46484
|
+
started = true;
|
|
46485
|
+
try {
|
|
46486
|
+
yield this.BleManager.startNotification(peripheralId, serviceUUID, characteristicUUID);
|
|
46487
|
+
this.addLog(`Started notifications for [actions] characteristic`);
|
|
46630
46488
|
}
|
|
46631
|
-
|
|
46632
|
-
|
|
46633
|
-
try {
|
|
46634
|
-
yield actionsCharacteristic.stopNotifications();
|
|
46635
|
-
this.addLog(`Stopped notifications for actions characteristic`);
|
|
46636
|
-
}
|
|
46637
|
-
catch (error) {
|
|
46638
|
-
this.addLog(`Attemped to stop notifications for [actions] characteristic: ${(_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error}`);
|
|
46639
|
-
}
|
|
46489
|
+
catch (error) {
|
|
46490
|
+
this.addLog(`Attemped to start notifications for [actions] characteristic: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
46640
46491
|
}
|
|
46641
|
-
}
|
|
46642
|
-
|
|
46643
|
-
|
|
46644
|
-
|
|
46645
|
-
|
|
46492
|
+
}
|
|
46493
|
+
if (!hasPendingActions && started) {
|
|
46494
|
+
started = false;
|
|
46495
|
+
try {
|
|
46496
|
+
yield this.BleManager.stopNotification(peripheralId, serviceUUID, characteristicUUID);
|
|
46497
|
+
this.addLog(`Stopped notifications for actions characteristic`);
|
|
46498
|
+
}
|
|
46499
|
+
catch (error) {
|
|
46500
|
+
this.addLog(`Attemped to stop notifications for [actions] characteristic: ${(_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error}`);
|
|
46501
|
+
}
|
|
46502
|
+
}
|
|
46503
|
+
})));
|
|
46646
46504
|
}
|
|
46647
46505
|
dispatchAction({ characteristicName, action }) {
|
|
46648
|
-
return __awaiter$
|
|
46506
|
+
return __awaiter$e(this, void 0, void 0, function* () {
|
|
46649
46507
|
const { responseRequired = false, responseTimeout = DEFAULT_ACTION_RESPONSE_TIMEOUT } = action;
|
|
46650
|
-
return new Promise((resolve, reject) => __awaiter$
|
|
46651
|
-
const characteristic = yield this.getCharacteristicByName(characteristicName).catch(() => {
|
|
46652
|
-
reject(`Did not find characteristic by the name: ${characteristicName}`);
|
|
46653
|
-
});
|
|
46654
|
-
if (!characteristic) {
|
|
46655
|
-
return;
|
|
46656
|
-
}
|
|
46508
|
+
return new Promise((resolve, reject) => __awaiter$e(this, void 0, void 0, function* () {
|
|
46657
46509
|
const actionId = create6DigitPin(); // use to later identify and filter response
|
|
46658
46510
|
const payload = JSON.stringify(Object.assign({ actionId }, action)); // add the response id to the action
|
|
46659
46511
|
this.addLog(`Dispatched action with id ${actionId}`);
|
|
@@ -46661,7 +46513,7 @@ class WebBluetoothTransport {
|
|
|
46661
46513
|
this._addPendingAction(actionId);
|
|
46662
46514
|
const timeout$$1 = timer(responseTimeout).subscribe(() => {
|
|
46663
46515
|
this._removePendingAction(actionId);
|
|
46664
|
-
reject(`Action with id ${actionId} timed out after ${responseTimeout}ms`);
|
|
46516
|
+
reject(new Error(`Action with id ${actionId} timed out after ${responseTimeout}ms`));
|
|
46665
46517
|
});
|
|
46666
46518
|
// listen for a response before writing
|
|
46667
46519
|
this.subscribeToCharacteristic({
|
|
@@ -46677,7 +46529,7 @@ class WebBluetoothTransport {
|
|
|
46677
46529
|
// register action by writing
|
|
46678
46530
|
this.writeCharacteristic(characteristicName, payload).catch((error) => {
|
|
46679
46531
|
this._removePendingAction(actionId);
|
|
46680
|
-
reject(error
|
|
46532
|
+
reject(error);
|
|
46681
46533
|
});
|
|
46682
46534
|
}
|
|
46683
46535
|
else {
|
|
@@ -46686,48 +46538,108 @@ class WebBluetoothTransport {
|
|
|
46686
46538
|
resolve(null);
|
|
46687
46539
|
})
|
|
46688
46540
|
.catch((error) => {
|
|
46689
|
-
reject(error
|
|
46541
|
+
reject(error);
|
|
46690
46542
|
});
|
|
46691
46543
|
}
|
|
46692
46544
|
}));
|
|
46693
46545
|
});
|
|
46694
46546
|
}
|
|
46695
46547
|
}
|
|
46696
|
-
|
|
46697
|
-
|
|
46698
|
-
|
|
46699
|
-
|
|
46700
|
-
|
|
46701
|
-
|
|
46702
|
-
|
|
46703
|
-
|
|
46548
|
+
|
|
46549
|
+
const defaultDataProp = "data";
|
|
46550
|
+
const defaultSamplingRate = 256;
|
|
46551
|
+
const isObject$2 = (object) => object instanceof Object && object === Object(object);
|
|
46552
|
+
const isFunction$2 = (object) => typeof object === "function";
|
|
46553
|
+
const patch = (sample$$1) => (info) => {
|
|
46554
|
+
var _a;
|
|
46555
|
+
return (Object.assign(Object.assign({}, sample$$1), { info: Object.assign(Object.assign({}, ((_a = sample$$1 === null || sample$$1 === void 0 ? void 0 : sample$$1.info) !== null && _a !== void 0 ? _a : {})), (info || {})) }));
|
|
46556
|
+
};
|
|
46557
|
+
/**
|
|
46558
|
+
* Annotates stream with user-defined metadata
|
|
46559
|
+
* @method addInfo
|
|
46560
|
+
* @example eeg$.pipe(addinfo({ samplingRate: 256, channelNames: ["Af7", "Fp1", "Fp2", "Af8"] })
|
|
46561
|
+
* @param {Object} info Info to be added to the EEG stream. Relevant info may include: `samplingRate` and `channelNames`
|
|
46562
|
+
* @returns {Observable<Sample|Epoch|PSD>}
|
|
46563
|
+
*/
|
|
46564
|
+
const addInfo = (infoValue) => pipe(map((sample$$1) => {
|
|
46565
|
+
if (!isObject$2(sample$$1) ||
|
|
46566
|
+
(!isObject$2(infoValue) && !isFunction$2(infoValue))) {
|
|
46567
|
+
return sample$$1;
|
|
46568
|
+
}
|
|
46569
|
+
const info = isFunction$2(infoValue) ? infoValue(sample$$1) : infoValue;
|
|
46570
|
+
return patch(sample$$1)(info);
|
|
46571
|
+
}));
|
|
46572
|
+
/**
|
|
46573
|
+
* Get a 2D data array organized by channel from an array of Samples. Credit to Ken from Seattle's elegant transposition
|
|
46574
|
+
* http://www.codesuck.com/2012/02/transpose-javascript-array-in-one-line.html
|
|
46575
|
+
* @method groupByChannel
|
|
46576
|
+
* @param {Array<Sample>} samplesBuffer Array of Samples to be grouped
|
|
46577
|
+
* @param {string} [dataProp] Name of the key associated with EEG data
|
|
46578
|
+
* @returns {Array<Array<number>>}
|
|
46579
|
+
*/
|
|
46580
|
+
const groupByChannel = (samplesBuffer, dataProp = defaultDataProp) => samplesBuffer[0][dataProp].map((_, channelIndex) => samplesBuffer.map((sample$$1) => sample$$1[dataProp][channelIndex]));
|
|
46581
|
+
/**
|
|
46582
|
+
* Takes an array or RxJS buffer of EEG Samples and returns an Epoch.
|
|
46583
|
+
* @method bufferToEpoch
|
|
46584
|
+
* @example eeg$.pipe(bufferTime(1000), bufferToEpoch({ samplingRate: 256 }))
|
|
46585
|
+
*
|
|
46586
|
+
* @param {Object} options - Data structure options
|
|
46587
|
+
* @param {number} [options.samplingRate] Sampling rate
|
|
46588
|
+
* @param {string} [options.dataProp='data'] Name of the key associated with eeg data
|
|
46589
|
+
*
|
|
46590
|
+
* @returns {Observable<Epoch>}
|
|
46591
|
+
*/
|
|
46592
|
+
const bufferToEpoch = ({ samplingRate = defaultSamplingRate, dataProp = defaultDataProp } = {}) => pipe(map((samplesArray) => ({
|
|
46593
|
+
[dataProp]: groupByChannel(samplesArray, dataProp),
|
|
46594
|
+
info: Object.assign(Object.assign({}, (samplesArray[0] && samplesArray[0].info
|
|
46595
|
+
? samplesArray[0].info
|
|
46596
|
+
: {})), { startTime: samplesArray[0].timestamp, samplingRate: samplesArray[0].info && samplesArray[0].info.samplingRate
|
|
46597
|
+
? samplesArray[0].info.samplingRate
|
|
46598
|
+
: samplingRate })
|
|
46599
|
+
})));
|
|
46600
|
+
/**
|
|
46601
|
+
* Converts a stream of individual Samples of EEG data into a stream of Epochs of a given duration emitted at specified interval. This operator functions similarly to a circular buffer internally and allows overlapping Epochs of data to be emitted (e.g. emitting the last one second of data every 100ms).
|
|
46602
|
+
* @method epoch
|
|
46603
|
+
* @example eeg$.pipe(epoch({ duration: 1024, interval: 100, samplingRate: 256 }))
|
|
46604
|
+
* @param {Object} options - Epoching options
|
|
46605
|
+
* @param {number} [options.duration=256] Number of samples to include in each epoch
|
|
46606
|
+
* @param {number} [options.interval=100] Time (ms) between emitted Epochs
|
|
46607
|
+
* @param {number} [options.samplingRate=256] Sampling rate
|
|
46608
|
+
* @param {string} [options.dataProp='data'] Name of the key associated with eeg data
|
|
46609
|
+
* @returns {Observable} Epoch
|
|
46610
|
+
*/
|
|
46611
|
+
const epoch = ({ duration, interval: interval$$1, samplingRate, dataProp = defaultDataProp }) => pipe(bufferCount(interval$$1), scan((acc, val) => acc.concat(val).slice(acc.length < duration ? 0 : -duration)), filter((samplesArray) => samplesArray.length === duration), bufferToEpoch({ samplingRate, dataProp }));
|
|
46612
|
+
|
|
46613
|
+
const EPOCH_BUFFER_SIZE = 16;
|
|
46614
|
+
const SAMPLING_RATE_FALLBACK = 256; // Crown's sampling rate
|
|
46615
|
+
/**
|
|
46616
|
+
* @hidden
|
|
46617
|
+
*/
|
|
46618
|
+
function csvBufferToEpoch(deviceInfo) {
|
|
46619
|
+
var _a;
|
|
46620
|
+
if (!(deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.samplingRate)) {
|
|
46621
|
+
console.warn(`Didn't receive a sampling rate, defaulting to ${SAMPLING_RATE_FALLBACK}`);
|
|
46622
|
+
}
|
|
46623
|
+
return pipe(csvBufferToSamples(), epoch({
|
|
46624
|
+
duration: EPOCH_BUFFER_SIZE,
|
|
46625
|
+
interval: EPOCH_BUFFER_SIZE,
|
|
46626
|
+
samplingRate: (_a = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.samplingRate) !== null && _a !== void 0 ? _a : SAMPLING_RATE_FALLBACK
|
|
46627
|
+
}), addInfo({
|
|
46628
|
+
channelNames: deviceInfo.channelNames,
|
|
46629
|
+
samplingRate: deviceInfo.samplingRate
|
|
46704
46630
|
}));
|
|
46705
46631
|
}
|
|
46706
|
-
|
|
46707
|
-
|
|
46708
|
-
|
|
46709
|
-
|
|
46710
|
-
|
|
46711
|
-
|
|
46712
|
-
|
|
46713
|
-
|
|
46714
|
-
}, {
|
|
46715
|
-
once: true
|
|
46716
|
-
});
|
|
46717
|
-
try {
|
|
46718
|
-
device.watchAdvertisements({ signal });
|
|
46719
|
-
}
|
|
46720
|
-
catch (error) {
|
|
46721
|
-
subscriber.error(error);
|
|
46722
|
-
}
|
|
46723
|
-
return () => {
|
|
46724
|
-
abortController.abort();
|
|
46725
|
-
device.removeEventListener("advertisementreceived", listener);
|
|
46726
|
-
};
|
|
46727
|
-
});
|
|
46632
|
+
/**
|
|
46633
|
+
* @hidden
|
|
46634
|
+
*/
|
|
46635
|
+
function csvBufferToSamples() {
|
|
46636
|
+
return pipe(mergeMap((samples) => from(samples)), map(([timestamp$$1, marker, ...data]) => ({
|
|
46637
|
+
timestamp: timestamp$$1,
|
|
46638
|
+
data
|
|
46639
|
+
})));
|
|
46728
46640
|
}
|
|
46729
46641
|
|
|
46730
|
-
var __awaiter$
|
|
46642
|
+
var __awaiter$f = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
46731
46643
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
46732
46644
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
46733
46645
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
@@ -46736,783 +46648,872 @@ var __awaiter$e = (undefined && undefined.__awaiter) || function (thisArg, _argu
|
|
|
46736
46648
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
46737
46649
|
});
|
|
46738
46650
|
};
|
|
46739
|
-
|
|
46740
|
-
autoConnect: true
|
|
46741
|
-
};
|
|
46742
|
-
class ReactNativeTransport {
|
|
46651
|
+
class BluetoothClient {
|
|
46743
46652
|
constructor(options) {
|
|
46744
|
-
this.
|
|
46745
|
-
this.
|
|
46746
|
-
this.
|
|
46747
|
-
|
|
46748
|
-
|
|
46749
|
-
|
|
46750
|
-
.asObservable()
|
|
46751
|
-
.pipe(filter((connection) => !!connection), distinctUntilChanged(), shareReplay(1));
|
|
46752
|
-
this._isAutoConnectEnabled$ = new ReplaySubject(1);
|
|
46753
|
-
if (!options) {
|
|
46754
|
-
const errorMessage = "React Native transport: missing options.";
|
|
46755
|
-
this.addLog(errorMessage);
|
|
46756
|
-
throw new Error(errorMessage);
|
|
46757
|
-
}
|
|
46758
|
-
this.options = Object.assign(Object.assign({}, defaultOptions$2), options);
|
|
46759
|
-
const { BleManager, bleManagerEmitter, platform, autoConnect } = this.options;
|
|
46760
|
-
if (!BleManager) {
|
|
46761
|
-
const errorMessage = "React Native option: BleManager not provided.";
|
|
46762
|
-
this.addLog(errorMessage);
|
|
46763
|
-
throw new Error(errorMessage);
|
|
46653
|
+
this.selectedDevice$ = new ReplaySubject(1);
|
|
46654
|
+
this.osHasBluetoothSupport$ = new ReplaySubject(1);
|
|
46655
|
+
this.isAuthenticated$ = new ReplaySubject(1);
|
|
46656
|
+
const { transport, selectedDevice$, osHasBluetoothSupport$, createBluetoothToken } = options !== null && options !== void 0 ? options : {};
|
|
46657
|
+
if (!transport) {
|
|
46658
|
+
throw new Error(`No bluetooth transport provided.`);
|
|
46764
46659
|
}
|
|
46765
|
-
|
|
46766
|
-
|
|
46767
|
-
|
|
46768
|
-
|
|
46660
|
+
this.transport = transport;
|
|
46661
|
+
// Pass events to the internal selectedDevice$ if selectedDevice$ is passed via options
|
|
46662
|
+
if (selectedDevice$) {
|
|
46663
|
+
selectedDevice$.subscribe(this.selectedDevice$);
|
|
46769
46664
|
}
|
|
46770
|
-
if
|
|
46771
|
-
|
|
46772
|
-
this.
|
|
46773
|
-
throw new Error(errorMessage);
|
|
46665
|
+
// Pass events to the internal osHasBluetoothSupport$ if osHasBluetoothSupport$ is passed via options
|
|
46666
|
+
if (osHasBluetoothSupport$) {
|
|
46667
|
+
osHasBluetoothSupport$.subscribe(this.osHasBluetoothSupport$);
|
|
46774
46668
|
}
|
|
46775
|
-
this.
|
|
46776
|
-
|
|
46777
|
-
|
|
46778
|
-
|
|
46779
|
-
|
|
46780
|
-
|
|
46781
|
-
|
|
46782
|
-
|
|
46783
|
-
|
|
46784
|
-
this.bleEvents = {
|
|
46785
|
-
stopScan$: this._fromEvent("BleManagerStopScan"),
|
|
46786
|
-
discoverPeripheral$: this._fromEvent("BleManagerDiscoverPeripheral"),
|
|
46787
|
-
connectPeripheral$: this._fromEvent("BleManagerConnectPeripheral"),
|
|
46788
|
-
disconnectPeripheral$: this._fromEvent("BleManagerDisconnectPeripheral"),
|
|
46789
|
-
didUpdateValueForCharacteristic$: this._fromEvent("BleManagerDidUpdateValueForCharacteristic"),
|
|
46790
|
-
didUpdateState$: this._fromEvent("BleManagerDidUpdateState")
|
|
46791
|
-
};
|
|
46792
|
-
this.onDisconnected$ = this.bleEvents.disconnectPeripheral$.pipe(share());
|
|
46793
|
-
// Initializes the module. This can only be called once.
|
|
46794
|
-
this.BleManager.start({ showAlert: false })
|
|
46795
|
-
.then(() => {
|
|
46796
|
-
this.addLog(`BleManger started`);
|
|
46797
|
-
})
|
|
46798
|
-
.catch((error) => {
|
|
46799
|
-
var _a;
|
|
46800
|
-
this.addLog(`BleManger failed to start. ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
46801
|
-
});
|
|
46802
|
-
this.connection$.asObservable().subscribe((connection) => {
|
|
46803
|
-
this.addLog(`connection status is ${connection}`);
|
|
46669
|
+
this.osHasBluetoothSupport$
|
|
46670
|
+
.pipe(switchMap((osHasBluetoothSupport) => osHasBluetoothSupport
|
|
46671
|
+
? this.transport._autoConnect(this.selectedDevice$)
|
|
46672
|
+
: EMPTY))
|
|
46673
|
+
.subscribe({
|
|
46674
|
+
error: (error) => {
|
|
46675
|
+
var _a;
|
|
46676
|
+
this.transport.addLog(`Auto connect: error -> ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
46677
|
+
}
|
|
46804
46678
|
});
|
|
46805
|
-
|
|
46806
|
-
|
|
46807
|
-
|
|
46808
|
-
|
|
46809
|
-
|
|
46810
|
-
|
|
46811
|
-
|
|
46812
|
-
|
|
46813
|
-
|
|
46814
|
-
|
|
46679
|
+
// Auto authentication
|
|
46680
|
+
if (typeof createBluetoothToken === "function") {
|
|
46681
|
+
this.transport.addLog("Auto authentication enabled");
|
|
46682
|
+
this._autoAuthenticate(createBluetoothToken).subscribe();
|
|
46683
|
+
}
|
|
46684
|
+
else {
|
|
46685
|
+
this.transport.addLog("Auto authentication not enabled");
|
|
46686
|
+
}
|
|
46687
|
+
// Auto manage action notifications
|
|
46688
|
+
this.osHasBluetoothSupport$
|
|
46689
|
+
.pipe(switchMap((osHasBluetoothSupport) => osHasBluetoothSupport
|
|
46690
|
+
? this.transport._autoToggleActionNotifications()
|
|
46691
|
+
: EMPTY))
|
|
46692
|
+
.subscribe();
|
|
46693
|
+
// Multicast metrics (share)
|
|
46694
|
+
this._focus$ = this._subscribeWhileAuthenticated("focus");
|
|
46695
|
+
this._calm$ = this._subscribeWhileAuthenticated("calm");
|
|
46696
|
+
this._accelerometer$ = this._subscribeWhileAuthenticated("accelerometer");
|
|
46697
|
+
this._brainwavesRaw$ = this._subscribeWhileAuthenticated("raw");
|
|
46698
|
+
this._brainwavesRawUnfiltered$ =
|
|
46699
|
+
this._subscribeWhileAuthenticated("rawUnfiltered");
|
|
46700
|
+
this._brainwavesPSD$ = this._subscribeWhileAuthenticated("psd");
|
|
46701
|
+
this._brainwavesPowerByBand$ =
|
|
46702
|
+
this._subscribeWhileAuthenticated("powerByBand");
|
|
46703
|
+
this._signalQuality$ = this._subscribeWhileAuthenticated("signalQuality");
|
|
46704
|
+
this._status$ = this._subscribeWhileAuthenticated("status");
|
|
46705
|
+
this._settings$ = this._subscribeWhileAuthenticated("settings");
|
|
46706
|
+
this._wifiNearbyNetworks$ =
|
|
46707
|
+
this._subscribeWhileAuthenticated("wifiNearbyNetworks");
|
|
46708
|
+
this._wifiConnections$ =
|
|
46709
|
+
this._subscribeWhileAuthenticated("wifiConnections");
|
|
46815
46710
|
}
|
|
46816
|
-
|
|
46817
|
-
const
|
|
46818
|
-
|
|
46819
|
-
|
|
46820
|
-
|
|
46821
|
-
|
|
46822
|
-
|
|
46823
|
-
|
|
46824
|
-
|
|
46825
|
-
|
|
46826
|
-
|
|
46711
|
+
_autoAuthenticate(createBluetoothToken) {
|
|
46712
|
+
const REAUTHENTICATE_INTERVAL = 3600000; // 1 hour
|
|
46713
|
+
const reauthenticateInterval$ = timer(0, REAUTHENTICATE_INTERVAL).pipe(tap(() => {
|
|
46714
|
+
this.transport.addLog(`Auto authentication in progress...`);
|
|
46715
|
+
}));
|
|
46716
|
+
return this.osHasBluetoothSupport$.pipe(switchMap((osHasBluetoothSupport) => osHasBluetoothSupport ? this.connection() : EMPTY), switchMap((connection) => connection === BLUETOOTH_CONNECTION.CONNECTED
|
|
46717
|
+
? reauthenticateInterval$
|
|
46718
|
+
: EMPTY), switchMap(() => __awaiter$f(this, void 0, void 0, function* () { return yield this.isAuthenticated(); })), tap(([isAuthenticated]) => __awaiter$f(this, void 0, void 0, function* () {
|
|
46719
|
+
if (!isAuthenticated) {
|
|
46720
|
+
const token = yield createBluetoothToken();
|
|
46721
|
+
yield this.authenticate(token);
|
|
46722
|
+
}
|
|
46723
|
+
else {
|
|
46724
|
+
this.transport.addLog(`Already authenticated`);
|
|
46725
|
+
}
|
|
46827
46726
|
})));
|
|
46828
46727
|
}
|
|
46829
46728
|
enableAutoConnect(autoConnect) {
|
|
46830
|
-
this.
|
|
46831
|
-
}
|
|
46832
|
-
connection() {
|
|
46833
|
-
return this.connectionStream$;
|
|
46729
|
+
this.transport.enableAutoConnect(autoConnect);
|
|
46834
46730
|
}
|
|
46835
|
-
|
|
46836
|
-
return
|
|
46837
|
-
this.
|
|
46838
|
-
}
|
|
46839
|
-
this.bleManagerEmitter.removeAllListeners(eventName);
|
|
46840
|
-
}).pipe(
|
|
46841
|
-
// @important: we need to share the subscription
|
|
46842
|
-
// to avoid missing events
|
|
46843
|
-
share());
|
|
46731
|
+
_hasBluetoothSupport() {
|
|
46732
|
+
return __awaiter$f(this, void 0, void 0, function* () {
|
|
46733
|
+
return yield firstValueFrom(this.osHasBluetoothSupport$);
|
|
46734
|
+
});
|
|
46844
46735
|
}
|
|
46845
|
-
|
|
46846
|
-
|
|
46847
|
-
|
|
46848
|
-
|
|
46849
|
-
|
|
46850
|
-
|
|
46851
|
-
|
|
46852
|
-
// update it back if no device is connected to
|
|
46853
|
-
const skipConnectionUpdate = (_c = options === null || options === void 0 ? void 0 : options.skipConnectionUpdate) !== null && _c !== void 0 ? _c : false;
|
|
46854
|
-
const serviceUUIDs = [BLUETOOTH_PRIMARY_SERVICE_UUID_STRING];
|
|
46855
|
-
const allowDuplicates = true;
|
|
46856
|
-
const scanOptions = {};
|
|
46857
|
-
const scanOnce$ = new Observable((subscriber) => {
|
|
46858
|
-
var _a;
|
|
46859
|
-
try {
|
|
46860
|
-
this.BleManager.scan(serviceUUIDs, seconds, allowDuplicates, scanOptions).then(() => {
|
|
46861
|
-
this.addLog(`BleManger scanning ${once ? "once" : "indefintely"}`);
|
|
46862
|
-
subscriber.next();
|
|
46863
|
-
});
|
|
46864
|
-
}
|
|
46865
|
-
catch (error) {
|
|
46866
|
-
this.addLog(`BleManger scanning ${once ? "once" : "indefintely"} failed. ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
46867
|
-
subscriber.error(error);
|
|
46736
|
+
authenticate(token) {
|
|
46737
|
+
return __awaiter$f(this, void 0, void 0, function* () {
|
|
46738
|
+
const hasBluetoothSupport = yield this._hasBluetoothSupport();
|
|
46739
|
+
if (!hasBluetoothSupport) {
|
|
46740
|
+
const errorMessage = `authenticate method: The OS version does not support Bluetooth.`;
|
|
46741
|
+
this.transport.addLog(errorMessage);
|
|
46742
|
+
return Promise.reject(errorMessage);
|
|
46868
46743
|
}
|
|
46869
|
-
|
|
46870
|
-
|
|
46871
|
-
|
|
46744
|
+
yield this.transport.writeCharacteristic("auth", token);
|
|
46745
|
+
const isAuthenticatedResponse = yield this.isAuthenticated();
|
|
46746
|
+
const [isAuthenticated] = isAuthenticatedResponse;
|
|
46747
|
+
this.transport.addLog(`Authentication ${isAuthenticated ? "succeeded" : "failed"}`);
|
|
46748
|
+
this.isAuthenticated$.next(isAuthenticated);
|
|
46749
|
+
return isAuthenticatedResponse;
|
|
46872
46750
|
});
|
|
46873
|
-
const scan$ = once
|
|
46874
|
-
? scanOnce$
|
|
46875
|
-
: timer(0, RESCAN_INTERVAL).pipe(switchMap(() => scanOnce$));
|
|
46876
|
-
const peripherals$ = scan$.pipe(tap(() => {
|
|
46877
|
-
if (!skipConnectionUpdate) {
|
|
46878
|
-
this.connection$.next(BLUETOOTH_CONNECTION.SCANNING);
|
|
46879
|
-
}
|
|
46880
|
-
}), takeUntil(this.onDisconnected$), switchMap(() => this.bleEvents.discoverPeripheral$),
|
|
46881
|
-
// Filter out devices that are not Neurosity devices
|
|
46882
|
-
filter((peripheral) => {
|
|
46883
|
-
var _a, _b, _c;
|
|
46884
|
-
const peripheralName = (_c = (_b = (_a = peripheral === null || peripheral === void 0 ? void 0 : peripheral.advertising) === null || _a === void 0 ? void 0 : _a.localName) !== null && _b !== void 0 ? _b : peripheral.name) !== null && _c !== void 0 ? _c : "";
|
|
46885
|
-
if (!peripheralName) {
|
|
46886
|
-
return false;
|
|
46887
|
-
}
|
|
46888
|
-
const startsWithPrefix = BLUETOOTH_DEVICE_NAME_PREFIXES.findIndex((prefix) => peripheralName.startsWith(prefix)) !== -1;
|
|
46889
|
-
return startsWithPrefix;
|
|
46890
|
-
}), scan((acc, peripheral) => {
|
|
46891
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
46892
|
-
// normalized peripheral name for backwards compatibility
|
|
46893
|
-
// Neurosity OS v15 doesn't have peripheral.name as deviceNickname
|
|
46894
|
-
// it only has peripheral.advertising.localName as deviceNickname
|
|
46895
|
-
// and OS v16 has both as deviceNickname
|
|
46896
|
-
const peripheralName = (_c = (_b = (_a = peripheral === null || peripheral === void 0 ? void 0 : peripheral.advertising) === null || _a === void 0 ? void 0 : _a.localName) !== null && _b !== void 0 ? _b : peripheral.name) !== null && _c !== void 0 ? _c : "";
|
|
46897
|
-
const manufactureDataString = (_h = (_g = decode$1(this.type, (_f = (_e = (_d = peripheral === null || peripheral === void 0 ? void 0 : peripheral.advertising) === null || _d === void 0 ? void 0 : _d.manufacturerData) === null || _e === void 0 ? void 0 : _e.bytes) !== null && _f !== void 0 ? _f : [])) === null || _g === void 0 ? void 0 : _g.slice) === null || _h === void 0 ? void 0 : _h.call(_g, 2); // First 2 bytes are reserved for the Neurosity company code
|
|
46898
|
-
return Object.assign(Object.assign({}, acc), { [peripheral.id]: Object.assign(Object.assign({}, peripheral), { name: peripheralName, manufactureDataString }) });
|
|
46899
|
-
}, {}), distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)), map((peripheralMap) => Object.values(peripheralMap)), share());
|
|
46900
|
-
return peripherals$;
|
|
46901
46751
|
}
|
|
46902
|
-
|
|
46903
|
-
return __awaiter$
|
|
46904
|
-
|
|
46905
|
-
|
|
46906
|
-
|
|
46907
|
-
this.addLog("Peripheral not found");
|
|
46908
|
-
return;
|
|
46909
|
-
}
|
|
46910
|
-
this.connection$.next(BLUETOOTH_CONNECTION.CONNECTING);
|
|
46911
|
-
yield this.BleManager.connect(peripheral.id);
|
|
46912
|
-
this.addLog(`Getting service...`);
|
|
46913
|
-
const peripheralInfo = yield this.BleManager.retrieveServices(peripheral.id, [
|
|
46914
|
-
BLUETOOTH_PRIMARY_SERVICE_UUID_STRING
|
|
46915
|
-
]);
|
|
46916
|
-
if (!peripheralInfo) {
|
|
46917
|
-
this.addLog("Could not retreive services");
|
|
46918
|
-
reject(new Error(`Could not retreive services`));
|
|
46919
|
-
return;
|
|
46920
|
-
}
|
|
46921
|
-
this.addLog(`Got service ${BLUETOOTH_PRIMARY_SERVICE_UUID_STRING}, getting characteristics...`);
|
|
46922
|
-
this.device = peripheral;
|
|
46923
|
-
this.characteristicsByName = Object.fromEntries(peripheralInfo.characteristics.map((characteristic) => [
|
|
46924
|
-
CHARACTERISTIC_UUIDS_TO_NAMES[characteristic.characteristic.toLowerCase() // react native uses uppercase
|
|
46925
|
-
],
|
|
46926
|
-
{
|
|
46927
|
-
characteristicUUID: characteristic.characteristic,
|
|
46928
|
-
serviceUUID: characteristic.service,
|
|
46929
|
-
peripheralId: peripheral.id
|
|
46930
|
-
}
|
|
46931
|
-
]));
|
|
46932
|
-
this.addLog(`Got characteristics.`);
|
|
46933
|
-
if (this.platform === "android") {
|
|
46934
|
-
yield this.BleManager.requestMTU(peripheral.id, ANDROID_MAX_MTU)
|
|
46935
|
-
.then((updatedMTU) => {
|
|
46936
|
-
this.addLog(`Successfully updated Android MTU to ${updatedMTU} bytes. Requested MTU: ${ANDROID_MAX_MTU} bytes.`);
|
|
46937
|
-
})
|
|
46938
|
-
.catch((error) => {
|
|
46939
|
-
this.addLog(`Failed to set Android MTU of ${ANDROID_MAX_MTU} bytes. Error: ${error}`);
|
|
46940
|
-
});
|
|
46941
|
-
}
|
|
46942
|
-
this.addLog(`Successfully connected to peripheral ${peripheral.id}`);
|
|
46943
|
-
this.connection$.next(BLUETOOTH_CONNECTION.CONNECTED);
|
|
46944
|
-
resolve();
|
|
46945
|
-
}
|
|
46946
|
-
catch (error) {
|
|
46947
|
-
reject(error);
|
|
46948
|
-
}
|
|
46949
|
-
}));
|
|
46752
|
+
isAuthenticated() {
|
|
46753
|
+
return __awaiter$f(this, void 0, void 0, function* () {
|
|
46754
|
+
const [isAuthenticated, expiresIn] = yield this.transport.readCharacteristic("auth", true);
|
|
46755
|
+
this.isAuthenticated$.next(isAuthenticated);
|
|
46756
|
+
return [isAuthenticated, expiresIn];
|
|
46950
46757
|
});
|
|
46951
46758
|
}
|
|
46759
|
+
// Method for React Native only
|
|
46760
|
+
scan(options) {
|
|
46761
|
+
if (this.transport instanceof ReactNativeTransport) {
|
|
46762
|
+
return this.transport.scan(options);
|
|
46763
|
+
}
|
|
46764
|
+
if (this.transport instanceof WebBluetoothTransport) {
|
|
46765
|
+
throw new Error(`scan method is compatibly with the React Native transport only`);
|
|
46766
|
+
}
|
|
46767
|
+
throw new Error(`unknown transport`);
|
|
46768
|
+
}
|
|
46769
|
+
// Argument for React Native only
|
|
46770
|
+
connect(deviceNicknameORPeripheral) {
|
|
46771
|
+
if (this.transport instanceof ReactNativeTransport) {
|
|
46772
|
+
return this.transport.connect(deviceNicknameORPeripheral);
|
|
46773
|
+
}
|
|
46774
|
+
if (this.transport instanceof WebBluetoothTransport) {
|
|
46775
|
+
return deviceNicknameORPeripheral
|
|
46776
|
+
? this.transport.connect(deviceNicknameORPeripheral)
|
|
46777
|
+
: this.transport.connect();
|
|
46778
|
+
}
|
|
46779
|
+
}
|
|
46952
46780
|
disconnect() {
|
|
46953
|
-
|
|
46954
|
-
|
|
46955
|
-
|
|
46956
|
-
|
|
46957
|
-
|
|
46958
|
-
|
|
46781
|
+
return this.transport.disconnect();
|
|
46782
|
+
}
|
|
46783
|
+
connection() {
|
|
46784
|
+
return this.transport.connection();
|
|
46785
|
+
}
|
|
46786
|
+
logs() {
|
|
46787
|
+
return this.transport.logs$.asObservable();
|
|
46788
|
+
}
|
|
46789
|
+
getDeviceId() {
|
|
46790
|
+
return __awaiter$f(this, void 0, void 0, function* () {
|
|
46791
|
+
// This is a public characteristic and does not require authentication
|
|
46792
|
+
return this.transport.readCharacteristic("deviceId");
|
|
46793
|
+
});
|
|
46794
|
+
}
|
|
46795
|
+
_withAuthentication(getter) {
|
|
46796
|
+
return __awaiter$f(this, void 0, void 0, function* () {
|
|
46797
|
+
// First check if the OS supports Bluetooth before checking if the device is authenticated
|
|
46798
|
+
const hasBluetoothSupport = yield this._hasBluetoothSupport();
|
|
46799
|
+
if (!hasBluetoothSupport) {
|
|
46800
|
+
const errorMessage = `The OS version does not support Bluetooth.`;
|
|
46801
|
+
this.transport.addLog(errorMessage);
|
|
46802
|
+
return Promise.reject(errorMessage);
|
|
46959
46803
|
}
|
|
46960
|
-
|
|
46961
|
-
|
|
46804
|
+
const isAuthenticated = yield firstValueFrom(this.isAuthenticated$);
|
|
46805
|
+
if (!isAuthenticated) {
|
|
46806
|
+
const errorMessage = `Authentication required.`;
|
|
46807
|
+
this.transport.addLog(errorMessage);
|
|
46808
|
+
return Promise.reject(errorMessage);
|
|
46962
46809
|
}
|
|
46810
|
+
return yield getter();
|
|
46963
46811
|
});
|
|
46964
46812
|
}
|
|
46965
|
-
|
|
46966
|
-
|
|
46967
|
-
|
|
46968
|
-
|
|
46969
|
-
|
|
46970
|
-
|
|
46813
|
+
_subscribeWhileAuthenticated(characteristicName) {
|
|
46814
|
+
return this.osHasBluetoothSupport$.pipe(switchMap((osHasBluetoothSupport) => osHasBluetoothSupport ? this.isAuthenticated$ : EMPTY), distinctUntilChanged(), switchMap((isAuthenticated) => isAuthenticated
|
|
46815
|
+
? this.transport.subscribeToCharacteristic({
|
|
46816
|
+
characteristicName
|
|
46817
|
+
})
|
|
46818
|
+
: EMPTY), share());
|
|
46971
46819
|
}
|
|
46972
|
-
|
|
46973
|
-
|
|
46974
|
-
|
|
46975
|
-
|
|
46976
|
-
|
|
46977
|
-
|
|
46978
|
-
|
|
46979
|
-
|
|
46980
|
-
|
|
46981
|
-
|
|
46982
|
-
|
|
46983
|
-
|
|
46984
|
-
|
|
46985
|
-
|
|
46986
|
-
|
|
46987
|
-
|
|
46988
|
-
|
|
46989
|
-
|
|
46990
|
-
|
|
46991
|
-
|
|
46992
|
-
|
|
46820
|
+
focus() {
|
|
46821
|
+
return this._focus$;
|
|
46822
|
+
}
|
|
46823
|
+
calm() {
|
|
46824
|
+
return this._calm$;
|
|
46825
|
+
}
|
|
46826
|
+
accelerometer() {
|
|
46827
|
+
return this._accelerometer$;
|
|
46828
|
+
}
|
|
46829
|
+
brainwaves(label) {
|
|
46830
|
+
switch (label) {
|
|
46831
|
+
default:
|
|
46832
|
+
case "raw":
|
|
46833
|
+
return defer(() => this.getInfo()).pipe(switchMap((deviceInfo) => this._brainwavesRaw$.pipe(csvBufferToEpoch(deviceInfo))));
|
|
46834
|
+
case "rawUnfiltered":
|
|
46835
|
+
return defer(() => this.getInfo()).pipe(switchMap((deviceInfo) => this._brainwavesRawUnfiltered$.pipe(csvBufferToEpoch(deviceInfo))));
|
|
46836
|
+
case "psd":
|
|
46837
|
+
return this._brainwavesPSD$;
|
|
46838
|
+
case "powerByBand":
|
|
46839
|
+
return this._brainwavesPowerByBand$;
|
|
46840
|
+
}
|
|
46841
|
+
}
|
|
46842
|
+
signalQuality() {
|
|
46843
|
+
return this._signalQuality$;
|
|
46844
|
+
}
|
|
46845
|
+
addMarker(label) {
|
|
46846
|
+
return __awaiter$f(this, void 0, void 0, function* () {
|
|
46847
|
+
yield this.dispatchAction({
|
|
46848
|
+
action: "marker",
|
|
46849
|
+
command: "add",
|
|
46850
|
+
message: {
|
|
46851
|
+
timestamp: Date.now(),
|
|
46852
|
+
label
|
|
46993
46853
|
}
|
|
46994
|
-
}
|
|
46995
|
-
})
|
|
46996
|
-
var _a;
|
|
46997
|
-
try {
|
|
46998
|
-
return JSON.parse(payload);
|
|
46999
|
-
}
|
|
47000
|
-
catch (error) {
|
|
47001
|
-
this.addLog(`Failed to parse JSON for ${characteristicName} characteristic. Falling back to unparsed string. ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
47002
|
-
return payload;
|
|
47003
|
-
}
|
|
47004
|
-
}));
|
|
47005
|
-
return this.connection$.pipe(switchMap((connection) => connection === BLUETOOTH_CONNECTION.CONNECTED
|
|
47006
|
-
? getData(this.getCharacteristicByName(characteristicName))
|
|
47007
|
-
: NEVER));
|
|
46854
|
+
});
|
|
46855
|
+
});
|
|
47008
46856
|
}
|
|
47009
|
-
|
|
47010
|
-
|
|
47011
|
-
|
|
47012
|
-
|
|
47013
|
-
|
|
47014
|
-
if (!characteristicUUID) {
|
|
47015
|
-
return Promise.reject(new Error(`Did not find characteristic matching ${characteristicName}`));
|
|
47016
|
-
}
|
|
47017
|
-
try {
|
|
47018
|
-
const value = yield this.BleManager.read(peripheralId, serviceUUID, characteristicUUID);
|
|
47019
|
-
const decodedValue = decode$1(this.type, value);
|
|
47020
|
-
const data = parse ? JSON.parse(decodedValue) : decodedValue;
|
|
47021
|
-
this.addLog(`Received read data from ${characteristicName} characteristic: \n${data}`);
|
|
47022
|
-
return data;
|
|
47023
|
-
}
|
|
47024
|
-
catch (error) {
|
|
47025
|
-
return Promise.reject(new Error(`readCharacteristic ${characteristicName} error. ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`));
|
|
47026
|
-
}
|
|
46857
|
+
getInfo() {
|
|
46858
|
+
return __awaiter$f(this, void 0, void 0, function* () {
|
|
46859
|
+
return yield this._withAuthentication(() => firstValueFrom(this.transport.subscribeToCharacteristic({
|
|
46860
|
+
characteristicName: "deviceInfo"
|
|
46861
|
+
})));
|
|
47027
46862
|
});
|
|
47028
46863
|
}
|
|
47029
|
-
|
|
47030
|
-
return
|
|
47031
|
-
|
|
47032
|
-
|
|
47033
|
-
|
|
47034
|
-
|
|
47035
|
-
|
|
47036
|
-
|
|
47037
|
-
|
|
46864
|
+
status() {
|
|
46865
|
+
return this._status$;
|
|
46866
|
+
}
|
|
46867
|
+
dispatchAction(action) {
|
|
46868
|
+
return __awaiter$f(this, void 0, void 0, function* () {
|
|
46869
|
+
return yield this._withAuthentication(() => this.transport.dispatchAction({
|
|
46870
|
+
characteristicName: "actions",
|
|
46871
|
+
action
|
|
46872
|
+
}));
|
|
47038
46873
|
});
|
|
47039
46874
|
}
|
|
47040
|
-
|
|
47041
|
-
|
|
47042
|
-
|
|
46875
|
+
settings() {
|
|
46876
|
+
return this._settings$;
|
|
46877
|
+
}
|
|
46878
|
+
haptics(effects) {
|
|
46879
|
+
const metric = "haptics";
|
|
46880
|
+
return this.dispatchAction({
|
|
46881
|
+
action: metric,
|
|
46882
|
+
command: "queue",
|
|
46883
|
+
responseRequired: true,
|
|
46884
|
+
responseTimeout: 4000,
|
|
46885
|
+
// @TODO: implement validation logic as per SDK
|
|
46886
|
+
message: { effects }
|
|
46887
|
+
});
|
|
46888
|
+
}
|
|
46889
|
+
get wifi() {
|
|
46890
|
+
return {
|
|
46891
|
+
nearbyNetworks: () => this._wifiNearbyNetworks$,
|
|
46892
|
+
connections: () => this._wifiConnections$,
|
|
46893
|
+
connect: (ssid, password) => {
|
|
46894
|
+
if (!ssid) {
|
|
46895
|
+
return Promise.reject(`Missing ssid`);
|
|
46896
|
+
}
|
|
46897
|
+
return this.dispatchAction({
|
|
46898
|
+
action: "wifi",
|
|
46899
|
+
command: "connect",
|
|
46900
|
+
responseRequired: true,
|
|
46901
|
+
responseTimeout: 1000 * 60 * 2,
|
|
46902
|
+
message: {
|
|
46903
|
+
ssid,
|
|
46904
|
+
password: password !== null && password !== void 0 ? password : null
|
|
46905
|
+
}
|
|
46906
|
+
});
|
|
46907
|
+
},
|
|
46908
|
+
forgetConnection: (ssid) => {
|
|
46909
|
+
if (!ssid) {
|
|
46910
|
+
return Promise.reject(`Missing ssid`);
|
|
46911
|
+
}
|
|
46912
|
+
return this.dispatchAction({
|
|
46913
|
+
action: "wifi",
|
|
46914
|
+
command: "forget-connection",
|
|
46915
|
+
responseRequired: true,
|
|
46916
|
+
responseTimeout: 1000 * 15,
|
|
46917
|
+
message: {
|
|
46918
|
+
ssid
|
|
46919
|
+
}
|
|
46920
|
+
});
|
|
46921
|
+
},
|
|
46922
|
+
reset: () => {
|
|
46923
|
+
return this.dispatchAction({
|
|
46924
|
+
action: "wifi",
|
|
46925
|
+
command: "reset",
|
|
46926
|
+
responseRequired: true,
|
|
46927
|
+
responseTimeout: 1000 * 30,
|
|
46928
|
+
message: {
|
|
46929
|
+
// without this, the action will resolve as soon as the
|
|
46930
|
+
// action is received by the OS
|
|
46931
|
+
respondOnSuccess: true
|
|
46932
|
+
}
|
|
46933
|
+
});
|
|
46934
|
+
},
|
|
46935
|
+
speedTest: () => {
|
|
46936
|
+
return this.dispatchAction({
|
|
46937
|
+
action: "wifi",
|
|
46938
|
+
command: "speed-test",
|
|
46939
|
+
responseRequired: true,
|
|
46940
|
+
responseTimeout: 1000 * 60 * 1 // 1 minute
|
|
46941
|
+
});
|
|
46942
|
+
}
|
|
46943
|
+
};
|
|
46944
|
+
}
|
|
46945
|
+
}
|
|
46946
|
+
|
|
46947
|
+
const debug = (
|
|
46948
|
+
typeof process === 'object' &&
|
|
46949
|
+
process.env &&
|
|
46950
|
+
process.env.NODE_DEBUG &&
|
|
46951
|
+
/\bsemver\b/i.test(process.env.NODE_DEBUG)
|
|
46952
|
+
) ? (...args) => console.error('SEMVER', ...args)
|
|
46953
|
+
: () => {};
|
|
46954
|
+
|
|
46955
|
+
var debug_1 = debug;
|
|
46956
|
+
|
|
46957
|
+
// Note: this is the semver.org version of the spec that it implements
|
|
46958
|
+
// Not necessarily the package version of this code.
|
|
46959
|
+
const SEMVER_SPEC_VERSION = '2.0.0';
|
|
46960
|
+
|
|
46961
|
+
const MAX_LENGTH = 256;
|
|
46962
|
+
const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||
|
|
46963
|
+
/* istanbul ignore next */ 9007199254740991;
|
|
46964
|
+
|
|
46965
|
+
// Max safe segment length for coercion.
|
|
46966
|
+
const MAX_SAFE_COMPONENT_LENGTH = 16;
|
|
46967
|
+
|
|
46968
|
+
var constants = {
|
|
46969
|
+
SEMVER_SPEC_VERSION,
|
|
46970
|
+
MAX_LENGTH,
|
|
46971
|
+
MAX_SAFE_INTEGER,
|
|
46972
|
+
MAX_SAFE_COMPONENT_LENGTH,
|
|
46973
|
+
};
|
|
46974
|
+
|
|
46975
|
+
function createCommonjsModule(fn, module) {
|
|
46976
|
+
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
|
46977
|
+
}
|
|
46978
|
+
|
|
46979
|
+
var re_1 = createCommonjsModule(function (module, exports) {
|
|
46980
|
+
const { MAX_SAFE_COMPONENT_LENGTH } = constants;
|
|
46981
|
+
|
|
46982
|
+
exports = module.exports = {};
|
|
46983
|
+
|
|
46984
|
+
// The actual regexps go on exports.re
|
|
46985
|
+
const re = exports.re = [];
|
|
46986
|
+
const src = exports.src = [];
|
|
46987
|
+
const t = exports.t = {};
|
|
46988
|
+
let R = 0;
|
|
46989
|
+
|
|
46990
|
+
const createToken = (name, value, isGlobal) => {
|
|
46991
|
+
const index = R++;
|
|
46992
|
+
debug_1(name, index, value);
|
|
46993
|
+
t[name] = index;
|
|
46994
|
+
src[index] = value;
|
|
46995
|
+
re[index] = new RegExp(value, isGlobal ? 'g' : undefined);
|
|
46996
|
+
};
|
|
46997
|
+
|
|
46998
|
+
// The following Regular Expressions can be used for tokenizing,
|
|
46999
|
+
// validating, and parsing SemVer version strings.
|
|
47000
|
+
|
|
47001
|
+
// ## Numeric Identifier
|
|
47002
|
+
// A single `0`, or a non-zero digit followed by zero or more digits.
|
|
47003
|
+
|
|
47004
|
+
createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*');
|
|
47005
|
+
createToken('NUMERICIDENTIFIERLOOSE', '[0-9]+');
|
|
47006
|
+
|
|
47007
|
+
// ## Non-numeric Identifier
|
|
47008
|
+
// Zero or more digits, followed by a letter or hyphen, and then zero or
|
|
47009
|
+
// more letters, digits, or hyphens.
|
|
47010
|
+
|
|
47011
|
+
createToken('NONNUMERICIDENTIFIER', '\\d*[a-zA-Z-][a-zA-Z0-9-]*');
|
|
47012
|
+
|
|
47013
|
+
// ## Main Version
|
|
47014
|
+
// Three dot-separated numeric identifiers.
|
|
47015
|
+
|
|
47016
|
+
createToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\.` +
|
|
47017
|
+
`(${src[t.NUMERICIDENTIFIER]})\\.` +
|
|
47018
|
+
`(${src[t.NUMERICIDENTIFIER]})`);
|
|
47019
|
+
|
|
47020
|
+
createToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` +
|
|
47021
|
+
`(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` +
|
|
47022
|
+
`(${src[t.NUMERICIDENTIFIERLOOSE]})`);
|
|
47023
|
+
|
|
47024
|
+
// ## Pre-release Version Identifier
|
|
47025
|
+
// A numeric identifier, or a non-numeric identifier.
|
|
47026
|
+
|
|
47027
|
+
createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NUMERICIDENTIFIER]
|
|
47028
|
+
}|${src[t.NONNUMERICIDENTIFIER]})`);
|
|
47029
|
+
|
|
47030
|
+
createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NUMERICIDENTIFIERLOOSE]
|
|
47031
|
+
}|${src[t.NONNUMERICIDENTIFIER]})`);
|
|
47032
|
+
|
|
47033
|
+
// ## Pre-release Version
|
|
47034
|
+
// Hyphen, followed by one or more dot-separated pre-release version
|
|
47035
|
+
// identifiers.
|
|
47036
|
+
|
|
47037
|
+
createToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER]
|
|
47038
|
+
}(?:\\.${src[t.PRERELEASEIDENTIFIER]})*))`);
|
|
47039
|
+
|
|
47040
|
+
createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]
|
|
47041
|
+
}(?:\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`);
|
|
47042
|
+
|
|
47043
|
+
// ## Build Metadata Identifier
|
|
47044
|
+
// Any combination of digits, letters, or hyphens.
|
|
47045
|
+
|
|
47046
|
+
createToken('BUILDIDENTIFIER', '[0-9A-Za-z-]+');
|
|
47047
|
+
|
|
47048
|
+
// ## Build Metadata
|
|
47049
|
+
// Plus sign, followed by one or more period-separated build metadata
|
|
47050
|
+
// identifiers.
|
|
47051
|
+
|
|
47052
|
+
createToken('BUILD', `(?:\\+(${src[t.BUILDIDENTIFIER]
|
|
47053
|
+
}(?:\\.${src[t.BUILDIDENTIFIER]})*))`);
|
|
47054
|
+
|
|
47055
|
+
// ## Full Version String
|
|
47056
|
+
// A main version, followed optionally by a pre-release version and
|
|
47057
|
+
// build metadata.
|
|
47058
|
+
|
|
47059
|
+
// Note that the only major, minor, patch, and pre-release sections of
|
|
47060
|
+
// the version string are capturing groups. The build metadata is not a
|
|
47061
|
+
// capturing group, because it should not ever be used in version
|
|
47062
|
+
// comparison.
|
|
47063
|
+
|
|
47064
|
+
createToken('FULLPLAIN', `v?${src[t.MAINVERSION]
|
|
47065
|
+
}${src[t.PRERELEASE]}?${
|
|
47066
|
+
src[t.BUILD]}?`);
|
|
47067
|
+
|
|
47068
|
+
createToken('FULL', `^${src[t.FULLPLAIN]}$`);
|
|
47069
|
+
|
|
47070
|
+
// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
|
|
47071
|
+
// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
|
|
47072
|
+
// common in the npm registry.
|
|
47073
|
+
createToken('LOOSEPLAIN', `[v=\\s]*${src[t.MAINVERSIONLOOSE]
|
|
47074
|
+
}${src[t.PRERELEASELOOSE]}?${
|
|
47075
|
+
src[t.BUILD]}?`);
|
|
47076
|
+
|
|
47077
|
+
createToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`);
|
|
47078
|
+
|
|
47079
|
+
createToken('GTLT', '((?:<|>)?=?)');
|
|
47080
|
+
|
|
47081
|
+
// Something like "2.*" or "1.2.x".
|
|
47082
|
+
// Note that "x.x" is a valid xRange identifer, meaning "any version"
|
|
47083
|
+
// Only the first item is strictly required.
|
|
47084
|
+
createToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`);
|
|
47085
|
+
createToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\*`);
|
|
47086
|
+
|
|
47087
|
+
createToken('XRANGEPLAIN', `[v=\\s]*(${src[t.XRANGEIDENTIFIER]})` +
|
|
47088
|
+
`(?:\\.(${src[t.XRANGEIDENTIFIER]})` +
|
|
47089
|
+
`(?:\\.(${src[t.XRANGEIDENTIFIER]})` +
|
|
47090
|
+
`(?:${src[t.PRERELEASE]})?${
|
|
47091
|
+
src[t.BUILD]}?` +
|
|
47092
|
+
`)?)?`);
|
|
47093
|
+
|
|
47094
|
+
createToken('XRANGEPLAINLOOSE', `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` +
|
|
47095
|
+
`(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +
|
|
47096
|
+
`(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +
|
|
47097
|
+
`(?:${src[t.PRERELEASELOOSE]})?${
|
|
47098
|
+
src[t.BUILD]}?` +
|
|
47099
|
+
`)?)?`);
|
|
47100
|
+
|
|
47101
|
+
createToken('XRANGE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`);
|
|
47102
|
+
createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`);
|
|
47103
|
+
|
|
47104
|
+
// Coercion.
|
|
47105
|
+
// Extract anything that could conceivably be a part of a valid semver
|
|
47106
|
+
createToken('COERCE', `${'(^|[^\\d])' +
|
|
47107
|
+
'(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` +
|
|
47108
|
+
`(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +
|
|
47109
|
+
`(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +
|
|
47110
|
+
`(?:$|[^\\d])`);
|
|
47111
|
+
createToken('COERCERTL', src[t.COERCE], true);
|
|
47112
|
+
|
|
47113
|
+
// Tilde ranges.
|
|
47114
|
+
// Meaning is "reasonably at or greater than"
|
|
47115
|
+
createToken('LONETILDE', '(?:~>?)');
|
|
47116
|
+
|
|
47117
|
+
createToken('TILDETRIM', `(\\s*)${src[t.LONETILDE]}\\s+`, true);
|
|
47118
|
+
exports.tildeTrimReplace = '$1~';
|
|
47119
|
+
|
|
47120
|
+
createToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`);
|
|
47121
|
+
createToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`);
|
|
47122
|
+
|
|
47123
|
+
// Caret ranges.
|
|
47124
|
+
// Meaning is "at least and backwards compatible with"
|
|
47125
|
+
createToken('LONECARET', '(?:\\^)');
|
|
47126
|
+
|
|
47127
|
+
createToken('CARETTRIM', `(\\s*)${src[t.LONECARET]}\\s+`, true);
|
|
47128
|
+
exports.caretTrimReplace = '$1^';
|
|
47129
|
+
|
|
47130
|
+
createToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`);
|
|
47131
|
+
createToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`);
|
|
47132
|
+
|
|
47133
|
+
// A simple gt/lt/eq thing, or just "" to indicate "any version"
|
|
47134
|
+
createToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`);
|
|
47135
|
+
createToken('COMPARATOR', `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`);
|
|
47136
|
+
|
|
47137
|
+
// An expression to strip any whitespace between the gtlt and the thing
|
|
47138
|
+
// it modifies, so that `> 1.2.3` ==> `>1.2.3`
|
|
47139
|
+
createToken('COMPARATORTRIM', `(\\s*)${src[t.GTLT]
|
|
47140
|
+
}\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true);
|
|
47141
|
+
exports.comparatorTrimReplace = '$1$2$3';
|
|
47142
|
+
|
|
47143
|
+
// Something like `1.2.3 - 1.2.4`
|
|
47144
|
+
// Note that these all use the loose form, because they'll be
|
|
47145
|
+
// checked against either the strict or loose comparator form
|
|
47146
|
+
// later.
|
|
47147
|
+
createToken('HYPHENRANGE', `^\\s*(${src[t.XRANGEPLAIN]})` +
|
|
47148
|
+
`\\s+-\\s+` +
|
|
47149
|
+
`(${src[t.XRANGEPLAIN]})` +
|
|
47150
|
+
`\\s*$`);
|
|
47151
|
+
|
|
47152
|
+
createToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` +
|
|
47153
|
+
`\\s+-\\s+` +
|
|
47154
|
+
`(${src[t.XRANGEPLAINLOOSE]})` +
|
|
47155
|
+
`\\s*$`);
|
|
47156
|
+
|
|
47157
|
+
// Star ranges basically just allow anything at all.
|
|
47158
|
+
createToken('STAR', '(<|>)?=?\\s*\\*');
|
|
47159
|
+
// >=0.0.0 is like a star
|
|
47160
|
+
createToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$');
|
|
47161
|
+
createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$');
|
|
47162
|
+
});
|
|
47163
|
+
var re_2 = re_1.re;
|
|
47164
|
+
var re_3 = re_1.src;
|
|
47165
|
+
var re_4 = re_1.t;
|
|
47166
|
+
var re_5 = re_1.tildeTrimReplace;
|
|
47167
|
+
var re_6 = re_1.caretTrimReplace;
|
|
47168
|
+
var re_7 = re_1.comparatorTrimReplace;
|
|
47169
|
+
|
|
47170
|
+
// parse out just the options we care about so we always get a consistent
|
|
47171
|
+
// obj with keys in a consistent order.
|
|
47172
|
+
const opts = ['includePrerelease', 'loose', 'rtl'];
|
|
47173
|
+
const parseOptions = options =>
|
|
47174
|
+
!options ? {}
|
|
47175
|
+
: typeof options !== 'object' ? { loose: true }
|
|
47176
|
+
: opts.filter(k => options[k]).reduce((o, k) => {
|
|
47177
|
+
o[k] = true;
|
|
47178
|
+
return o
|
|
47179
|
+
}, {});
|
|
47180
|
+
var parseOptions_1 = parseOptions;
|
|
47181
|
+
|
|
47182
|
+
const numeric = /^[0-9]+$/;
|
|
47183
|
+
const compareIdentifiers = (a, b) => {
|
|
47184
|
+
const anum = numeric.test(a);
|
|
47185
|
+
const bnum = numeric.test(b);
|
|
47186
|
+
|
|
47187
|
+
if (anum && bnum) {
|
|
47188
|
+
a = +a;
|
|
47189
|
+
b = +b;
|
|
47190
|
+
}
|
|
47191
|
+
|
|
47192
|
+
return a === b ? 0
|
|
47193
|
+
: (anum && !bnum) ? -1
|
|
47194
|
+
: (bnum && !anum) ? 1
|
|
47195
|
+
: a < b ? -1
|
|
47196
|
+
: 1
|
|
47197
|
+
};
|
|
47198
|
+
|
|
47199
|
+
const rcompareIdentifiers = (a, b) => compareIdentifiers(b, a);
|
|
47200
|
+
|
|
47201
|
+
var identifiers = {
|
|
47202
|
+
compareIdentifiers,
|
|
47203
|
+
rcompareIdentifiers,
|
|
47204
|
+
};
|
|
47205
|
+
|
|
47206
|
+
const { MAX_LENGTH: MAX_LENGTH$1, MAX_SAFE_INTEGER: MAX_SAFE_INTEGER$1 } = constants;
|
|
47207
|
+
const { re: re$1, t: t$1 } = re_1;
|
|
47208
|
+
|
|
47209
|
+
|
|
47210
|
+
const { compareIdentifiers: compareIdentifiers$1 } = identifiers;
|
|
47211
|
+
class SemVer {
|
|
47212
|
+
constructor (version, options) {
|
|
47213
|
+
options = parseOptions_1(options);
|
|
47214
|
+
|
|
47215
|
+
if (version instanceof SemVer) {
|
|
47216
|
+
if (version.loose === !!options.loose &&
|
|
47217
|
+
version.includePrerelease === !!options.includePrerelease) {
|
|
47218
|
+
return version
|
|
47219
|
+
} else {
|
|
47220
|
+
version = version.version;
|
|
47221
|
+
}
|
|
47222
|
+
} else if (typeof version !== 'string') {
|
|
47223
|
+
throw new TypeError(`Invalid Version: ${version}`)
|
|
47043
47224
|
}
|
|
47044
|
-
|
|
47045
|
-
|
|
47046
|
-
|
|
47225
|
+
|
|
47226
|
+
if (version.length > MAX_LENGTH$1) {
|
|
47227
|
+
throw new TypeError(
|
|
47228
|
+
`version is longer than ${MAX_LENGTH$1} characters`
|
|
47229
|
+
)
|
|
47047
47230
|
}
|
|
47048
|
-
|
|
47049
|
-
|
|
47050
|
-
|
|
47051
|
-
|
|
47052
|
-
|
|
47053
|
-
|
|
47054
|
-
|
|
47055
|
-
|
|
47056
|
-
|
|
47057
|
-
|
|
47058
|
-
|
|
47059
|
-
|
|
47060
|
-
yield this.BleManager.startNotification(peripheralId, serviceUUID, characteristicUUID);
|
|
47061
|
-
this.addLog(`Started notifications for [actions] characteristic`);
|
|
47062
|
-
}
|
|
47063
|
-
catch (error) {
|
|
47064
|
-
this.addLog(`Attemped to start notifications for [actions] characteristic: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
47065
|
-
}
|
|
47066
|
-
}
|
|
47067
|
-
if (!hasPendingActions && started) {
|
|
47068
|
-
started = false;
|
|
47069
|
-
try {
|
|
47070
|
-
yield this.BleManager.stopNotification(peripheralId, serviceUUID, characteristicUUID);
|
|
47071
|
-
this.addLog(`Stopped notifications for actions characteristic`);
|
|
47072
|
-
}
|
|
47073
|
-
catch (error) {
|
|
47074
|
-
this.addLog(`Attemped to stop notifications for [actions] characteristic: ${(_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error}`);
|
|
47075
|
-
}
|
|
47076
|
-
}
|
|
47077
|
-
})));
|
|
47078
|
-
selectedDevice$
|
|
47079
|
-
.pipe(switchMap((selectedDevice) => !osHasBluetoothSupport(selectedDevice) ? EMPTY : sideEffects$))
|
|
47080
|
-
.subscribe();
|
|
47081
|
-
});
|
|
47231
|
+
|
|
47232
|
+
debug_1('SemVer', version, options);
|
|
47233
|
+
this.options = options;
|
|
47234
|
+
this.loose = !!options.loose;
|
|
47235
|
+
// this isn't actually relevant for versions, but keep it so that we
|
|
47236
|
+
// don't run into trouble passing this.options around.
|
|
47237
|
+
this.includePrerelease = !!options.includePrerelease;
|
|
47238
|
+
|
|
47239
|
+
const m = version.trim().match(options.loose ? re$1[t$1.LOOSE] : re$1[t$1.FULL]);
|
|
47240
|
+
|
|
47241
|
+
if (!m) {
|
|
47242
|
+
throw new TypeError(`Invalid Version: ${version}`)
|
|
47082
47243
|
}
|
|
47083
|
-
|
|
47084
|
-
|
|
47085
|
-
|
|
47086
|
-
|
|
47087
|
-
|
|
47088
|
-
|
|
47089
|
-
|
|
47090
|
-
|
|
47091
|
-
|
|
47092
|
-
|
|
47093
|
-
this._removePendingAction(actionId);
|
|
47094
|
-
reject(new Error(`Action with id ${actionId} timed out after ${responseTimeout}ms`));
|
|
47095
|
-
});
|
|
47096
|
-
// listen for a response before writing
|
|
47097
|
-
this.subscribeToCharacteristic({
|
|
47098
|
-
characteristicName,
|
|
47099
|
-
manageNotifications: false
|
|
47100
|
-
})
|
|
47101
|
-
.pipe(filter((response) => (response === null || response === void 0 ? void 0 : response.actionId) === actionId), take(1))
|
|
47102
|
-
.subscribe((response) => {
|
|
47103
|
-
timeout$$1.unsubscribe();
|
|
47104
|
-
this._removePendingAction(actionId);
|
|
47105
|
-
resolve(response);
|
|
47106
|
-
});
|
|
47107
|
-
// register action by writing
|
|
47108
|
-
this.writeCharacteristic(characteristicName, payload).catch((error) => {
|
|
47109
|
-
this._removePendingAction(actionId);
|
|
47110
|
-
reject(error);
|
|
47111
|
-
});
|
|
47112
|
-
}
|
|
47113
|
-
else {
|
|
47114
|
-
this.writeCharacteristic(characteristicName, payload)
|
|
47115
|
-
.then(() => {
|
|
47116
|
-
resolve(null);
|
|
47117
|
-
})
|
|
47118
|
-
.catch((error) => {
|
|
47119
|
-
reject(error);
|
|
47120
|
-
});
|
|
47121
|
-
}
|
|
47122
|
-
}));
|
|
47123
|
-
});
|
|
47244
|
+
|
|
47245
|
+
this.raw = version;
|
|
47246
|
+
|
|
47247
|
+
// these are actually numbers
|
|
47248
|
+
this.major = +m[1];
|
|
47249
|
+
this.minor = +m[2];
|
|
47250
|
+
this.patch = +m[3];
|
|
47251
|
+
|
|
47252
|
+
if (this.major > MAX_SAFE_INTEGER$1 || this.major < 0) {
|
|
47253
|
+
throw new TypeError('Invalid major version')
|
|
47124
47254
|
}
|
|
47125
|
-
}
|
|
47126
47255
|
|
|
47127
|
-
|
|
47128
|
-
|
|
47129
|
-
const isObject$2 = (object) => object instanceof Object && object === Object(object);
|
|
47130
|
-
const isFunction$2 = (object) => typeof object === "function";
|
|
47131
|
-
const patch = (sample$$1) => (info) => {
|
|
47132
|
-
var _a;
|
|
47133
|
-
return (Object.assign(Object.assign({}, sample$$1), { info: Object.assign(Object.assign({}, ((_a = sample$$1 === null || sample$$1 === void 0 ? void 0 : sample$$1.info) !== null && _a !== void 0 ? _a : {})), (info || {})) }));
|
|
47134
|
-
};
|
|
47135
|
-
/**
|
|
47136
|
-
* Annotates stream with user-defined metadata
|
|
47137
|
-
* @method addInfo
|
|
47138
|
-
* @example eeg$.pipe(addinfo({ samplingRate: 256, channelNames: ["Af7", "Fp1", "Fp2", "Af8"] })
|
|
47139
|
-
* @param {Object} info Info to be added to the EEG stream. Relevant info may include: `samplingRate` and `channelNames`
|
|
47140
|
-
* @returns {Observable<Sample|Epoch|PSD>}
|
|
47141
|
-
*/
|
|
47142
|
-
const addInfo = (infoValue) => pipe(map((sample$$1) => {
|
|
47143
|
-
if (!isObject$2(sample$$1) ||
|
|
47144
|
-
(!isObject$2(infoValue) && !isFunction$2(infoValue))) {
|
|
47145
|
-
return sample$$1;
|
|
47256
|
+
if (this.minor > MAX_SAFE_INTEGER$1 || this.minor < 0) {
|
|
47257
|
+
throw new TypeError('Invalid minor version')
|
|
47146
47258
|
}
|
|
47147
|
-
const info = isFunction$2(infoValue) ? infoValue(sample$$1) : infoValue;
|
|
47148
|
-
return patch(sample$$1)(info);
|
|
47149
|
-
}));
|
|
47150
|
-
/**
|
|
47151
|
-
* Get a 2D data array organized by channel from an array of Samples. Credit to Ken from Seattle's elegant transposition
|
|
47152
|
-
* http://www.codesuck.com/2012/02/transpose-javascript-array-in-one-line.html
|
|
47153
|
-
* @method groupByChannel
|
|
47154
|
-
* @param {Array<Sample>} samplesBuffer Array of Samples to be grouped
|
|
47155
|
-
* @param {string} [dataProp] Name of the key associated with EEG data
|
|
47156
|
-
* @returns {Array<Array<number>>}
|
|
47157
|
-
*/
|
|
47158
|
-
const groupByChannel = (samplesBuffer, dataProp = defaultDataProp) => samplesBuffer[0][dataProp].map((_, channelIndex) => samplesBuffer.map((sample$$1) => sample$$1[dataProp][channelIndex]));
|
|
47159
|
-
/**
|
|
47160
|
-
* Takes an array or RxJS buffer of EEG Samples and returns an Epoch.
|
|
47161
|
-
* @method bufferToEpoch
|
|
47162
|
-
* @example eeg$.pipe(bufferTime(1000), bufferToEpoch({ samplingRate: 256 }))
|
|
47163
|
-
*
|
|
47164
|
-
* @param {Object} options - Data structure options
|
|
47165
|
-
* @param {number} [options.samplingRate] Sampling rate
|
|
47166
|
-
* @param {string} [options.dataProp='data'] Name of the key associated with eeg data
|
|
47167
|
-
*
|
|
47168
|
-
* @returns {Observable<Epoch>}
|
|
47169
|
-
*/
|
|
47170
|
-
const bufferToEpoch = ({ samplingRate = defaultSamplingRate, dataProp = defaultDataProp } = {}) => pipe(map((samplesArray) => ({
|
|
47171
|
-
[dataProp]: groupByChannel(samplesArray, dataProp),
|
|
47172
|
-
info: Object.assign(Object.assign({}, (samplesArray[0] && samplesArray[0].info
|
|
47173
|
-
? samplesArray[0].info
|
|
47174
|
-
: {})), { startTime: samplesArray[0].timestamp, samplingRate: samplesArray[0].info && samplesArray[0].info.samplingRate
|
|
47175
|
-
? samplesArray[0].info.samplingRate
|
|
47176
|
-
: samplingRate })
|
|
47177
|
-
})));
|
|
47178
|
-
/**
|
|
47179
|
-
* Converts a stream of individual Samples of EEG data into a stream of Epochs of a given duration emitted at specified interval. This operator functions similarly to a circular buffer internally and allows overlapping Epochs of data to be emitted (e.g. emitting the last one second of data every 100ms).
|
|
47180
|
-
* @method epoch
|
|
47181
|
-
* @example eeg$.pipe(epoch({ duration: 1024, interval: 100, samplingRate: 256 }))
|
|
47182
|
-
* @param {Object} options - Epoching options
|
|
47183
|
-
* @param {number} [options.duration=256] Number of samples to include in each epoch
|
|
47184
|
-
* @param {number} [options.interval=100] Time (ms) between emitted Epochs
|
|
47185
|
-
* @param {number} [options.samplingRate=256] Sampling rate
|
|
47186
|
-
* @param {string} [options.dataProp='data'] Name of the key associated with eeg data
|
|
47187
|
-
* @returns {Observable} Epoch
|
|
47188
|
-
*/
|
|
47189
|
-
const epoch = ({ duration, interval: interval$$1, samplingRate, dataProp = defaultDataProp }) => pipe(bufferCount(interval$$1), scan((acc, val) => acc.concat(val).slice(acc.length < duration ? 0 : -duration)), filter((samplesArray) => samplesArray.length === duration), bufferToEpoch({ samplingRate, dataProp }));
|
|
47190
47259
|
|
|
47191
|
-
|
|
47192
|
-
|
|
47193
|
-
/**
|
|
47194
|
-
* @hidden
|
|
47195
|
-
*/
|
|
47196
|
-
function csvBufferToEpoch(deviceInfo) {
|
|
47197
|
-
var _a;
|
|
47198
|
-
if (!(deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.samplingRate)) {
|
|
47199
|
-
console.warn(`Didn't receive a sampling rate, defaulting to ${SAMPLING_RATE_FALLBACK}`);
|
|
47260
|
+
if (this.patch > MAX_SAFE_INTEGER$1 || this.patch < 0) {
|
|
47261
|
+
throw new TypeError('Invalid patch version')
|
|
47200
47262
|
}
|
|
47201
|
-
return pipe(csvBufferToSamples(), epoch({
|
|
47202
|
-
duration: EPOCH_BUFFER_SIZE,
|
|
47203
|
-
interval: EPOCH_BUFFER_SIZE,
|
|
47204
|
-
samplingRate: (_a = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.samplingRate) !== null && _a !== void 0 ? _a : SAMPLING_RATE_FALLBACK
|
|
47205
|
-
}), addInfo({
|
|
47206
|
-
channelNames: deviceInfo.channelNames,
|
|
47207
|
-
samplingRate: deviceInfo.samplingRate
|
|
47208
|
-
}));
|
|
47209
|
-
}
|
|
47210
|
-
/**
|
|
47211
|
-
* @hidden
|
|
47212
|
-
*/
|
|
47213
|
-
function csvBufferToSamples() {
|
|
47214
|
-
return pipe(mergeMap((samples) => from(samples)), map(([timestamp$$1, marker, ...data]) => ({
|
|
47215
|
-
timestamp: timestamp$$1,
|
|
47216
|
-
data
|
|
47217
|
-
})));
|
|
47218
|
-
}
|
|
47219
47263
|
|
|
47220
|
-
|
|
47221
|
-
|
|
47222
|
-
|
|
47223
|
-
|
|
47224
|
-
|
|
47225
|
-
|
|
47226
|
-
|
|
47227
|
-
|
|
47228
|
-
|
|
47229
|
-
|
|
47230
|
-
constructor(options) {
|
|
47231
|
-
this.selectedDevice$ = new ReplaySubject(1);
|
|
47232
|
-
this.isAuthenticated$ = new ReplaySubject(1);
|
|
47233
|
-
const { transport, selectedDevice$, createBluetoothToken } = options !== null && options !== void 0 ? options : {};
|
|
47234
|
-
if (!transport) {
|
|
47235
|
-
throw new Error(`No bluetooth transport provided.`);
|
|
47236
|
-
}
|
|
47237
|
-
this.transport = transport;
|
|
47238
|
-
// Pass events to the internal selectedDevice$ if selectedDevice$ is passed via options
|
|
47239
|
-
if (selectedDevice$) {
|
|
47240
|
-
selectedDevice$.subscribe(this.selectedDevice$);
|
|
47241
|
-
}
|
|
47242
|
-
// Auto Connect
|
|
47243
|
-
this.transport._autoConnect(this.selectedDevice$).subscribe({
|
|
47244
|
-
error: (error) => {
|
|
47245
|
-
var _a;
|
|
47246
|
-
this.transport.addLog(`Auto connect: error -> ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
|
|
47247
|
-
}
|
|
47248
|
-
});
|
|
47249
|
-
// Auto authentication
|
|
47250
|
-
if (typeof createBluetoothToken === "function") {
|
|
47251
|
-
this.transport.addLog("Auto authentication enabled");
|
|
47252
|
-
this._autoAuthenticate(createBluetoothToken).subscribe();
|
|
47253
|
-
}
|
|
47254
|
-
else {
|
|
47255
|
-
this.transport.addLog("Auto authentication not enabled");
|
|
47264
|
+
// numberify any prerelease numeric ids
|
|
47265
|
+
if (!m[4]) {
|
|
47266
|
+
this.prerelease = [];
|
|
47267
|
+
} else {
|
|
47268
|
+
this.prerelease = m[4].split('.').map((id) => {
|
|
47269
|
+
if (/^[0-9]+$/.test(id)) {
|
|
47270
|
+
const num = +id;
|
|
47271
|
+
if (num >= 0 && num < MAX_SAFE_INTEGER$1) {
|
|
47272
|
+
return num
|
|
47273
|
+
}
|
|
47256
47274
|
}
|
|
47257
|
-
|
|
47258
|
-
|
|
47259
|
-
// Multicast metrics (share)
|
|
47260
|
-
this._focus$ = this._subscribeWhileAuthenticated("focus");
|
|
47261
|
-
this._calm$ = this._subscribeWhileAuthenticated("calm");
|
|
47262
|
-
this._accelerometer$ = this._subscribeWhileAuthenticated("accelerometer");
|
|
47263
|
-
this._brainwavesRaw$ = this._subscribeWhileAuthenticated("raw");
|
|
47264
|
-
this._brainwavesRawUnfiltered$ =
|
|
47265
|
-
this._subscribeWhileAuthenticated("rawUnfiltered");
|
|
47266
|
-
this._brainwavesPSD$ = this._subscribeWhileAuthenticated("psd");
|
|
47267
|
-
this._brainwavesPowerByBand$ =
|
|
47268
|
-
this._subscribeWhileAuthenticated("powerByBand");
|
|
47269
|
-
this._signalQuality$ = this._subscribeWhileAuthenticated("signalQuality");
|
|
47270
|
-
this._status$ = this._subscribeWhileAuthenticated("status");
|
|
47271
|
-
this._settings$ = this._subscribeWhileAuthenticated("settings");
|
|
47272
|
-
this._wifiNearbyNetworks$ =
|
|
47273
|
-
this._subscribeWhileAuthenticated("wifiNearbyNetworks");
|
|
47274
|
-
this._wifiConnections$ =
|
|
47275
|
-
this._subscribeWhileAuthenticated("wifiConnections");
|
|
47275
|
+
return id
|
|
47276
|
+
});
|
|
47276
47277
|
}
|
|
47277
|
-
|
|
47278
|
-
|
|
47279
|
-
|
|
47280
|
-
|
|
47281
|
-
|
|
47282
|
-
|
|
47283
|
-
|
|
47284
|
-
|
|
47285
|
-
|
|
47286
|
-
: EMPTY), switchMap(() => __awaiter$f(this, void 0, void 0, function* () { return yield this.isAuthenticated(); })), tap(([isAuthenticated]) => __awaiter$f(this, void 0, void 0, function* () {
|
|
47287
|
-
if (!isAuthenticated) {
|
|
47288
|
-
const token = yield createBluetoothToken();
|
|
47289
|
-
yield this.authenticate(token);
|
|
47290
|
-
}
|
|
47291
|
-
else {
|
|
47292
|
-
this.transport.addLog(`Already authenticated`);
|
|
47293
|
-
}
|
|
47294
|
-
})))));
|
|
47278
|
+
|
|
47279
|
+
this.build = m[5] ? m[5].split('.') : [];
|
|
47280
|
+
this.format();
|
|
47281
|
+
}
|
|
47282
|
+
|
|
47283
|
+
format () {
|
|
47284
|
+
this.version = `${this.major}.${this.minor}.${this.patch}`;
|
|
47285
|
+
if (this.prerelease.length) {
|
|
47286
|
+
this.version += `-${this.prerelease.join('.')}`;
|
|
47295
47287
|
}
|
|
47296
|
-
|
|
47297
|
-
|
|
47288
|
+
return this.version
|
|
47289
|
+
}
|
|
47290
|
+
|
|
47291
|
+
toString () {
|
|
47292
|
+
return this.version
|
|
47293
|
+
}
|
|
47294
|
+
|
|
47295
|
+
compare (other) {
|
|
47296
|
+
debug_1('SemVer.compare', this.version, this.options, other);
|
|
47297
|
+
if (!(other instanceof SemVer)) {
|
|
47298
|
+
if (typeof other === 'string' && other === this.version) {
|
|
47299
|
+
return 0
|
|
47300
|
+
}
|
|
47301
|
+
other = new SemVer(other, this.options);
|
|
47298
47302
|
}
|
|
47299
|
-
|
|
47300
|
-
|
|
47301
|
-
|
|
47302
|
-
return osHasBluetoothSupport(selectedDevice);
|
|
47303
|
-
});
|
|
47303
|
+
|
|
47304
|
+
if (other.version === this.version) {
|
|
47305
|
+
return 0
|
|
47304
47306
|
}
|
|
47305
|
-
|
|
47306
|
-
|
|
47307
|
-
|
|
47308
|
-
|
|
47309
|
-
|
|
47310
|
-
|
|
47311
|
-
|
|
47312
|
-
}
|
|
47313
|
-
yield this.transport.writeCharacteristic("auth", token);
|
|
47314
|
-
const isAuthenticatedResponse = yield this.isAuthenticated();
|
|
47315
|
-
const [isAuthenticated] = isAuthenticatedResponse;
|
|
47316
|
-
this.transport.addLog(`Authentication ${isAuthenticated ? "succeeded" : "failed"}`);
|
|
47317
|
-
this.isAuthenticated$.next(isAuthenticated);
|
|
47318
|
-
return isAuthenticatedResponse;
|
|
47319
|
-
});
|
|
47307
|
+
|
|
47308
|
+
return this.compareMain(other) || this.comparePre(other)
|
|
47309
|
+
}
|
|
47310
|
+
|
|
47311
|
+
compareMain (other) {
|
|
47312
|
+
if (!(other instanceof SemVer)) {
|
|
47313
|
+
other = new SemVer(other, this.options);
|
|
47320
47314
|
}
|
|
47321
|
-
|
|
47322
|
-
|
|
47323
|
-
|
|
47324
|
-
|
|
47325
|
-
|
|
47326
|
-
|
|
47315
|
+
|
|
47316
|
+
return (
|
|
47317
|
+
compareIdentifiers$1(this.major, other.major) ||
|
|
47318
|
+
compareIdentifiers$1(this.minor, other.minor) ||
|
|
47319
|
+
compareIdentifiers$1(this.patch, other.patch)
|
|
47320
|
+
)
|
|
47321
|
+
}
|
|
47322
|
+
|
|
47323
|
+
comparePre (other) {
|
|
47324
|
+
if (!(other instanceof SemVer)) {
|
|
47325
|
+
other = new SemVer(other, this.options);
|
|
47327
47326
|
}
|
|
47328
|
-
|
|
47329
|
-
|
|
47330
|
-
|
|
47331
|
-
|
|
47327
|
+
|
|
47328
|
+
// NOT having a prerelease is > having one
|
|
47329
|
+
if (this.prerelease.length && !other.prerelease.length) {
|
|
47330
|
+
return -1
|
|
47331
|
+
} else if (!this.prerelease.length && other.prerelease.length) {
|
|
47332
|
+
return 1
|
|
47333
|
+
} else if (!this.prerelease.length && !other.prerelease.length) {
|
|
47334
|
+
return 0
|
|
47335
|
+
}
|
|
47336
|
+
|
|
47337
|
+
let i = 0;
|
|
47338
|
+
do {
|
|
47339
|
+
const a = this.prerelease[i];
|
|
47340
|
+
const b = other.prerelease[i];
|
|
47341
|
+
debug_1('prerelease compare', i, a, b);
|
|
47342
|
+
if (a === undefined && b === undefined) {
|
|
47343
|
+
return 0
|
|
47344
|
+
} else if (b === undefined) {
|
|
47345
|
+
return 1
|
|
47346
|
+
} else if (a === undefined) {
|
|
47347
|
+
return -1
|
|
47348
|
+
} else if (a === b) {
|
|
47349
|
+
continue
|
|
47350
|
+
} else {
|
|
47351
|
+
return compareIdentifiers$1(a, b)
|
|
47352
|
+
}
|
|
47353
|
+
} while (++i)
|
|
47354
|
+
}
|
|
47355
|
+
|
|
47356
|
+
compareBuild (other) {
|
|
47357
|
+
if (!(other instanceof SemVer)) {
|
|
47358
|
+
other = new SemVer(other, this.options);
|
|
47359
|
+
}
|
|
47360
|
+
|
|
47361
|
+
let i = 0;
|
|
47362
|
+
do {
|
|
47363
|
+
const a = this.build[i];
|
|
47364
|
+
const b = other.build[i];
|
|
47365
|
+
debug_1('prerelease compare', i, a, b);
|
|
47366
|
+
if (a === undefined && b === undefined) {
|
|
47367
|
+
return 0
|
|
47368
|
+
} else if (b === undefined) {
|
|
47369
|
+
return 1
|
|
47370
|
+
} else if (a === undefined) {
|
|
47371
|
+
return -1
|
|
47372
|
+
} else if (a === b) {
|
|
47373
|
+
continue
|
|
47374
|
+
} else {
|
|
47375
|
+
return compareIdentifiers$1(a, b)
|
|
47376
|
+
}
|
|
47377
|
+
} while (++i)
|
|
47378
|
+
}
|
|
47379
|
+
|
|
47380
|
+
// preminor will bump the version up to the next minor release, and immediately
|
|
47381
|
+
// down to pre-release. premajor and prepatch work the same way.
|
|
47382
|
+
inc (release, identifier) {
|
|
47383
|
+
switch (release) {
|
|
47384
|
+
case 'premajor':
|
|
47385
|
+
this.prerelease.length = 0;
|
|
47386
|
+
this.patch = 0;
|
|
47387
|
+
this.minor = 0;
|
|
47388
|
+
this.major++;
|
|
47389
|
+
this.inc('pre', identifier);
|
|
47390
|
+
break
|
|
47391
|
+
case 'preminor':
|
|
47392
|
+
this.prerelease.length = 0;
|
|
47393
|
+
this.patch = 0;
|
|
47394
|
+
this.minor++;
|
|
47395
|
+
this.inc('pre', identifier);
|
|
47396
|
+
break
|
|
47397
|
+
case 'prepatch':
|
|
47398
|
+
// If this is already a prerelease, it will bump to the next version
|
|
47399
|
+
// drop any prereleases that might already exist, since they are not
|
|
47400
|
+
// relevant at this point.
|
|
47401
|
+
this.prerelease.length = 0;
|
|
47402
|
+
this.inc('patch', identifier);
|
|
47403
|
+
this.inc('pre', identifier);
|
|
47404
|
+
break
|
|
47405
|
+
// If the input is a non-prerelease version, this acts the same as
|
|
47406
|
+
// prepatch.
|
|
47407
|
+
case 'prerelease':
|
|
47408
|
+
if (this.prerelease.length === 0) {
|
|
47409
|
+
this.inc('patch', identifier);
|
|
47332
47410
|
}
|
|
47333
|
-
|
|
47334
|
-
|
|
47411
|
+
this.inc('pre', identifier);
|
|
47412
|
+
break
|
|
47413
|
+
|
|
47414
|
+
case 'major':
|
|
47415
|
+
// If this is a pre-major version, bump up to the same major version.
|
|
47416
|
+
// Otherwise increment major.
|
|
47417
|
+
// 1.0.0-5 bumps to 1.0.0
|
|
47418
|
+
// 1.1.0 bumps to 2.0.0
|
|
47419
|
+
if (
|
|
47420
|
+
this.minor !== 0 ||
|
|
47421
|
+
this.patch !== 0 ||
|
|
47422
|
+
this.prerelease.length === 0
|
|
47423
|
+
) {
|
|
47424
|
+
this.major++;
|
|
47335
47425
|
}
|
|
47336
|
-
|
|
47337
|
-
|
|
47338
|
-
|
|
47339
|
-
|
|
47340
|
-
|
|
47341
|
-
|
|
47426
|
+
this.minor = 0;
|
|
47427
|
+
this.patch = 0;
|
|
47428
|
+
this.prerelease = [];
|
|
47429
|
+
break
|
|
47430
|
+
case 'minor':
|
|
47431
|
+
// If this is a pre-minor version, bump up to the same minor version.
|
|
47432
|
+
// Otherwise increment minor.
|
|
47433
|
+
// 1.2.0-5 bumps to 1.2.0
|
|
47434
|
+
// 1.2.1 bumps to 1.3.0
|
|
47435
|
+
if (this.patch !== 0 || this.prerelease.length === 0) {
|
|
47436
|
+
this.minor++;
|
|
47342
47437
|
}
|
|
47343
|
-
|
|
47344
|
-
|
|
47345
|
-
|
|
47346
|
-
|
|
47438
|
+
this.patch = 0;
|
|
47439
|
+
this.prerelease = [];
|
|
47440
|
+
break
|
|
47441
|
+
case 'patch':
|
|
47442
|
+
// If this is not a pre-release version, it will increment the patch.
|
|
47443
|
+
// If it is a pre-release it will bump up to the same patch version.
|
|
47444
|
+
// 1.2.0-5 patches to 1.2.0
|
|
47445
|
+
// 1.2.0 patches to 1.2.1
|
|
47446
|
+
if (this.prerelease.length === 0) {
|
|
47447
|
+
this.patch++;
|
|
47347
47448
|
}
|
|
47348
|
-
|
|
47349
|
-
|
|
47350
|
-
|
|
47351
|
-
|
|
47352
|
-
|
|
47353
|
-
|
|
47354
|
-
|
|
47355
|
-
|
|
47356
|
-
|
|
47357
|
-
|
|
47358
|
-
|
|
47359
|
-
|
|
47360
|
-
|
|
47361
|
-
return this.transport.readCharacteristic("deviceId");
|
|
47362
|
-
});
|
|
47363
|
-
}
|
|
47364
|
-
_withAuthentication(getter) {
|
|
47365
|
-
return __awaiter$f(this, void 0, void 0, function* () {
|
|
47366
|
-
// First check if the OS supports Bluetooth before checking if the device is authenticated
|
|
47367
|
-
const hasBluetoothSupport = yield this._hasBluetoothSupport();
|
|
47368
|
-
if (!hasBluetoothSupport) {
|
|
47369
|
-
const errorMessage = `The OS version does not support Bluetooth.`;
|
|
47370
|
-
this.transport.addLog(errorMessage);
|
|
47371
|
-
return Promise.reject(errorMessage);
|
|
47449
|
+
this.prerelease = [];
|
|
47450
|
+
break
|
|
47451
|
+
// This probably shouldn't be used publicly.
|
|
47452
|
+
// 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction.
|
|
47453
|
+
case 'pre':
|
|
47454
|
+
if (this.prerelease.length === 0) {
|
|
47455
|
+
this.prerelease = [0];
|
|
47456
|
+
} else {
|
|
47457
|
+
let i = this.prerelease.length;
|
|
47458
|
+
while (--i >= 0) {
|
|
47459
|
+
if (typeof this.prerelease[i] === 'number') {
|
|
47460
|
+
this.prerelease[i]++;
|
|
47461
|
+
i = -2;
|
|
47372
47462
|
}
|
|
47373
|
-
|
|
47374
|
-
|
|
47375
|
-
|
|
47376
|
-
|
|
47377
|
-
|
|
47463
|
+
}
|
|
47464
|
+
if (i === -1) {
|
|
47465
|
+
// didn't increment anything
|
|
47466
|
+
this.prerelease.push(0);
|
|
47467
|
+
}
|
|
47468
|
+
}
|
|
47469
|
+
if (identifier) {
|
|
47470
|
+
// 1.2.0-beta.1 bumps to 1.2.0-beta.2,
|
|
47471
|
+
// 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
|
|
47472
|
+
if (compareIdentifiers$1(this.prerelease[0], identifier) === 0) {
|
|
47473
|
+
if (isNaN(this.prerelease[1])) {
|
|
47474
|
+
this.prerelease = [identifier, 0];
|
|
47378
47475
|
}
|
|
47379
|
-
|
|
47380
|
-
|
|
47381
|
-
|
|
47382
|
-
_subscribeWhileAuthenticated(characteristicName) {
|
|
47383
|
-
return this.selectedDevice$.pipe(switchMap((selectedDevice) => !osHasBluetoothSupport(selectedDevice)
|
|
47384
|
-
? EMPTY
|
|
47385
|
-
: this.isAuthenticated$.pipe(distinctUntilChanged(), switchMap((isAuthenticated) => isAuthenticated
|
|
47386
|
-
? this.transport.subscribeToCharacteristic({
|
|
47387
|
-
characteristicName
|
|
47388
|
-
})
|
|
47389
|
-
: EMPTY))), share());
|
|
47390
|
-
}
|
|
47391
|
-
focus() {
|
|
47392
|
-
return this._focus$;
|
|
47393
|
-
}
|
|
47394
|
-
calm() {
|
|
47395
|
-
return this._calm$;
|
|
47396
|
-
}
|
|
47397
|
-
accelerometer() {
|
|
47398
|
-
return this._accelerometer$;
|
|
47399
|
-
}
|
|
47400
|
-
brainwaves(label) {
|
|
47401
|
-
switch (label) {
|
|
47402
|
-
default:
|
|
47403
|
-
case "raw":
|
|
47404
|
-
return defer(() => this.getInfo()).pipe(switchMap((deviceInfo) => this._brainwavesRaw$.pipe(csvBufferToEpoch(deviceInfo))));
|
|
47405
|
-
case "rawUnfiltered":
|
|
47406
|
-
return defer(() => this.getInfo()).pipe(switchMap((deviceInfo) => this._brainwavesRawUnfiltered$.pipe(csvBufferToEpoch(deviceInfo))));
|
|
47407
|
-
case "psd":
|
|
47408
|
-
return this._brainwavesPSD$;
|
|
47409
|
-
case "powerByBand":
|
|
47410
|
-
return this._brainwavesPowerByBand$;
|
|
47476
|
+
} else {
|
|
47477
|
+
this.prerelease = [identifier, 0];
|
|
47478
|
+
}
|
|
47411
47479
|
}
|
|
47480
|
+
break
|
|
47481
|
+
|
|
47482
|
+
default:
|
|
47483
|
+
throw new Error(`invalid increment argument: ${release}`)
|
|
47412
47484
|
}
|
|
47413
|
-
|
|
47414
|
-
|
|
47415
|
-
|
|
47416
|
-
|
|
47417
|
-
|
|
47418
|
-
|
|
47419
|
-
|
|
47420
|
-
|
|
47421
|
-
|
|
47422
|
-
|
|
47423
|
-
|
|
47424
|
-
|
|
47425
|
-
|
|
47426
|
-
|
|
47427
|
-
|
|
47428
|
-
|
|
47429
|
-
|
|
47430
|
-
|
|
47431
|
-
|
|
47432
|
-
})));
|
|
47433
|
-
});
|
|
47434
|
-
}
|
|
47435
|
-
status() {
|
|
47436
|
-
return this._status$;
|
|
47437
|
-
}
|
|
47438
|
-
dispatchAction(action) {
|
|
47439
|
-
return __awaiter$f(this, void 0, void 0, function* () {
|
|
47440
|
-
return yield this._withAuthentication(() => this.transport.dispatchAction({
|
|
47441
|
-
characteristicName: "actions",
|
|
47442
|
-
action
|
|
47443
|
-
}));
|
|
47444
|
-
});
|
|
47445
|
-
}
|
|
47446
|
-
settings() {
|
|
47447
|
-
return this._settings$;
|
|
47485
|
+
this.format();
|
|
47486
|
+
this.raw = this.version;
|
|
47487
|
+
return this
|
|
47488
|
+
}
|
|
47489
|
+
}
|
|
47490
|
+
|
|
47491
|
+
var semver = SemVer;
|
|
47492
|
+
|
|
47493
|
+
const compare = (a, b, loose) =>
|
|
47494
|
+
new semver(a, loose).compare(new semver(b, loose));
|
|
47495
|
+
|
|
47496
|
+
var compare_1 = compare;
|
|
47497
|
+
|
|
47498
|
+
const gte = (a, b, loose) => compare_1(a, b, loose) >= 0;
|
|
47499
|
+
var gte_1 = gte;
|
|
47500
|
+
|
|
47501
|
+
function osHasBluetoothSupport(selectedDevice, osVersion) {
|
|
47502
|
+
if (!selectedDevice) {
|
|
47503
|
+
return false;
|
|
47448
47504
|
}
|
|
47449
|
-
|
|
47450
|
-
|
|
47451
|
-
|
|
47452
|
-
|
|
47453
|
-
command: "queue",
|
|
47454
|
-
responseRequired: true,
|
|
47455
|
-
responseTimeout: 4000,
|
|
47456
|
-
// @TODO: implement validation logic as per SDK
|
|
47457
|
-
message: { effects }
|
|
47458
|
-
});
|
|
47505
|
+
// Only the Crown supports Bluetooth
|
|
47506
|
+
const isCrown = Number(selectedDevice.modelVersion) >= 3;
|
|
47507
|
+
if (!isCrown) {
|
|
47508
|
+
return false;
|
|
47459
47509
|
}
|
|
47460
|
-
|
|
47461
|
-
|
|
47462
|
-
|
|
47463
|
-
connections: () => this._wifiConnections$,
|
|
47464
|
-
connect: (ssid, password) => {
|
|
47465
|
-
if (!ssid) {
|
|
47466
|
-
return Promise.reject(`Missing ssid`);
|
|
47467
|
-
}
|
|
47468
|
-
return this.dispatchAction({
|
|
47469
|
-
action: "wifi",
|
|
47470
|
-
command: "connect",
|
|
47471
|
-
responseRequired: true,
|
|
47472
|
-
responseTimeout: 1000 * 60 * 2,
|
|
47473
|
-
message: {
|
|
47474
|
-
ssid,
|
|
47475
|
-
password: password !== null && password !== void 0 ? password : null
|
|
47476
|
-
}
|
|
47477
|
-
});
|
|
47478
|
-
},
|
|
47479
|
-
forgetConnection: (ssid) => {
|
|
47480
|
-
if (!ssid) {
|
|
47481
|
-
return Promise.reject(`Missing ssid`);
|
|
47482
|
-
}
|
|
47483
|
-
return this.dispatchAction({
|
|
47484
|
-
action: "wifi",
|
|
47485
|
-
command: "forget-connection",
|
|
47486
|
-
responseRequired: true,
|
|
47487
|
-
responseTimeout: 1000 * 15,
|
|
47488
|
-
message: {
|
|
47489
|
-
ssid
|
|
47490
|
-
}
|
|
47491
|
-
});
|
|
47492
|
-
},
|
|
47493
|
-
reset: () => {
|
|
47494
|
-
return this.dispatchAction({
|
|
47495
|
-
action: "wifi",
|
|
47496
|
-
command: "reset",
|
|
47497
|
-
responseRequired: true,
|
|
47498
|
-
responseTimeout: 1000 * 30,
|
|
47499
|
-
message: {
|
|
47500
|
-
// without this, the action will resolve as soon as the
|
|
47501
|
-
// action is received by the OS
|
|
47502
|
-
respondOnSuccess: true
|
|
47503
|
-
}
|
|
47504
|
-
});
|
|
47505
|
-
},
|
|
47506
|
-
speedTest: () => {
|
|
47507
|
-
return this.dispatchAction({
|
|
47508
|
-
action: "wifi",
|
|
47509
|
-
command: "speed-test",
|
|
47510
|
-
responseRequired: true,
|
|
47511
|
-
responseTimeout: 1000 * 60 * 1 // 1 minute
|
|
47512
|
-
});
|
|
47513
|
-
}
|
|
47514
|
-
};
|
|
47510
|
+
const isEmulator = !!(selectedDevice === null || selectedDevice === void 0 ? void 0 : selectedDevice.emulator);
|
|
47511
|
+
if (isEmulator) {
|
|
47512
|
+
return false;
|
|
47515
47513
|
}
|
|
47514
|
+
// `osVersion` is updated in real time,
|
|
47515
|
+
// unlike accessing via `selectedDevice.osVersion`
|
|
47516
|
+
return gte_1(osVersion !== null && osVersion !== void 0 ? osVersion : selectedDevice.osVersion, "16.0.0");
|
|
47516
47517
|
}
|
|
47517
47518
|
|
|
47518
47519
|
var __awaiter$g = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
@@ -47567,6 +47568,7 @@ class Neurosity {
|
|
|
47567
47568
|
if (!!bluetoothTransport) {
|
|
47568
47569
|
this.bluetoothClient = new BluetoothClient({
|
|
47569
47570
|
selectedDevice$: this.onDeviceChange(),
|
|
47571
|
+
osHasBluetoothSupport$: this._osHasBluetoothSupport(),
|
|
47570
47572
|
createBluetoothToken: this.createBluetoothToken.bind(this),
|
|
47571
47573
|
transport: bluetoothTransport
|
|
47572
47574
|
});
|
|
@@ -47597,6 +47599,16 @@ class Neurosity {
|
|
|
47597
47599
|
this.streamingMode$.next(streamingMode);
|
|
47598
47600
|
}
|
|
47599
47601
|
}
|
|
47602
|
+
/**
|
|
47603
|
+
*
|
|
47604
|
+
* @hidden
|
|
47605
|
+
*/
|
|
47606
|
+
_osHasBluetoothSupport() {
|
|
47607
|
+
return combineLatest({
|
|
47608
|
+
selectedDevice: this.onDeviceChange(),
|
|
47609
|
+
osVersion: this.osVersion().pipe(startWith(null))
|
|
47610
|
+
}).pipe(map(({ selectedDevice, osVersion }) => osHasBluetoothSupport(selectedDevice, osVersion)));
|
|
47611
|
+
}
|
|
47600
47612
|
/**
|
|
47601
47613
|
* Subscribe to the device's streaming state changes and the current strategy
|
|
47602
47614
|
*
|
|
@@ -47612,12 +47624,14 @@ class Neurosity {
|
|
|
47612
47624
|
streamingState() {
|
|
47613
47625
|
const isWifiOnline = (state) => [STATUS.ONLINE, STATUS.UPDATING].includes(state);
|
|
47614
47626
|
return this.streamingMode$.pipe(switchMap((streamingMode) => {
|
|
47615
|
-
return
|
|
47616
|
-
|
|
47627
|
+
return combineLatest({
|
|
47628
|
+
selectedDevice: this.onDeviceChange(),
|
|
47629
|
+
osHasBluetoothSupport: this._osHasBluetoothSupport()
|
|
47630
|
+
}).pipe(switchMap(({ selectedDevice, osHasBluetoothSupport: osHasBluetoothSupport$$1 }) => {
|
|
47631
|
+
if (!selectedDevice) {
|
|
47617
47632
|
return EMPTY;
|
|
47618
47633
|
}
|
|
47619
|
-
const isUnableToUseBluetooth = this.isMissingBluetoothTransport ||
|
|
47620
|
-
!osHasBluetoothSupport(selectDevice);
|
|
47634
|
+
const isUnableToUseBluetooth = this.isMissingBluetoothTransport || !osHasBluetoothSupport$$1;
|
|
47621
47635
|
if (isUnableToUseBluetooth) {
|
|
47622
47636
|
return this.cloudClient.status().pipe(map(({ state }) => ({
|
|
47623
47637
|
connected: isWifiOnline(state),
|
|
@@ -48283,7 +48297,7 @@ class Neurosity {
|
|
|
48283
48297
|
if (hasOAuthError) {
|
|
48284
48298
|
return throwError(() => OAuthError);
|
|
48285
48299
|
}
|
|
48286
|
-
return this.cloudClient.
|
|
48300
|
+
return this.cloudClient.osVersion();
|
|
48287
48301
|
}
|
|
48288
48302
|
/**
|
|
48289
48303
|
* <StreamingModes wifi={true} bluetooth={true} />
|