@iotile/iotile-device
Version:
A typescript library for interfacing with IOTile BLE devices
216 lines • 8.35 kB
JavaScript
"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