teco-kit/p4a-sensorAPI

View on GitHub
SensorAPI.js

Summary

Maintainability
F
2 wks
Test Coverage
/*
Copyright 2015 KIT Anton Truong - truong@teco.edu

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/


// The main scanner object
var SensorAPI = (function(driver,options){
    //To be returned scanner object
    var SensorAPI = {};

    //Make SensorAPI variable a DOM variable
    var eventTrigger = document.createElement("object");
    //SensorAPI = document.createElement("object");

    //Holds internal functions
    var internal = {};

    // Registered scanner
    internal.scanners = [];

    // Setting sensor filter, when looking for specific sensors
    internal.filter = [];

    // Storing the driver objects
    SensorAPI.drivers = {};

    // Stores drivers internally
    internal.drivers = [];



    //Storage for the devices
    SensorAPI.devices = {};

    //Storage for all ever detected devices
    SensorAPI.deviceHistory = {};

    //Internal timeout watcher for each device
    internal.timeouts = [];

    //Setze globalen Filter
    if(options && options.filterBySensorTypes) {
        internal.filter = options.filterBySensorTypes ? options.filterBySensorTypes : "";
    } else {
        internal.filter = false;
    }

    // events
    internal.events = {
        deviceAdded: "deviceAdded",
        deviceRemoved: "deviceRemoved"
      };

    //Setzte TTL für sensoren
    if(options && options.setTTL) {
        internal.TTL = options.setTTL ? options.setTTL : 0;
    } else {
        internal.TTL = 0;
    }

    /* Register function for scanner.
     Params
     scanners array(), expect objects
     fail     callback in case of fail
     */

    internal.register = function(drivers) {
        for(var scan = 0;scan< drivers.length; scan++) {
            //Check before pushing if the scanner object has a startScan function
            if(drivers[scan]) {
                internal.scanners.push({"driver": drivers[scan].driver, "args":drivers[scan].args});
            }
        }
    }

    /*
    General fail function
    */

    internal.failFunction = function(e) {
        console.log("Failure: " +JSON.stringify(e));
    }


    /*
     Expecting sensors as an object. Each element in the object must represent a sensor. So that one can sort out the sensors according to the
     given flter. internal.filter
     */
     internal.storeDevice = function(device, driver) {
       // Check if the device meets the device interface requirements
       internal.checkMandatoryInterface(device, [
         {name: "ID", type: "string"},
         {name: "description", type: "string", replace:"No description"},
         {name: "sensors", type:"object", replace:null}
       ]);

       // Add the driver information
       device.driver = driver;
             //Check if the sensors is already in internal.devices
             if(device.ID != undefined) {

          if(SensorAPI.getFilter().length > 0 && internal.filterBySensorType(device.sensors)) {
                // Überprüfe ob der Sensor bereits bekannt ist und im SensorAPI.devices vorhanden ist.
              //console.log(device.ID);
              if(!SensorAPI.devices[device.ID]) {
                  //Speicher welcher treiber verwendet wird
                  SensorAPI.devices[device.ID] = device
                  //Speicher in jemals gefundenen array
                  SensorAPI.deviceHistory[device.ID] = device;
              }
                var event = new CustomEvent(internal.events.deviceAdded, {detail:device},false,false);
                eventTrigger.dispatchEvent(event);
            } else if(!SensorAPI.getFilter() || SensorAPI.getFilter().length == 0) {
              var event = new CustomEvent(internal.events.deviceAdded, {detail:device},false,false);
              eventTrigger.dispatchEvent(event);
            }

        } else {
          console.log("Device is not supported and will be therefore not stored/tracked. Result of getDevices wont contain this device." + device.name);
        }
         }




     // Callback Function when the interface of the driver is offering an onDeviceRemoved
     internal.removeDevice = function(device) {
       if(SensorAPI.devices[device.ID]) {
         delete SensorAPI.devices[device.ID];
       }
       var event = new CustomEvent(internal.events.deviceRemoved, {detail:device},false,false);
       //SensorAPI.dispatchEvent(event);
       eventTrigger.dispatchEvent(event);
     }



     SensorAPI.onDeviceAdded = function(callback) {
       var stdCallback = function(device) {
         console.log("Device : " + device.name + " (address: " + device.address  +") added.");
       }

       // Schaue ob ein callback übergeben wurde
       // sonst nutze den oben deklarierten Standardcallback
       callback = callback ? callback : stdCallback;
       //SensorAPI.addEventListener(SensorAPI.events.deviceAdded, function(obj) {
       eventTrigger.addEventListener(internal.events.deviceAdded, function(obj) {
         callback(obj.detail);
       });
     }


     SensorAPI.onDeviceRemoved = function(callback) {
       var stdCallback = function(device) {
         console.log("Device : " + device.name + " (address: " + device.address  +") removed.");
       }
       // Schaue ob ein callback übergeben wurde
       // sonst nutze den oben deklarierten Standardcallback
       callback = callback ? callback : stdCallback;

       //SensorAPI.addEventListener(SensorAPI.events.deviceAdded, function(obj) {
       eventTrigger.addEventListener(internal.events.deviceAdded, function(obj) {
         callback(obj.detail);
       });
     }


    //Internal filter function
    //accepts only the string which is to be searched in
    internal.filterBySensorType = function(services) {
        var found = false;
        if(internal.filter && services != null) {
            for (filter in internal.filter) {
              //console.log(internal.filter[filter] + JSON.stringify(services));
              if(JSON.stringify(services).indexOf(internal.filter[filter]) > -1) {
                found = true;
                break;
              }
            }
        }
        if(!internal.filter) {
            found = true;
        }
        return found;
    }



    /*
        Set filter
    */
    SensorAPI.setFilter = function(filter) {
        //check if filter has the conform format
        // Must be an array
        var filterSet = false;
        if(filter) {
            internal.filter = filter;
            filterSet = true;
        } else {
            console.log("error: Filter criteria must be in an array");
        }
        return filterSet;
    }

    SensorAPI.getFilter = function() {
        return internal.filter;
    }

  // Driver Exception
  function driverException(message) {
    this.message = message;
    this.name = "Driver Exception.";
  }

  // Checking functions for driver interface
  internal.checkMandatoryInterface = function(loadedDriver, interfaceArray) {
    interfaceArray.forEach(function(element) {
      if(!(loadedDriver[element.name] && typeof loadedDriver[element.name] == element.type)) {
        if(element.replace) {
          loadedDriver[element.name] = element.replace;
        } else {
          throw new driverException("MandantoryInterfaceNotAvailable"+element.name);
        }
      }
    });
  }

  internal.checkOptionalInterface = function(loadedDriver, interfaceArray) {
    interfaceArray.forEach(function(element) {
      if(!(loadedDriver[element] && typeof loadedDriver[element] === "function")) {
        loadedDriver[element] = function(){};
      }
    });
  }


  SensorAPI.loadDriver = function(driver, options) {


    if(!SensorAPI.drivers[driver]) {


      var xhr= new XMLHttpRequest();
      xhr.open('GET', driver, true);
      xhr.onreadystatechange= function() {
          if (this.readyState!==4) return;
          if (this.status!==200) return; // or whatever error handling you want

          var loadedDriver = eval(this.responseText);

          // Check if driver has the mandantory functionsn parameter
          // ID, onDeviceAdded, onDeviceRemoved, Description
          try {
            internal.checkMandatoryInterface(
              loadedDriver,
              [{name:"ID", type:"string", replace: driver},
              {name: "onDeviceAdded", type: "function"},
              {name: "onDeviceRemoved", type: "function"}
            ]);
          } catch(e) {
            console.log(e.message);
          }

          //Check for optional properties, functions
          // initialize, finalize
          internal.checkOptionalInterface(loadedDriver, ["finalize", "initialize"] );

          SensorAPI.drivers[driver] = loadedDriver;
          SensorAPI.drivers[driver].onDeviceAdded(function(dev) {internal.storeDevice(dev,driver);}, options);
          SensorAPI.drivers[driver].initialize();
          SensorAPI.drivers[driver].onDeviceRemoved(function(dev) {internal.removeDevice(dev);});
      };
      xhr.send();
    }
  }

  SensorAPI.unloadDriver = function(driver) {
    if(SensorAPI.drivers[driver]) {
      SensorAPI.drivers[driver].finalize();
      SensorAPI.drivers[driver] = null;
      return true;
    } else {
      console.log("No such driver available to be removed: " + driver);
      return false;
    }
  }



    return SensorAPI;
});