Source: views/StatusView.js

/**
 * @author Serge Babayan
 * @module views/StatusView
 * @requires StatusManager
 * @requires models/TelemetryData
 * @requires util/Template
 * @requires util/Logger
 * @requires util/Validator
 * @requires electron
 * @requires moment
 * @listens models/TelemetryData~TelemetryData:data_received
 * @listens models/StatusManager~StatusManager:new_status
 * @listens models/StatusManager~StatusManager:remote_status
 * @copyright Waterloo Aerial Robotics Group 2016
 * @licence https://raw.githubusercontent.com/UWARG/WARG-Ground-Station/master/LICENSE
 * @description View for the status bar that listens in on events from StatusManager and TelemetryData
 */

var remote = require('electron').remote;
var TelemetryData = remote.require('./app/models/TelemetryData');
var StatusManager = remote.require('./app/StatusManager');
var Logger = remote.require('./app/util/Logger');
var Validator = require('../util/Validator');
var Template = require('../util/Template');

var moment = require('moment');

module.exports = function (Marionette, $) {

  return Marionette.ItemView.extend({
    template: Template('StatusView'), //name of the file in the views folder at the project root
    className: 'statusView',

    ui: {
      statuses: ".statuses",
      vehicle_time: ".time-view .vehicle-time",
      elapsed_time: ".time-view .elapsed-time",
      battery_percent: ".battery-percentage",
      battery_message: ".battery-message",
      battery_picture: ".battery-picture .battery-base .percentage",
      gps_message: ".gps-status .gps-message",
      transmission_speed: '.transition-rate',
      rssi: '.rssi'
    },
    events: {
      'click #reset-elapsed-time': 'resetElapsedTime',
      'click #clear-statuses-button': 'clearStatuses'
    },

    initialize: function () {
      this.starting_time = null;
      this.current_battery_level = -1;
      this.current_gps_status = null;
      this.messagesReceived = 0;//for keeping track of the transmission rate
      this.transmissionInterval = null;

      this.data_callback = null; //so that we can get rid of the listener safely
      this.new_status_callback = null;
      this.remove_status_callback = null;

      this.status_messages = [];
    },
    onRender: function () {
      this.data_callback = this.onDataCallback.bind(this);
      TelemetryData.addListener('data_received', this.data_callback);

      this.new_status_callback = this.onNewStatusCallback.bind(this);
      StatusManager.addListener('new_status', this.new_status_callback);

      this.remove_status_callback = this.onRemoveStatusCallback.bind(this);
      StatusManager.addListener('remove_status', this.remove_status_callback);

      this.transmissionInterval = setInterval(function () {
        this.ui.transmission_speed.text(this.messagesReceived + '/s');
        this.messagesReceived = 0;
      }.bind(this), 1000);
    },
    onBeforeDestroy: function () {
      TelemetryData.removeListener('data_received', this.data_callback);
      StatusManager.removeListener('new_status', this.new_status_callback);
      StatusManager.removeListener('remove_status', this.remove_status_callback);
      clearInterval(this.transmissionInterval);
    },
    onDataCallback: function (data) {
      if (!this.starting_time && Validator.isValidTime(data.time)) {
        time = Number(data.time).toFixed(2);
        this.starting_time = moment(time, 'HHmmss.SS');
      }
      this.setTime(data.time);
      this.setBatteryLevel(data.battery_level1);
      this.setGpsLevel(data.gps_status);
      this.ui.rssi.text(data.RSSI);
      this.messagesReceived++;
    },
    onNewStatusCallback: function (message, priority, timeout) {
      if (priority === 0) {
        var element = $('<p class="status status-high red">' + message + '</p>');
      }
      else if (priority === 1) {
        var element = $('<p class="status status-high green">' + message + '</p>');
      }
      else if (priority === 2) {
        var element = $('<p class="status status-medium">' + message + '</p>');
      }
      else {
        var element = $('<p class="status status-low">' + message + '</p>');
      }
      this.status_messages.push({
        element: element,
        message: message,
        priority: priority,
        timeout: timeout
      });
      this.ui.statuses.append(element);
      this.ui.statuses[0].scrollTop = 0;
    },
    onRemoveStatusCallback: function (message, priority, timeout) {
      for (var i = 0; i < this.status_messages.length; i++) {
        if (this.status_messages[i].message === message && this.status_messages[i].priority === priority && this.status_messages[i].timeout === timeout) {
          this.status_messages[i].element.remove();
          this.status_messages.splice(i, 1);
          return;
        }
      }
    },
    setTime: function (time) {
      if (!Validator.isValidTime(time)) {
        Logger.warn('Got invalid value for the time! Time: ' + time);
        this.ui.vehicle_time.text('Invalid Time Received');
        this.ui.elapsed_time.text('--');
      }
      else {
        time = Number(time).toFixed(2);
        var date = moment(time, 'HHmmss.SS');
        var elapsed_time = moment(date.diff(this.starting_time));
        this.ui.vehicle_time.text(date.format('HH:mm:ss:SS'));
        this.ui.elapsed_time.text(elapsed_time.minute() + ' min ' + elapsed_time.second() + ' sec');
      }
    },
    setBatteryLevel: function (battery_level) {
      if (!Validator.isValidBattery(battery_level)) {
        Logger.warn('Got an invalid value for the battery level! Battery Level: ' + battery_level);
        this.ui.battery_percent.text('Invalid Battery Level');
      }
      else if (Number(battery_level) !== this.current_battery_level) {
        var percent = Math.round(Number(battery_level));
        this.current_battery_level = percent;
        this.ui.battery_percent.text(percent + '%');
        this.ui.battery_picture.css('width', percent + '%');
        if (percent > 50 && percent <= 100) {
          this.ui.battery_picture.css('background-color', 'green');
          this.ui.battery_message.text('');
        } else if (percent >= 20 && percent <= 50) {
          this.ui.battery_picture.css('background-color', 'orange');
          this.ui.battery_message.text('Low');
          this.ui.battery_message.css('color', 'orange');
        } else {
          this.ui.battery_picture.css('background-color', 'red');
          this.ui.battery_message.text('Very Low');
          this.ui.battery_message.css('color', 'red');
        }
      }
    },
    setGpsLevel: function (gps_level) {
      if (!Validator.isValidGpsStatus(gps_level)) {
        Logger.warn('Got an invalid value for the GPS level! GPS Level: ' + gps_level);
        this.ui.gps_message.css('color', 'orange');
        this.ui.gps_message.text('Invalid GPS Level');
      }
      else {
        var level = Number(gps_level);
        if (level !== this.current_gps_status) { //check if the gps status is different than last time
          this.current_gps_status = level;

          if (gps_level === 0) {
            Logger.warn('no GPS connection');
            this.ui.gps_message.css('color', 'red');
            this.ui.gps_message.text('NOT CONNECTED');
          }
          else {
            this.ui.gps_message.css('color', 'green');
            this.ui.gps_message.text('Connected to ' + (gps_level & 0x0f) + ' satelites');
          }
        }
      }
    },
    resetElapsedTime: function () {
      this.starting_time = null;
    },
    clearStatuses: function () { //removes all persistent statuses
      StatusManager.removeStatusesByTimeout(0);
    }

  });
};