[Examples] #359 Cleaned up REMS data integration example.

This commit is contained in:
Henry
2016-01-22 10:49:40 -08:00
316 changed files with 17432 additions and 6983 deletions

View File

@ -28,6 +28,9 @@ define(
* source and its data types. The data dictionary will be parsed by a custom
* server provider for this data source (in this case
* {@link RemsTelemetryServerAdapter}).
*
* Typically a data dictionary would be made available alongside the
* telemetry data source itself.
*/
function () {
return {

View File

@ -28,6 +28,18 @@ define(
var TAXONOMY_ID = "msl:curiosity",
PREFIX = "msl_tlm:";
/**
* Function that is executed on application startup and populates
* the navigation tree with objects representing the MSL REMS
* telemetry points. The tree is populated based on the data
* dictionary on the provider.
*
* @param {RemsTelemetryServerAdapter} adapter The server adapter
* (necessary in order to retrieve data dictionary)
* @param objectService the ObjectService which allows for lookup of
* objects by ID
* @constructor
*/
function RemsTelemetryInitializer(adapter, objectService) {
function makeId(element) {
return PREFIX + element.identifier;

View File

@ -27,43 +27,53 @@ define (
var SOURCE = "rems.source";
function RemsTelemetryProvider(adapter, $q){
/*
Filters requests for telemetry so that it only handles requests for
this source
*/
function RemsTelemetryProvider(adapter, $q) {
this.adapter = adapter;
this.$q = $q;
}
/**
* Retrieve telemetry from this telemetry source.
* @memberOf example/msl
* @param {Array<TelemetryRequest>} requests An array of all request
* objects (which needs to be filtered to only those relevant to this
* source)
* @returns {Promise} A {@link Promise} resolved with a {@link RemsTelemetrySeries}
* object that wraps the telemetry returned from the telemetry source.
*/
RemsTelemetryProvider.prototype.requestTelemetry = function (requests) {
var packaged = {},
relevantReqs = requests.filter(matchesSource),
adapter = this.adapter;
function matchesSource(request) {
return (request.source === SOURCE);
}
return {
requestTelemetry: function(requests) {
var packaged = {},
relevantReqs = requests.filter(matchesSource);
function addToPackage(history) {
packaged[SOURCE][history.id] =
new RemsTelemetrySeries(history.values);
}
function handleRequest(request) {
var key = request.key;
return adapter.history(key).then(addToPackage);
}
packaged[SOURCE] = {};
return $q.all(relevantReqs.map(handleRequest))
.then(function () {
return packaged;
});
},
subscribe: function (callback, requests) {
return function() {};
},
unsubscribe: function (callback, requests) {
return function() {};
}
function addToPackage(history) {
packaged[SOURCE][history.id] =
new RemsTelemetrySeries(history.values);
}
function handleRequest(request) {
var key = request.key;
return adapter.history(key).then(addToPackage);
}
packaged[SOURCE] = {};
return this.$q.all(relevantReqs.map(handleRequest))
.then(function () {
return packaged;
});
}
/**
* This data source does not support real-time subscriptions
*/
RemsTelemetryProvider.prototype.subscribe = function (callback, requests) {
return function() {};
},
RemsTelemetryProvider.prototype.unsubscribe = function (callback, requests) {
return function() {};
}
return RemsTelemetryProvider;

View File

@ -24,18 +24,59 @@ define(
function () {
"use strict";
/**
* @typedef {Object} RemsTelemetryValue
* @memberOf example/msl
* @property {number} date The date/time of the telemetry value. Constitutes the domain value of this value pair
* @property {number} value The value of this telemetry datum.
* A floating point value representing some observable quantity (eg.
* temperature, air pressure, etc.)
*/
/**
* A representation of a collection of telemetry data. The REMS
* telemetry data is time ordered, with the 'domain' value
* constituting the time stamp of each data value and the
* 'range' being the value itself.
*
* TelemetrySeries will typically wrap an array of telemetry data,
* and provide an interface for retrieving individual an telemetry
* value.
* @memberOf example/msl
* @param {Array<RemsTelemetryValue>} data An array of telemetry values
* @constructor
*/
function RemsTelemetrySeries(data) {
return {
getPointCount: function(){
return data.length;
},
getDomainValue: function(index) {
return data[index].date;
},
getRangeValue: function(index){
return data[index].value;
}
}
this.data = data;
}
/**
* @returns {number} A count of the number of data values available in
* this series
*/
RemsTelemetrySeries.prototype.getPointCount = function() {
return this.data.length;
};
/**
* The domain value at the given index. The Rems telemetry data is
* time ordered, so the domain value is the time stamp of each data
* value.
* @param index
* @returns {number} the time value in ms since 1 January 1970
*/
RemsTelemetrySeries.prototype.getDomainValue = function(index) {
return this.data[index].date;
};
/**
* The range value of the REMS data set is the value of the thing
* being measured, be it temperature, air pressure, etc.
* @param index The datum in the data series to return the range
* value of.
* @returns {number} A floating point number
*/
RemsTelemetrySeries.prototype.getRangeValue = function(index) {
return this.data[index].value;
}
return RemsTelemetrySeries;

View File

@ -25,20 +25,20 @@ define(
["./MSLDataDictionary"],
function (MSLDataDictionary) {
"use strict";
var TERRESTRIAL_DATE = "terrestrial_date";
/**
* Fetches historical data from the REMS instrument on the Curiosity
* Rover. Exposes two services to client code, one
* Rover.
* @memberOf example/msl
* @param $q
* @param $http
* @param REMS_WS_URL
* @returns {{dictionary: exports, history: Function}}
* @param REMS_WS_URL The location of the REMS telemetry data.
* @constructor
*/
function RemsTelemetryServerAdapter($q, $http, REMS_WS_URL) {
this.histories = {},
this.historyData = {},
this.deferreds = {};
this.REMS_WS_URL = REMS_WS_URL;
this.$q = $q;
@ -46,48 +46,69 @@ define(
}
/**
* The data dictionary for this data source.
* @type {MSLDataDictionary}
*/
RemsTelemetryServerAdapter.prototype.dictionary = MSLDataDictionary;
/**
* Fetches historical data from source, and associates it with the
* given request ID.
* @private
*/
RemsTelemetryServerAdapter.prototype.requestHistory = function(id) {
var self = this;
return this.$http.get(this.REMS_WS_URL).then(function(response){
self.histories = {};
/**
* All history is fetched in one go, cache it all to save round trips to the server on subsequent requests
/*
* Refresh history data on each request so that it's always
* current.
*/
self.historyData = {};
/*
* History data is organised by Sol. Iterate over sols...
*/
response.data.soles.forEach(function(solData){
for (var prop in solData){
self.histories[prop] = self.histories[prop] || [];
/*
* Each sol contains a number of properties for each
* piece of data available, eg. min ground temperature,
* avg air pressure, etc.
*/
Object.keys(solData).forEach(function (prop) {
self.historyData[prop] = self.historyData[prop] || [];
/*
* Check that valid data exists
*/
if (!isNaN(solData[prop])) {
self.histories[prop].unshift({
/*
* Append each data point to the array of values
* for this data point property (min. temp, etc).
*/
self.historyData[prop].unshift({
date: Date.parse(solData[TERRESTRIAL_DATE]),
value: solData[prop]
});
}
}
});
});
self.deferreds[id].resolve({id: id, values: self.histories[id]});
self.deferreds[id].resolve({id: id, values: self.historyData[id]});
});
};
/**
*
* @type {exports}
*/
RemsTelemetryServerAdapter.prototype.dictionary = MSLDataDictionary;
/**
*
* @param id
* @returns {p.promise|{then, fail, end}|performPromise|deferred.promise|{}|*}
* Requests historical telemetry for the named data attribute. In
* the case of REMS, this data source exposes multiple different
* data variables from the REMS instrument, including temperature
* and others
* @param id The telemetry data point key to be queried.
* @returns {Promise | Array<RemsTelemetryValue>} that resolves with an Array of {@link RemsTelemetryValue} objects for the request data key.
*/
RemsTelemetryServerAdapter.prototype.history = function(id) {
this.deferreds[id] = this.deferreds[id] || this.$q.defer();
if (this.histories[id]) {
this.deferreds[id].resolve({id: id, values: this.histories[id]});
if (this.historyData[id]) {
this.deferreds[id].resolve({id: id, values: this.historyData[id]});
} else {
this.histories = {};
this.historyData = {};
this.requestHistory(id);
}
return this.deferreds[id].promise;