UNPKG

@robotical/ricjs

Version:

Javascript/TS library for Robotical RIC

266 lines 11 kB
"use strict"; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // RICJS // Communications Library // // Rob Dobson & Chris Greening 2020-2022 // (C) 2020-2022 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const RICConnEvents_1 = require("./RICConnEvents"); const RICLog_1 = tslib_1.__importDefault(require("./RICLog")); const RICUtils_1 = tslib_1.__importDefault(require("./RICUtils")); class RICChannelWebBLE { constructor() { // Device and characteristics this._bleDevice = null; this._characteristicTx = null; this._characteristicRx = null; // Message handler this._ricMsgHandler = null; // Conn event fn this._onConnEvent = null; // Last message tx time this._msgTxTimeLast = Date.now(); this._msgTxMinTimeBetweenMs = 1; this.maxRetries = 1; // Connected flag and retries this._isConnected = false; this._maxConnRetries = 3; // Event listener fn this._eventListenerFn = null; // File Handler parameters this._requestedBatchAckSize = 10; this._requestedFileBlockSize = 500; } fhBatchAckSize() { return this._requestedBatchAckSize; } fhFileBlockSize() { return this._requestedFileBlockSize; } // Set message handler setMsgHandler(ricMsgHandler) { this._ricMsgHandler = ricMsgHandler; } // BLE interfaces are automatically subscribed to publish messages requiresSubscription() { return false; } // isEnabled isEnabled() { if (navigator.bluetooth) { RICLog_1.default.error("Web Bluetooth is supported in your browser."); return true; } else { window.alert("Web Bluetooth API is not available.\n" + 'Please make sure the "Experimental Web Platform features" flag is enabled.'); return false; } } // isConnected isConnected() { return this._bleDevice !== null && this._isConnected; } // Set onConnEvent handler setOnConnEvent(connEventFn) { this._onConnEvent = connEventFn; } // Disconnection event onDisconnected(event) { const device = event.target; RICLog_1.default.debug(`RICChannelWebBLE.onDisconnected ${device.name}`); if (this._bleDevice) { this._bleDevice.removeEventListener("gattserverdisconnected", this._eventListenerFn); } this._isConnected = false; if (this._onConnEvent) { this._onConnEvent(RICConnEvents_1.RICConnEvent.CONN_DISCONNECTED_RIC); } } // Get connected locator getConnectedLocator() { return this._bleDevice || ""; } // Connect to a device async connect(locator) { // RICLog.debug(`Selected device: ${deviceID}`); this._bleDevice = locator; if (this._bleDevice && this._bleDevice.gatt) { try { // Connect for (let connRetry = 0; connRetry < this._maxConnRetries; connRetry++) { // Connect await RICUtils_1.default.withTimeout(2000, this._bleDevice.gatt.connect()); RICLog_1.default.debug(`RICChannelWebBLE.connect - ${this._bleDevice.gatt.connected ? "OK" : "FAILED"} connection to device ${this._bleDevice.name}`); // Get service try { const service = await this._bleDevice.gatt.getPrimaryService(RICChannelWebBLE.RICServiceUUID); RICLog_1.default.debug(`RICChannelWebBLE.connect - found service: ${service.uuid}`); try { // Get Tx and Rx characteristics this._characteristicTx = await service.getCharacteristic(RICChannelWebBLE.RICCmdUUID); RICLog_1.default.debug(`RICChannelWebBLE.connect - found char ${this._characteristicTx.uuid}`); this._characteristicRx = await service.getCharacteristic(RICChannelWebBLE.RICRespUUID); RICLog_1.default.debug(`RICChannelWebBLE.connect - found char ${this._characteristicRx.uuid}`); // Notifications of received messages try { await this._characteristicRx.startNotifications(); RICLog_1.default.debug("RICChannelWebBLE.connect - notifications started"); this._characteristicRx.addEventListener("characteristicvaluechanged", this._onMsgRx.bind(this)); } catch (error) { RICLog_1.default.debug("RICChannelWebBLE.connnect - addEventListener failed " + error); } // Connected ok RICLog_1.default.debug(`RICChannelWebBLE.connect ${this._bleDevice.name}`); // Add disconnect listener this._eventListenerFn = this.onDisconnected.bind(this); this._bleDevice.addEventListener("gattserverdisconnected", this._eventListenerFn); // Connected this._isConnected = true; return true; } catch (error) { RICLog_1.default.error(`RICChannelWebBLE.connect - cannot find characteristic: ${error}`); } } catch (error) { if (connRetry === this._maxConnRetries - 1) { RICLog_1.default.error(`RICChannelWebBLE.connect - cannot get service ${error}`); } else { RICLog_1.default.debug(`RICChannelWebBLE.connect - cannot get service - retryIdx ${connRetry} ${error}`); } } } } catch (error) { RICLog_1.default.warn(`RICChannelWebBLE.connect - cannot connect ${error}`); } // Disconnect if (this._bleDevice && this._bleDevice.gatt && this._bleDevice.gatt.connected) { try { await this._bleDevice.gatt.disconnect(); } catch (error) { RICLog_1.default.warn(`RICChannelWebBLE.connect - cannot disconnect ${error}`); } } } return false; } // Disconnect async disconnect() { if (this._bleDevice && this._bleDevice.gatt) { try { RICLog_1.default.debug(`RICChannelWebBLE.disconnect GATT`); await this._bleDevice.gatt.disconnect(); } catch (error) { RICLog_1.default.debug(`RICChannelWebBLE.disconnect ${error}`); } } } pauseConnection(pause) { RICLog_1.default.verbose(`pauseConnection ${pause} - no effect for this channel type`); return; } // Handle notifications _onMsgRx(event) { // Get characteristic const characteristic = event.target; // Get value const value = characteristic.value; if (value !== undefined) { const msg = new Uint8Array(value.buffer); // Handle message if (this._ricMsgHandler) { try { this._ricMsgHandler.handleNewRxMsg(msg); } catch (error) { RICLog_1.default.debug(`RICChannelWebBLE.onMsgRx ${error}`); } } } } // Send a message async sendTxMsg(msg // _sendWithResponse: boolean ) { // Check valid if (this._bleDevice === null) { return false; } // Retry upto maxRetries for (let retryIdx = 0; retryIdx < this.maxRetries; retryIdx++) { // Check for min time between messages while (Date.now() - this._msgTxTimeLast < this._msgTxMinTimeBetweenMs) { await new Promise((resolve) => setTimeout(resolve, 5)); } this._msgTxTimeLast = Date.now(); // Write to the characteristic try { if (this._characteristicTx) { if (this._characteristicTx.writeValueWithoutResponse) { await this._characteristicTx.writeValueWithoutResponse(msg); } else if (this._characteristicTx.writeValue) { await this._characteristicTx.writeValue(msg); } else if (this._characteristicTx.writeValueWithResponse) { await this._characteristicTx.writeValueWithResponse(msg); } } break; } catch (error) { if (retryIdx === this.maxRetries - 1) { RICLog_1.default.info(`RICChannelWebBLE.sendTxMsg ${error} retried ${retryIdx} times`); } } } return true; } // Send message without awaiting response async sendTxMsgNoAwait(msg // _sendWithResponse: boolean ) { // Check valid if (this._bleDevice === null) { return false; } // Check for min time between messages while (Date.now() - this._msgTxTimeLast < this._msgTxMinTimeBetweenMs) { await new Promise((resolve) => setTimeout(resolve, 5)); } this._msgTxTimeLast = Date.now(); // Write to the characteristic if (this._characteristicTx) { if (this._characteristicTx.writeValueWithoutResponse) { this._characteristicTx.writeValueWithoutResponse(msg); } else if (this._characteristicTx.writeValue) { this._characteristicTx.writeValue(msg); } else if (this._characteristicTx.writeValueWithResponse) { this._characteristicTx.writeValueWithResponse(msg); } return true; } return false; } } exports.default = RICChannelWebBLE; // BLE UUIDS RICChannelWebBLE.RICServiceUUID = "aa76677e-9cfd-4626-a510-0d305be57c8d"; RICChannelWebBLE.RICCmdUUID = "aa76677e-9cfd-4626-a510-0d305be57c8e"; RICChannelWebBLE.RICRespUUID = "aa76677e-9cfd-4626-a510-0d305be57c8f"; //# sourceMappingURL=RICChannelWebBLE.js.map