/* * cylon * cylonjs.com * * Copyright (c) 2013 The Hybrid Group * Licensed under the Apache 2.0 license. */ "use strict"; var Async = require("async"); var Logger = require("./logger"), Robot = require("./robot"), Config = require("./config"), Utils = require("./utils"), _ = require("./lodash"); var EventEmitter = require("events").EventEmitter; var Cylon = module.exports = new EventEmitter(); Cylon.Logger = Logger; Cylon.Driver = require("./driver"); Cylon.Adaptor = require("./adaptor"); Cylon.Utils = Utils; Cylon.IO = { DigitalPin: require("./io/digital-pin"), Utils: require("./io/utils") }; Cylon.api_instance = null; Cylon.robots = {}; Cylon.commands = {}; Cylon.events = [ "robot_added", "robot_removed" ]; // Public: Creates a new Robot // // opts - hash of Robot attributes // // Returns a shiny new Robot // Examples: // Cylon.robot // connection: { name: "arduino", adaptor: "firmata" } // device: { name: "led", driver: "led", pin: 13 } // // work: (me) -> // me.led.toggle() Cylon.robot = function robot(opts) { opts = opts || {}; // check if a robot with the same name exists already if (opts.name && this.robots[opts.name]) { var original = opts.name; opts.name = Utils.makeUnique(original, Object.keys(this.robots)); var str = "Robot names must be unique. Renaming '"; str += original + "' to '" + opts.name + "'"; Logger.warn(str); } var bot = new Robot(opts); this.robots[bot.name] = bot; this.emit("robot_added", bot.name); return bot; }; // Public: Creates a new API based on passed options // // Returns nothing Cylon.api = function api(opts) { if (typeof opts === "object") { this.config({ api: opts }); } var API = require("./api"); var config = Utils.fetch(Config, "api", {}); this.api_instance = new API(config); this.api_instance.listen(); }; // Public: Starts up the API and the robots // // Returns nothing Cylon.start = function start() { var starters = _.map(this.robots, "start"); Async.parallel(starters, function() { var mode = Utils.fetch(Config, "workMode", "async"); if (mode === "sync") { _.invoke(this.robots, "startWork"); } }.bind(this)); }; // Public: Sets the internal configuration, based on passed options // // opts - object containing configuration key/value pairs // // Returns the current config Cylon.config = function(opts) { var logChanges = (opts.logging && !_.isEqual(Config.logging, opts.logging)); if (_.isObject(opts) && !_.isArray(opts)) { Config = _.merge(Config, opts); } if (logChanges) { Logger.setup(); } return Config; }; // Public: Halts the API and the robots // // callback - callback to be triggered when Cylon is ready to shutdown // // Returns nothing Cylon.halt = function halt(callback) { callback = callback || function() {}; var fns = _.map(this.robots, "halt"); // if robots can"t shut down quickly enough, forcefully self-terminate var timeout = Config.haltTimeout || 3000; Utils.after(timeout, callback); Async.parallel(fns, callback); }; Cylon.toJSON = function() { return { robots: _.invoke(this.robots, "toJSON"), commands: _.keys(this.commands), events: this.events }; }; if (process.platform === "win32") { var readline = require("readline"), io = { input: process.stdin, output: process.stdout }; readline.createInterface(io).on("SIGINT", function() { process.emit("SIGINT"); }); } process.on("SIGINT", function() { Cylon.halt(function() { process.kill(process.pid); }); });