@iotile/iotile-device
Version:
A typescript library for interfacing with IOTile BLE devices
866 lines • 44.1 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var iotile_mqtt_1 = require("./iotile-mqtt");
var iotile_common_1 = require("@iotile/iotile-common");
var Errors = require("../common/error-space");
var iotile_reports_1 = require("../common/iotile-reports");
var iotile_types_1 = require("../common/iotile-types");
var config_1 = require("../config");
var iotile_network_1 = require("./iotile-network");
;
var MatchBy;
(function (MatchBy) {
MatchBy[MatchBy["MatchBySlot"] = 1] = "MatchBySlot";
MatchBy[MatchBy["MatchController"] = 2] = "MatchController";
MatchBy[MatchBy["MatchByName"] = 3] = "MatchByName";
})(MatchBy = exports.MatchBy || (exports.MatchBy = {}));
var RemoteBridgeState;
(function (RemoteBridgeState) {
RemoteBridgeState[RemoteBridgeState["Idle"] = 0] = "Idle";
RemoteBridgeState[RemoteBridgeState["WaitingForScript"] = 1] = "WaitingForScript";
RemoteBridgeState[RemoteBridgeState["ReceivingScript"] = 2] = "ReceivingScript";
RemoteBridgeState[RemoteBridgeState["ReceivedCompleteScript"] = 3] = "ReceivedCompleteScript";
RemoteBridgeState[RemoteBridgeState["ValidatedScript"] = 4] = "ValidatedScript";
RemoteBridgeState[RemoteBridgeState["ExecutingScript"] = 5] = "ExecutingScript";
})(RemoteBridgeState = exports.RemoteBridgeState || (exports.RemoteBridgeState = {}));
function convertToSecondsSince2000(date) {
var millisecondsAt2000 = Date.UTC(2000, 0, 1);
var secondsSince2000 = Math.ceil((date.valueOf() - millisecondsAt2000) / 1000);
return secondsSince2000;
}
exports.convertToSecondsSince2000 = convertToSecondsSince2000;
/**
* Proxy class for calling functionality on the script processing and firmware update engine on an IOTile Device
*/
var RemoteBridge = /** @class */ (function () {
function RemoteBridge(adapter) {
this.adapter = adapter;
}
RemoteBridge.prototype.beginScript = function () {
return this.adapter.errorHandlingRPC(8, 0x2100, "", "L", [], 10.0);
};
RemoteBridge.prototype.endScript = function () {
return this.adapter.errorHandlingRPC(8, 0x2102, "", "L", [], 2.0);
};
RemoteBridge.prototype.triggerScript = function () {
return this.adapter.errorHandlingRPC(8, 0x2103, "", "L", [], 2.0);
};
RemoteBridge.prototype.resetScript = function () {
return this.adapter.errorHandlingRPC(8, 0x2105, "", "L", [], 20.0);
};
RemoteBridge.prototype.queryStatus = function () {
return __awaiter(this, void 0, void 0, function () {
var _a, state, error;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.adapter.typedRPC(8, 0x2104, "", "LL", [], 2.0)];
case 1:
_a = _b.sent(), state = _a[0], error = _a[1];
return [2 /*return*/, {
state: state,
lastError: error
}];
}
});
});
};
return RemoteBridge;
}());
exports.RemoteBridge = RemoteBridge;
/**
* Proxy class for calling functionality on the configuration variables of an IOTile Device
*/
var Config = /** @class */ (function () {
function Config(adapter) {
this.adapter = adapter;
this.configLock = new iotile_common_1.Mutex;
}
Config.prototype.setConfigVariable = function (target, id, fmt, data) {
return __awaiter(this, void 0, void 0, function () {
var releaseConfig, db_status, err;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.configLock.acquire()];
case 1:
releaseConfig = _a.sent();
_a.label = 2;
case 2:
_a.trys.push([2, , 9, 10]);
return [4 /*yield*/, this.getConfigDatabaseInfo(fmt)];
case 3:
db_status = _a.sent();
if (!!db_status) return [3 /*break*/, 5];
return [4 /*yield*/, this.compactConfigDatabase()];
case 4:
_a.sent();
_a.label = 5;
case 5: return [4 /*yield*/, this.startEntry(id, target)];
case 6:
err = _a.sent();
if (err) {
throw new Error('Failed to start Config entry');
}
return [4 /*yield*/, this.pushData(fmt, data)];
case 7:
_a.sent();
return [4 /*yield*/, this.finishEntry()];
case 8:
_a.sent();
return [3 /*break*/, 10];
case 9:
releaseConfig();
return [7 /*endfinally*/];
case 10: return [2 /*return*/];
}
});
});
};
Config.prototype.startEntry = function (id, target) {
return __awaiter(this, void 0, void 0, function () {
var args, slot, resp;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (target == 'controller') {
args = iotile_common_1.packArrayBuffer("H7xB", id, MatchBy.MatchController);
}
else if (target.includes('slot')) {
slot = target.split(" ")[1];
if (+slot >= 0 && +slot <= 255) {
args = iotile_common_1.packArrayBuffer("HB6xB", id, slot, MatchBy.MatchBySlot);
}
else {
throw new iotile_common_1.ArgumentError("Slot number must be between 0 and 255");
}
}
else {
throw new iotile_common_1.ArgumentError("Only controller and numbered slot targets are supported");
}
return [4 /*yield*/, this.adapter.rpc(8, 0x2a07, args, 5.0)];
case 1:
resp = _a.sent();
resp = iotile_common_1.unpackArrayBuffer("L", resp)[0];
return [2 /*return*/, resp];
}
});
});
};
Config.prototype.pushData = function (type, data) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.adapter.errorHandlingRPC(8, 0x2a08, type, 'L', [data], 5.0)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
Config.prototype.finishEntry = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.adapter.errorHandlingRPC(8, 0x2a09, "", "L", [], 5.0)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
// FIXME
// public async getConfigVariable(target: string, id: number){
// // TODO: how to find index [call count; rpc(8, 0x2a0a, ...) [ignore 0 index]]
// let index: number;
// let meta = this.adapter.errorHandlingRPC(8, 0x2a0a, "H", "L16s", [index]);
// let name; // = this.getIdentifier(index, meta);
// let value; // = this.getData(index);
// let variable = {
// 'metadata': meta,
// 'name': name,
// 'data': value
// };
// return variable;
// }
Config.prototype.compactConfigDatabase = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.adapter.errorHandlingRPC(8, 0x2a0f, "", "L", [], 5.0)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
Config.prototype.getConfigDatabaseInfo = function (type) {
return __awaiter(this, void 0, void 0, function () {
var resp, max_data, data_size, invalid_data, entry_count, invalid_count, max_entries, typeSize;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.adapter.typedRPC(8, 0x2a10, "", "LHHHHHBB", [], 5.0)];
case 1:
resp = _a.sent();
max_data = resp[0], data_size = resp[1], invalid_data = resp[2], entry_count = resp[3], invalid_count = resp[4], max_entries = resp[5];
typeSize = {
'B': 1,
'b': 1,
'H': 2,
'h': 2,
'L': 4,
'l': 4
};
// make sure there's enough room to store config variable
return [2 /*return*/, (data_size + typeSize[type] < max_data)];
}
});
});
};
return Config;
}());
exports.Config = Config;
var IOTileDevice = /** @class */ (function (_super) {
__extends(IOTileDevice, _super);
function IOTileDevice(adapter, advData) {
var _this = _super.call(this, config_1.catIOTileDevice) || this;
_this.advertisement = advData;
_this.deviceID = advData.deviceID;
_this.adapter = adapter;
_this.networkConfig = new iotile_network_1.NetworkConfig(adapter, 10);
_this.mqttBridgeConfig = new iotile_mqtt_1.MQTTBridgeConfig(adapter, 11);
_this.slug = iotile_common_1.deviceIDToSlug(_this.deviceID);
_this.connectionID = advData.connectionID;
_this.downloadLock = new iotile_common_1.Mutex;
return _this;
}
IOTileDevice.prototype.acknowledgeStreamerRPC = function (streamer, highestID, force) {
return __awaiter(this, void 0, void 0, function () {
var args, resp, decoded, err;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (streamer > 255) {
throw new iotile_common_1.ArgumentError('Acknowledgement RPC called with invalid streamer index');
}
args = iotile_common_1.packArrayBuffer("HHL", streamer, force ? 1 : 0, highestID);
return [4 /*yield*/, this.adapter.rpc(8, 0x200f, args, 2.0)];
case 1:
resp = _a.sent();
decoded = iotile_common_1.unpackArrayBuffer("L", resp);
err = decoded[0];
//If we're not forcing the update then the device can return
//that the update is older than what is currently has stored
//which is not an error.
if (!force && err === 0x8003801e) {
return [2 /*return*/];
}
else if (err != 0) {
throw new Errors.RPCError(8, 0x200f, err);
}
return [2 /*return*/];
}
});
});
};
IOTileDevice.prototype.queryStreamerRPC = function (streamer) {
return __awaiter(this, void 0, void 0, function () {
var resp, info;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.adapter.typedRPC(8, 0x200a, "H", "LLLLBBBB", [streamer], 2.0)];
case 1:
resp = _a.sent();
info = {
lastAttemptTime: resp[0],
lastSuccessTime: resp[1],
lastError: resp[2],
highestAck: resp[3],
lastStatus: resp[4],
backoffNumber: resp[5],
commStatus: resp[6]
};
return [2 /*return*/, info];
}
});
});
};
IOTileDevice.prototype.tileVersionRPC = function (address) {
return __awaiter(this, void 0, void 0, function () {
var resp, major, minor, patch;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.adapter.typedRPC(address, 0x4, "", "H6sBBBB", [], 2.0)];
case 1:
resp = _a.sent();
major = resp[2];
minor = resp[3];
patch = resp[4];
return [2 /*return*/, major + "." + minor + "." + patch];
}
});
});
};
IOTileDevice.prototype.controllerVersionRPC = function () {
return this.tileVersionRPC(8);
};
/**
* IOTile controllers have an embedded 10 character long hardware id tag that uniquely
* determines what hardware type they are. This is important information to know when
* seeing what kind of script or firmware update to apply since different hardware
* versions may require different scripts or different firmware.
*
* The value is padded out with null characters to exactly 10 bytes so make sure to
* strip those out.
*/
IOTileDevice.prototype.controllerHWVersionRPC = function () {
return __awaiter(this, void 0, void 0, function () {
var version, err_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
return [4 /*yield*/, this.adapter.typedRPC(8, 0x2, "", "10s", [], 2.0)];
case 1:
version = (_a.sent())[0];
return [2 /*return*/, version.replace(/[\0]+$/g, '')];
case 2:
err_1 = _a.sent();
//Very old firmware versions don't support the controller hw version rpc, so return null in that case
//any other error code is an error that should be propagated to the caller.
if (err_1 instanceof Errors.RPCError && err_1.errorCode == Errors.RPCProtocolError.CommandNotFound)
return [2 /*return*/, ""];
throw err_1;
case 3: return [2 /*return*/];
}
});
});
};
IOTileDevice.prototype.getDeviceInfo = function () {
return __awaiter(this, void 0, void 0, function () {
var _a, uuid, stateFlags, flags, res1, res2, res3, osInfo, appInfo, osTag, osEncVersion, appTag, appEnvVersion;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.adapter.typedRPC(8, 0x1008, "", "LLBBBBLL", [], 2.0)];
case 1:
_a = _b.sent(), uuid = _a[0], stateFlags = _a[1], flags = _a[2], res1 = _a[3], res2 = _a[4], res3 = _a[5], osInfo = _a[6], appInfo = _a[7];
osTag = osInfo & ((1 << 20) - 1);
osEncVersion = osInfo >> 20;
appTag = appInfo & ((1 << 20) - 1);
appEnvVersion = appInfo >> 20;
return [2 /*return*/, {
uuid: uuid,
stateFlags: stateFlags,
flags: flags,
osTag: osTag,
osVersion: this.convertEncodedVersion(osEncVersion),
appTag: appTag,
appVersion: this.convertEncodedVersion(appEnvVersion)
}];
}
});
});
};
IOTileDevice.prototype.convertEncodedVersion = function (encVersion) {
var major = (encVersion >> 6) & ((1 << 6) - 1);
var minor = (encVersion >> 0) & ((1 << 6) - 1);
return major + "." + minor;
};
IOTileDevice.prototype.highestUniqueIDRPC = function () {
return __awaiter(this, void 0, void 0, function () {
var highestID;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.adapter.errorHandlingRPC(8, 0x2011, "", "LL", [], 2.0)];
case 1:
highestID = (_a.sent())[0];
return [2 /*return*/, highestID];
}
});
});
};
IOTileDevice.prototype.graphInput = function (stream, value) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (typeof stream == 'string') {
stream = iotile_common_1.mapStreamName(stream);
}
return [4 /*yield*/, this.adapter.errorHandlingRPC(8, 0x2004, "LH", "L", [value, stream], 1.0)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
/**
* Clear all stored readings in the device.
*
* This removes all buffered and output stream data stored in the device.
*/
IOTileDevice.prototype.clearAllReadings = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.adapter.errorHandlingRPC(8, 0x200c, "", "L", [], 2.0)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
IOTileDevice.prototype.triggerStreamer = function (streamer) {
return __awaiter(this, void 0, void 0, function () {
var error;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.adapter.typedRPC(8, 0x2010, "H", "L", [streamer], 1.0)];
case 1:
error = (_a.sent())[0];
return [2 /*return*/, error];
}
});
});
};
IOTileDevice.prototype.waitReports = function (notifier, streamers) {
return __awaiter(this, void 0, void 0, function () {
var reportInProgress, reportFailed, reportCount, invalidReports, streamerNames, streamerNumbers, _i, streamers_1, streamer, _a, _b, streamer, subNotifier, progressCallback, disconnectCallback, reportStartedHandler, reportStalledHandler, reportParseErrorHandler, reportProgressHandler, reportInvalidHandler, reportFinishedHandler, reportDisconnectedHandler, _c, streamerNumbers_1, key, info, err, i;
var _this = this;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
reportInProgress = false;
reportFailed = false;
reportCount = 0;
invalidReports = 0;
streamerNames = {};
streamerNumbers = [];
/**
* Setup default names for all streamers if we were not passed in a dictionary
*/
if (streamers instanceof Array) {
for (_i = 0, streamers_1 = streamers; _i < streamers_1.length; _i++) {
streamer = streamers_1[_i];
streamerNames[streamer] = "Report Type " + streamer;
}
streamerNumbers = streamers;
}
else {
streamerNames = streamers;
for (_a = 0, _b = Object.keys(streamers); _a < _b.length; _a++) {
streamer = _b[_a];
streamerNumbers.push(+streamer);
}
}
subNotifier = null;
progressCallback = function (eventName, event) {
_this.logTrace("waitReports received event: " + eventName, event);
switch (event.name) {
case 'ReportInvalidEvent':
reportInProgress = false;
invalidReports += 1;
notifier.finishOne();
break;
case 'ReportFinishedEvent':
reportInProgress = false;
reportCount += 1;
notifier.finishOne();
break;
case 'ReportStartedEvent':
subNotifier = notifier.startOne("Receiving " + getReportName(event.reportIndex, streamerNames), 20);
reportInProgress = true;
break;
case 'ReportProgressEvent':
if (subNotifier != null)
subNotifier.finishOne();
reportInProgress = true;
break;
case 'ReportStalledEvent':
case 'ReportParsingError':
reportInProgress = false;
reportFailed = true;
break;
}
};
disconnectCallback = function (eventName, event) {
reportInProgress = false;
};
reportStartedHandler = this.adapter.subscribe(iotile_types_1.AdapterEvent.RobustReportStarted, progressCallback);
reportStalledHandler = this.adapter.subscribe(iotile_types_1.AdapterEvent.RobustReportStalled, progressCallback);
reportParseErrorHandler = this.adapter.subscribe(iotile_types_1.AdapterEvent.UnrecoverableStreamingError, progressCallback);
reportProgressHandler = this.adapter.subscribe(iotile_types_1.AdapterEvent.RobustReportProgress, progressCallback);
reportInvalidHandler = this.adapter.subscribe(iotile_types_1.AdapterEvent.RobustReportInvalid, progressCallback);
reportFinishedHandler = this.adapter.subscribe(iotile_types_1.AdapterEvent.RobustReportFinished, progressCallback);
reportDisconnectedHandler = this.adapter.subscribe(iotile_types_1.AdapterEvent.Disconnected, disconnectCallback);
/**
* Make sure to clear out any previous corrupt data from the streaming interface before starting to
* receive new reports. This prevents a permanent failure receiving data if there is a corrupt report
* that has corruption in the first 20 bytes since that will cause it to decode as an invalid report
* type and the report parser will enter permanent failure until you reconnect or reset the stream
* interface.
*/
this.adapter.resetStreaming();
_d.label = 1;
case 1:
_d.trys.push([1, , 10, 11]);
_c = 0, streamerNumbers_1 = streamerNumbers;
_d.label = 2;
case 2:
if (!(_c < streamerNumbers_1.length)) return [3 /*break*/, 6];
key = streamerNumbers_1[_c];
return [4 /*yield*/, this.queryStreamerRPC(+key)];
case 3:
info = _d.sent();
this.logDebug("Queried streamer " + key, {
info: info
});
if (!(info.commStatus === 0)) return [3 /*break*/, 5];
return [4 /*yield*/, this.triggerStreamer(+key)];
case 4:
err = _d.sent();
this.logDebug("Triggered streamer " + key, {
returnValue: err
});
// if error != no new reports
if (err && (err !== 0x8003801f))
throw new Errors.FatalStreamingError("Error triggering streamer " + key + ", error: " + err, "Download Failed - Please Try Again");
_d.label = 5;
case 5:
_c++;
return [3 /*break*/, 2];
case 6:
if (!true) return [3 /*break*/, 9];
return [4 /*yield*/, iotile_common_1.delay(500)];
case 7:
_d.sent();
if (reportInProgress)
return [3 /*break*/, 6];
return [4 /*yield*/, iotile_common_1.delay(100)];
case 8:
_d.sent();
if (!reportInProgress)
return [3 /*break*/, 9];
return [3 /*break*/, 6];
case 9:
if (reportFailed)
throw new Errors.FatalStreamingError("Stall while receiving a report", "Streaming Failed - Please Try Again");
return [3 /*break*/, 11];
case 10:
//clean up subscriptions
reportStartedHandler();
reportStalledHandler();
reportProgressHandler();
reportFinishedHandler();
reportDisconnectedHandler();
reportInvalidHandler();
reportParseErrorHandler();
return [7 /*endfinally*/];
case 11:
/**
* If we received fewer reports than we were expecting, make sure we finish the rest of the progress items
*/
for (i = reportCount; i < streamerNumbers.length; ++i) {
notifier.startOne("Skipping Report with No New Data", 1);
notifier.finishOne();
}
return [2 /*return*/, {
numInvalid: invalidReports,
numReceived: reportCount
}];
}
});
});
};
IOTileDevice.prototype.receiveReports = function (options, progress) {
return __awaiter(this, void 0, void 0, function () {
var result, receivedNames, clearSubscription, reportInfo, _i, _a, key;
var _this = this;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
result = { reports: [], receivedFromAll: true, receivedExtra: false };
if (!progress)
progress = new iotile_common_1.ProgressNotifier();
receivedNames = [];
clearSubscription = this.adapter.subscribe(iotile_types_1.AdapterEvent.RawRobustReport, function (event, report) { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
try {
// is this a report we care about?
if (report.streamer in options.expectedStreamers && !(report.streamer in receivedNames)) {
result.reports.push(report);
receivedNames.push(report.streamer);
}
else {
result.receivedExtra = true;
}
}
catch (err) {
this.logException("Could not process report: " + options.expectedStreamers[report.streamer], new Error(err));
}
return [2 /*return*/];
});
}); });
_b.label = 1;
case 1:
_b.trys.push([1, , 3, 4]);
return [4 /*yield*/, this.waitReports(progress, options.expectedStreamers)];
case 2:
reportInfo = _b.sent();
this.logDebug("Result of waitReports", {
streamers: options.expectedStreamers,
result: reportInfo
});
if (reportInfo.numInvalid > 0)
throw new Errors.FatalStreamingError("Received " + reportInfo.numInvalid + " invalid reports", 'Download Failed - Please Try Again');
return [3 /*break*/, 4];
case 3:
clearSubscription();
return [7 /*endfinally*/];
case 4:
for (_i = 0, _a = Object.keys(options.expectedStreamers); _i < _a.length; _i++) {
key = _a[_i];
if (!(+key in receivedNames)) {
result.receivedFromAll = false;
}
}
if (options.requireAll && !result.receivedFromAll) {
this.logError("Failed to receive all required streamers", {
result: result,
options: options
});
throw new Errors.FatalStreamingError("Missing required report", 'Download Failed - Please Try Again');
}
//Make sure we finish
return [2 /*return*/, result];
}
});
});
};
IOTileDevice.prototype.remoteBridge = function () {
return new RemoteBridge(this.adapter);
};
IOTileDevice.prototype.config = function () {
return new Config(this.adapter);
};
IOTileDevice.prototype.currentTime = function (synchronizationSlopSeconds) {
if (synchronizationSlopSeconds === void 0) { synchronizationSlopSeconds = 60; }
return __awaiter(this, void 0, void 0, function () {
var deviceTime, timestamp, secondsSince2000, convertedSeconds, convertedTime, currentSeconds, synched;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.adapter.typedRPC(8, 0x1001, "", "L", [])];
case 1:
timestamp = (_a.sent())[0];
config_1.catAdapter.info("Timestamp is: " + timestamp);
if (!!(timestamp & (1 << 31)) === true) {
secondsSince2000 = timestamp & ((1 << 31) - 1);
config_1.catAdapter.info("Seconds since 2000: " + secondsSince2000);
convertedSeconds = (Date.UTC(2000, 0, 1) / 1000) + secondsSince2000;
convertedTime = new Date(convertedSeconds * 1000);
currentSeconds = Date.now() / 1000;
synched = (Math.abs(convertedSeconds - currentSeconds) <= synchronizationSlopSeconds);
//Returns a DeviceUTCTime if UTC is set
deviceTime = {
isUTC: true,
isSynchronized: synched,
currentTime: convertedTime
};
}
else {
//Returns a DeviceUptime if UTC is not set
deviceTime = {
isUTC: false,
isSynchronized: false,
currentTime: timestamp
};
}
return [2 /*return*/, deviceTime];
}
});
});
};
IOTileDevice.prototype.synchronizeTime = function (forcedTime) {
return __awaiter(this, void 0, void 0, function () {
var secondsSince2000;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!forcedTime) {
forcedTime = new Date();
}
secondsSince2000 = convertToSecondsSince2000(forcedTime);
config_1.catAdapter.info("Sending time to RTC: " + secondsSince2000);
return [4 /*yield*/, this.adapter.errorHandlingRPC(8, 0x1010, "L", "L", [secondsSince2000])];
case 1:
_a.sent();
return [2 /*return*/, secondsSince2000];
}
});
});
};
IOTileDevice.prototype.downloadStream = function (streamName, progress) {
return __awaiter(this, void 0, void 0, function () {
var releaseStream, streamId, _a, err, count, device_time, now, readings, subNotifier, i, _b, timestamp, raw_reading, timebase, reading;
return __generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, this.downloadLock.acquire()];
case 1:
releaseStream = _c.sent();
_c.label = 2;
case 2:
_c.trys.push([2, , 8, 9]);
streamId = iotile_common_1.mapStreamName(streamName);
return [4 /*yield*/, this.adapter.errorHandlingRPC(8, 0x2008, "H", "LLLL", [streamId], 3.0)];
case 3:
_a = _c.sent(), err = _a[0], count = _a[1], device_time = _a[2];
now = new Date();
readings = [];
subNotifier = undefined;
if (err) {
throw new iotile_common_1.ArgumentError("Error starting stream download: " + err);
}
if (progress) {
subNotifier = progress.startOne("Downloading " + count + " readings", count);
}
i = 0;
_c.label = 4;
case 4:
if (!(i < count)) return [3 /*break*/, 7];
return [4 /*yield*/, this.adapter.errorHandlingRPC(8, 0x2009, "", "LLL", [], 1.0)];
case 5:
_b = _c.sent(), timestamp = _b[0], raw_reading = _b[1];
timebase = new Date(now.valueOf() - (device_time * 1000));
reading = new iotile_reports_1.RawReading(streamId, raw_reading, timestamp, timebase);
readings.push(reading);
if (subNotifier) {
subNotifier.finishOne();
}
_c.label = 6;
case 6:
i++;
return [3 /*break*/, 4];
case 7: return [2 /*return*/, readings];
case 8:
releaseStream();
return [7 /*endfinally*/];
case 9: return [2 /*return*/];
}
});
});
};
IOTileDevice.prototype.inspectVirtualStream = function (stream) {
return __awaiter(this, void 0, void 0, function () {
var val;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (typeof stream == 'string') {
stream = iotile_common_1.mapStreamName(stream);
}
return [4 /*yield*/, this.adapter.errorHandlingRPC(8, 0x200b, "H", "LL", [stream])];
case 1:
val = (_a.sent())[0];
return [2 /*return*/, val];
}
});
});
};
IOTileDevice.prototype.queryBLEConnectionInfo = function () {
return __awaiter(this, void 0, void 0, function () {
var _a, interval, timeout, prefMin, prefMax, prefTimeout;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.adapter.errorHandlingRPC(8, 0x8000, "", "LHHHHHH", [], 1.0)];
case 1:
_a = _b.sent(), interval = _a[0], timeout = _a[1], prefMin = _a[2], prefMax = _a[3], prefTimeout = _a[4];
return [2 /*return*/, {
intervalMS: interval * 1.25,
preferredMinMS: prefMin * 1.25,
preferredMaxMS: prefMax * 1.25,
timeoutMS: timeout * 10
}];
}
});
});
};
IOTileDevice.prototype.updateBLEParams = function (minIntervalMS, maxIntervalMS, timeoutMS) {
return __awaiter(this, void 0, void 0, function () {
var minInterval, maxInterval, timeout, err;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
minInterval = Math.floor(minIntervalMS / 1.25);
maxInterval = Math.floor(maxIntervalMS / 1.25);
timeout = Math.floor(timeoutMS / 10);
if (minIntervalMS < 7.5 || maxIntervalMS < minIntervalMS) {
throw new iotile_common_1.ArgumentError("Invalid interval given [" + minIntervalMS + ", " + maxIntervalMS + "], must be min >= 7.5 ms, max >= min");
}
if (timeoutMS < 100) {
throw new iotile_common_1.ArgumentError("Invalid connection timeout given (" + timeoutMS + " ms), must be >= 100 ms.");
}
return [4 /*yield*/, this.adapter.typedRPC(8, 0x8001, "HHHH", "L", [minInterval, maxInterval, timeout, 0], 1.0)];
case 1:
err = (_a.sent())[0];
return [2 /*return*/, err];
}
});
});
};
return IOTileDevice;
}(iotile_common_1.LoggingBase));
exports.IOTileDevice = IOTileDevice;
function getReportName(streamer, streamerNames) {
if (!(streamer in streamerNames))
return "Extra Report";
return streamerNames[streamer];
}
//# sourceMappingURL=iotile-device.js.map