Source: Sensor.js


var EvenEmitter = require('events').EventEmitter;
var util = require('util');
var SensorManager = require('./Sensors.js').SensorManager; 

/**
 * Generic sensor class
 * @constructor
 */
var Sensor = function (initOption) {
    if (this.constructor === Sensor) {
        throw new Error("Can't instantiate abstract class!");
    }
    /**
     * @description Holds basic sensor information
     * @private
     * @memberof Sensor
     * @member {Object} info
     * @property {String} type - Sensor type
     * @property {String} vendor - Vendor name
     * @property {String} version - Sensor version
     * @property {Number} freq - Sensor frequency (Hz)
     * @property {Number} threshold - Threshold value
     * @property {String} state - Sensor state
     */
    this.info = {
        type: 'N/A', 
        vendor: 'N/A',
        version: 'N/A',
        freq: -1, //Hz
        threshold: -1, // Threshold is disable as default
        state: 'idle'
    };
    /**
     * @description Sensor data buffer
     * @private
     * @memberof Sensor
     * @var {Array} buffer - Sensor data buffer  
     */
    this.buffer = new Array();
    /**
     * @var {Number} bufferSize - The size of buffer data 
     * @private
     * @memberof Sensor 
     */
    this.bufferSize = 512; // default buffer size
    /**
     * @var {Number} intervalRead - An id return by setInterval() function 
     * @private
     * @memberof Sensor 
     */
    this.intervalRead = 0;
}

/**
 * @extends EventEmitter
 */
util.inherits(Sensor, EvenEmitter);

/**
 * Start the sensor's operation
 * @param {Object} self - Sensor object
 */   
Sensor.prototype.start = function (self) {
    this.info.state = 'active';
    if (this.info.freq !== -1) {
        this.intervalRead = setInterval(function () {
            self.readData();
        }, 1000 / this.info.freq);
    }
};
    
/**
 * Stop the sensor's operation
 */ 
Sensor.prototype.stop = function () {
    this.info.state = 'idle';
    clearInterval(this.intervalRead);
};
    
/**
 * Reset data buffer
 */
Sensor.prototype.resetBuffer = function () {
    while (this.buffer.length > 0) {
        this.buffer.pop();
    }
};

/*------------------ GETTER/SETTER FUNCTIONS -------------------------*/

/**
 * Set sensor frequency
 * @param {Number} freq - Frequency value
 */   
Sensor.prototype.setFreq = function (freq) {
    //TODO: Check if freq is a number
    this.info.freq = freq;
    if (this.info.hasOwnProperty('minFreq')) {
        // if maxFreq is defined
        if (freq < this.info.minFreq) {
            console.log(this.info.type + "-Warning: set freq=minFreq(" + this.info.minFreq + ")");
            this.info.freq = this.info.minFreq;
        }
    }
    if (this.info.hasOwnProperty('maxFreq')) {
        if (freq > this.info.maxFreq) {
            console.log(this.info.type + "-Warning: set freq=maxFreq(" + this.info.maxFreq + ")");
            this.info.freq = this.info.maxFreq;
        }
    }
    //restart
    this.stop();
    this.start(this);
};

/**
 * Retrieve sensor frequency
 * @return {Number} Frequency of the sensor
 */ 
Sensor.prototype.getFreq = function () {
    return this.info.freq;
}

/**
 * Retrieve sensor type
 * @return {String} The sensor type
 */ 
Sensor.prototype.getType = function () {
    return this.info.type;
}

/**
 * Set sensor threshold
 * @param {int} freq - Threshold value
 */    
Sensor.prototype.setThreshold = function (threshold) {
    //TODO: check if threshold is a number
    if (threshold >= 0) {
        this.info.threshold = threshold;
    } else {
        console.log("Cannot set threshold value which is less than 0");
    }   
};

/**
 * Disable the functionality of using threshold
 */
Sensor.prototype.disableThreshold = function () {
    // reset threshold value to -1
    this.info.threshold = -1;
}

/**
 * Retrieve sensor threshold
 * @return {Number} - Threshold value
 */
Sensor.prototype.getThreshold = function () {
    return this.info.threshold;
};

/**
 * Set sensor state
 * @param {String} state - State value
 */ 
Sensor.prototype.setState = function (state) {
    if (state === 'idle' || state === 'active' || state === 'errored') {
        this.info.state = state;
    }
}

/**
 * Retrieve sensor state
 * @return {Number} - Sensor state
 */
Sensor.prototype.getState = function () {
    return this.info.state;
}

/**
 * Set buffer size
 * @param {Number} size - Buffer size
 */
Sensor.prototype.setBufferSize = function (size) {
    //TODO: Check if size is a number
    if (size > 0) {
        this.bufferSize = size;
    } else { // Ignore the setting if size <= 0, print the notification
        console.log("Cannot set buffer's size less than or equal to 0");
    }
}

/**
 * Retrieve buffer size
 * @return {Number} Buffer size
 */
Sensor.prototype.getBufferSize = function () {
    return this.bufferSize;
}
    
/**
 * Read data from the sensor
 * @abstract
 */    
Sensor.prototype.readData = function () {};
    
/**
 * Read data from the data buffer
 * @param {Number} numOfData - Number of data
 * @return {Array} - Array of returned data
 */    
Sensor.prototype.readDataBuffer = function (numOfData) {
    //TODO: it should return recent data rather than data from the O position
    return this.buffer.slice(0, numOfData - 1);
};
    
/**
 * Print sensor's basic information (type + vendor + version)
 */   
Sensor.prototype.toString = function () {
    console.log(this.info.type + ' || ' 
    + 'Vendor: ' + this.info.vendor + ' || ' 
    + 'Version: ' + this.info.version);
};

/**
 * Check sensor's validity. If this sensor is valid, register to use it
 * @param {Object} initOption - sensor's initialized information
 * @return {String} Sensor ID
 * @throw Error when:
 *          + type of sensor is undefined, or
 *          + sensor is using, or 
 *          + sensor is unsupported
 * @fires TemperatureSensor#onerror
 */   
Sensor.prototype.isValid = function (initOption) {
    try {
        var sensorId;
        var validCode;
        // check if it is possible to instantiate this sensor
        if (initOption.type) {
            if (initOption.id) {
                sensorId = initOption.id;
                validCode = SensorManager.isValid(initOption.type, initOption.id);
            } else {
                ids = SensorManager.getIds(initOption.type);
                if (ids === null) {
                    validCode = SensorManager.isValid(initOption.type);
                } else {
                    // check if there is any available id for this type of sensor
                    for (count = 0; count < ids.length; count++) {
                        if (!SensorManager.isUsing("temperature_ds18b20", ids[count])) {
                            sensorId = ids[count];
                            console.log("ID of this " + initOption.type + " sensor is missing. Assign it to id = " + sensorId);
                            this.info.id = sensorId;
                            break;
                        }
                    }
                    if (sensorId === undefined) {
                        throw new Error("All " + type + " sensor(s) are using. Initialization is fail");
                    }
                    validCode = SensorManager.isValid(initOption.type, sensorId);
                }
            }
        } else {
            throwError(9, initOption.type);
        }
        if (validCode === 1) {
            if (sensorId) {
                var  assignCode = SensorManager.assignSensor(initOption.type, sensorId);
            } else {
                var assignCode = SensorManager.assignSensor(initOption.type);
            }
            if (assignCode === 1) {
                for (var property in initOption) {
                    if (initOption.hasOwnProperty(property)) {
                        this.info[property] = initOption[property];
                    }
                }
                this.setState('active');
            } else {
                throwError(assignCode, initOption.type, sensorId);
            }
        } else {
            throwError(validCode, initOption.type, sensorId);
        }
        return sensorId;
    } catch (err) {
        console.log(err);
        console.log(err.stack);
        this.setState('errored');
        this.emit('onerror', err);
    } 
}

var throwError = function (errorCode, type, id) {
    switch (errorCode) {
        case 2:
            throw new Error("The " + type + " sensor is using");
        case 3:
            throw new Error("The " + type + " sensor is unused");
        case 4:
            throw new Error("The " + type + "sensor with id = " + id + " is using");
        case 5:
            throw new Error("The " + type + "sensor with id = " + id + " is unused");
        case 6:
            throw new Error("There are multiple " + type + " sensor. An id is needed");
        case 7:
            throw new Error("The " + type + " sensor is unsupported");
        case 8:
            throw new Error("The " + type + " sensor with id = " + id + " is unsupported");
        case 9:
            throw new Error("The " + type + " sensor is undefined");
        default:
            throw new Error("Error code: " + errorCode + " is undefined");
    }
}
/**
* @exports Sensor
*/
module.exports.Sensor = Sensor;