UNPKG

@iotile/iotile-device

Version:

A typescript library for interfacing with IOTile BLE devices

216 lines 8.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const ring_buffer_1 = require("../common/ring-buffer"); const Errors = require("../common/error-space"); const iotile_reports_1 = require("../common/iotile-reports"); var ReceiveStatus; (function (ReceiveStatus) { ReceiveStatus[ReceiveStatus["Idle"] = 0] = "Idle"; ReceiveStatus[ReceiveStatus["InProgress"] = 1] = "InProgress"; })(ReceiveStatus = exports.ReceiveStatus || (exports.ReceiveStatus = {})); class ReportParserEvent { constructor(name, finishedPercentage, reportIndex) { this.name = name; this.finishedPercentage = finishedPercentage; this.reportIndex = reportIndex; } } exports.ReportParserEvent = ReportParserEvent; class ReportStartedEvent extends ReportParserEvent { constructor(totalSize, reportIndex) { super('ReportStartedEvent', 0, reportIndex); this.totalSize = totalSize; } } exports.ReportStartedEvent = ReportStartedEvent; class ReportStalledEvent extends ReportParserEvent { constructor(finishedPercentage, reportIndex) { super('ReportStalledEvent', finishedPercentage, reportIndex); } } exports.ReportStalledEvent = ReportStalledEvent; class ReportProgressEvent extends ReportParserEvent { constructor(finishedPercentage, reportIndex) { super('ReportProgressEvent', finishedPercentage, reportIndex); } } exports.ReportProgressEvent = ReportProgressEvent; class ReportFinishedEvent extends ReportParserEvent { constructor(reportIndex) { super('ReportFinishedEvent', 100, reportIndex); } } exports.ReportFinishedEvent = ReportFinishedEvent; class ReportInvalidEvent extends ReportParserEvent { constructor(reportIndex, rawData) { super('ReportInvalidEvent', 100, reportIndex); this.rawData = rawData; } } exports.ReportInvalidEvent = ReportInvalidEvent; class ReportParser { constructor(ringBufferSize, expand = false) { this.ringBuffer = new ring_buffer_1.RingBuffer(ringBufferSize, expand); this.broken = false; this._receiveState = ReceiveStatus.Idle; this._inProgressReceived = 0; this._inProgressTotal = 0; this._lastProgressReport = 0; this._lastEvent = null; this._lastUpdateTime = null; this._reportsReceived = 0; this._receivedTime = null; this._lastUpdateTime = null; this._progressReportInterval = 5; } get state() { return this._receiveState; } get inProgressReceived() { return this._inProgressReceived; } get inProgressTotal() { return this._inProgressTotal; } stop() { this.broken = true; if (this._receiveState == ReceiveStatus.InProgress) { this.updateStatus(false, 0, 0); } } pushData(chunk) { if (this.broken) { throw new Errors.ReportParsingStoppedError('attempting to push data to a stopped report parser'); } this.ringBuffer.push(chunk); return this.tryParseReports(); } reset() { this.ringBuffer.reset(); this.broken = false; this._receiveState = ReceiveStatus.Idle; this._inProgressReceived = 0; this._inProgressTotal = 0; this._lastProgressReport = 0; this._lastEvent = null; this._lastUpdateTime = null; this._reportsReceived = 0; } popLastEvent() { let event = this._lastEvent; if (this._receivedTime && this._lastUpdateTime && this._lastEvent && (this._lastUpdateTime.getSeconds() + 1 < (new Date()).getSeconds())) { this._lastEvent = new ReportStalledEvent(this._lastEvent.finishedPercentage, this._lastEvent.reportIndex); } else { this._lastEvent = null; } return event; } tryParseReports() { if (this.broken) { throw new Errors.ReportParsingStoppedError('attempting to parse reports with a stopped parser'); } let reports = []; try { while (true) { let report = this.tryParseReport(); if (report != null) { reports.push(report); } } } catch (err) { if (err.name == 'RingBufferEmptyError') { } else { this.broken = true; throw new Errors.ReportParsingError(err.message); } } return reports; } tryParseReport() { let val = this.ringBuffer.peekAs('B'); let reportType = val[0]; switch (reportType) { case 0: return this.tryParseIndividualReport(); case 1: return this.tryParseListReport(); default: throw new Errors.ReportParsingError('Unknown report format received: ' + reportType); } } tryParseIndividualReport() { let report = this.ringBuffer.popAs("BBHLLLL"); let format = report[0]; let stream = report[2]; let uuid = report[3]; let sentTimestamp = report[4]; let readingTimestamp = report[5]; let readingValue = report[6]; let now = new Date(); let onTime = new Date(now.valueOf() - (sentTimestamp * 1000)); let reading = new iotile_reports_1.RawReading(stream, readingValue, readingTimestamp, onTime); return new iotile_reports_1.IndividualReport(uuid, sentTimestamp, reading); } tryParseListReport() { let header = this.ringBuffer.peekAs("BBHLLLBBH"); let totalLength = (header[1] | (header[2] << 8)); let uuid = header[3]; let originStreamer = header[7]; if (totalLength > this.ringBuffer.count) { this.updateStatus(true, totalLength, this.ringBuffer.count, originStreamer); } if (this._receivedTime == null) { this._receivedTime = new Date(); } let totalReport = this.ringBuffer.pop(totalLength); this.updateStatus(false, 0, 0, originStreamer); let report = new iotile_reports_1.SignedListReport(uuid, originStreamer, totalReport, this._receivedTime); this._receivedTime = null; if (report.validity == iotile_reports_1.SignatureStatus.Invalid) { this._lastEvent = new ReportInvalidEvent(this._reportsReceived, totalReport); report = null; } this._reportsReceived += 1; return report; } updateStatus(inProgress, totalSize, receivedSize, streamer) { if (streamer == undefined) streamer = -1; if (inProgress && this._receiveState != ReceiveStatus.InProgress && receivedSize < totalSize) { this._lastEvent = new ReportStartedEvent(totalSize, streamer); } else if (!inProgress && this._receiveState == ReceiveStatus.InProgress) { this._lastEvent = new ReportFinishedEvent(streamer); } else if (inProgress && this._inProgressReceived != receivedSize) { let lastPercentage = this._lastProgressReport / this._inProgressTotal * 100; let currentPercentage = receivedSize / this._inProgressTotal * 100; let lastProgress = Math.floor(lastPercentage / this._progressReportInterval); let currentProgress = Math.floor(currentPercentage / this._progressReportInterval); if (currentProgress != lastProgress) { this._lastEvent = new ReportProgressEvent(currentProgress * this._progressReportInterval, streamer); this._lastProgressReport = receivedSize; } } else if (inProgress && this._receiveState != ReceiveStatus.InProgress && receivedSize == totalSize) { } this._lastUpdateTime = new Date(); if (inProgress) { this._receiveState = ReceiveStatus.InProgress; this._inProgressTotal = totalSize; this._inProgressReceived = receivedSize; } else { this._receiveState = ReceiveStatus.Idle; this._inProgressTotal = 0; this._inProgressReceived = 0; this._lastProgressReport = 0; } } } exports.ReportParser = ReportParser; //# sourceMappingURL=iotile-report-parser.js.map