Merge branch 'master' into literate-coffeescript

* master: (21 commits)
  Removes unnecessary IO class.
  Fixes raspi button example typo.
  Updated DigitalPin and raspi_button example.
  Adding interval reads to digitalRead.
  Added new Digital read example for raspi, updated digitalRead in lib.
  Refactored DigitalRead and setup mode to only emit connection event on connect.
  Added new DigitalPin to Cylon core to use in adaptors, for real.
  Added new DigitalPin to Cylon core to use in adaptors.
  Added new example for raspi adaptor.
  Updated digital pin lib and example.
  Fixed missing mode variable in digital pin.
  Remove logging and update example.
  Change events and update example in digital pin.
  Added close for GPIO and updated negative ifs
  Change event triggers in callbacks to fat arrows to keep obj scope.
  Removed self and changed example.
  Updated IO and digital pin to use events.
  Fix bug in GPIO example.
  Adde pure GPIO example and updated digital pin lib
  Added new LinuxIO DigitalPin library.
  ...
This commit is contained in:
Andrew Stewart 2013-11-06 15:14:30 -08:00
commit 7543f834e4
11 changed files with 416 additions and 1 deletions

28
dist/cylon.js vendored
View File

@ -9,7 +9,7 @@
(function() {
'use strict';
var Cylon, Robot,
var Cylon, Robot, readLine,
__slice = [].slice,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
@ -21,6 +21,8 @@
require('./api');
readLine = require("readline");
Logger.setup();
Cylon = (function() {
@ -49,7 +51,21 @@
function Master() {
this.robot = __bind(this.robot, this);
var rl;
this.self = this;
if (process.platform === "win32") {
rl = readLine.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on("SIGINT", function() {
return process.emit("SIGINT");
});
}
process.on("SIGINT", function() {
Cylon.getInstance().stop();
return process.exit();
});
}
Master.prototype.robot = function(opts) {
@ -140,6 +156,16 @@
return _results;
};
Master.prototype.stop = function() {
var robot, _i, _len, _results;
_results = [];
for (_i = 0, _len = robots.length; _i < _len; _i++) {
robot = robots[_i];
_results.push(robot.stop());
}
return _results;
};
Master.prototype.startAPI = function() {
return api != null ? api : api = new Api.Server({
master: this.self

6
dist/device.js vendored
View File

@ -28,6 +28,7 @@
if (opts == null) {
opts = {};
}
this.stop = __bind(this.stop, this);
this.start = __bind(this.start, this);
this.self = this;
this.robot = opts.robot;
@ -48,6 +49,11 @@
return this.driver.start(callback);
};
Device.prototype.stop = function() {
Logger.info("Stopping device '" + this.name + "'");
return this.driver.stop();
};
Device.prototype.data = function() {
return {
name: this.name,

162
dist/digital-pin.js vendored Normal file
View File

@ -0,0 +1,162 @@
/*
* Linux IO DigitalPin
* cylonjs.com
*
* Copyright (c) 2013 The Hybrid Group
* Licensed under the Apache 2.0 license.
*/
(function() {
'use strict';
var EventEmitter, FS, namespace,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
FS = require('fs');
EventEmitter = require('events').EventEmitter;
namespace = require('node-namespace');
namespace('Cylon.IO', function() {
return this.DigitalPin = (function(_super) {
var GPIO_DIRECTION_READ, GPIO_DIRECTION_WRITE, GPIO_PATH, HIGH, LOW;
__extends(DigitalPin, _super);
GPIO_PATH = "/sys/class/gpio";
GPIO_DIRECTION_READ = "in";
GPIO_DIRECTION_WRITE = "out";
HIGH = 1;
LOW = 0;
function DigitalPin(opts) {
this.self = this;
this.pinNum = opts.pin;
this.status = 'low';
this.ready = false;
this.mode = opts.mode;
}
DigitalPin.prototype.connect = function(mode) {
var _this = this;
if (mode == null) {
mode = null;
}
if (this.mode == null) {
this.mode = mode;
}
return FS.writeFile("" + GPIO_PATH + "/export", "" + this.pinNum, function(err) {
if (err) {
return _this.self.emit('error', 'Error while creating pin files');
} else {
_this.self._setMode(_this.mode, true);
return _this.self.emit('open');
}
});
};
DigitalPin.prototype.close = function() {
var _this = this;
return FS.writeFile("" + GPIO_PATH + "/unexport", "" + this.pinNum, function(err) {
if (err) {
return _this.self.emit('error', 'Error while closing pin files');
} else {
return _this.self.emit('close');
}
});
};
DigitalPin.prototype.digitalWrite = function(value) {
var _this = this;
if (this.mode !== 'w') {
this.self._setMode('w');
}
this.status = value === 1 ? 'high' : 'low';
return FS.writeFile(this.pinFile, value, function(err) {
if (err) {
return _this.self.emit('error', "Error occurred while writing value " + value + " to pin " + _this.pinNum);
} else {
return _this.self.emit('digitalWrite', value);
}
});
};
DigitalPin.prototype.digitalRead = function(interval) {
var readData,
_this = this;
if (this.mode !== 'r') {
this.self._setMode('r');
}
readData = null;
return setInterval(function() {
return FS.readFile(_this.pinFile, function(err, data) {
if (err) {
return _this.self.emit('error', "Error occurred while reading from pin " + _this.pinNum);
} else {
readData = data;
return _this.self.emit('digitalRead', data);
}
});
}, interval);
};
DigitalPin.prototype._setMode = function(mode, emitConnect) {
var _this = this;
if (emitConnect == null) {
emitConnect = false;
}
if (mode === 'w') {
return FS.writeFile("" + GPIO_PATH + "/gpio" + this.pinNum + "/direction", GPIO_DIRECTION_WRITE, function(err) {
if (err) {
return _this.self.emit('error', "Setting up pin direction failed");
} else {
_this.pinFile = "" + GPIO_PATH + "/gpio" + _this.pinNum + "/value";
_this.ready = true;
if (emitConnect) {
return _this.self.emit('connect', mode);
}
}
});
} else if (mode === 'r') {
return FS.writeFile("" + GPIO_PATH + "/gpio" + this.pinNum + "/direction", GPIO_DIRECTION_READ, function(err) {
if (err) {
return _this.self.emit('error', "Setting up pin direction failed");
} else {
_this.pinFile = "" + GPIO_PATH + "/gpio" + _this.pinNum + "/value";
_this.ready = true;
if (emitConnect) {
return _this.self.emit('connect', mode);
}
}
});
}
};
DigitalPin.prototype.setHigh = function() {
return this.self.digitalWrite(1);
};
DigitalPin.prototype.setLow = function() {
return this.self.digitalWrite(0);
};
DigitalPin.prototype.toggle = function() {
if (this.status === 'low') {
return this.self.setHigh();
} else {
return this.self.setLow();
}
};
return DigitalPin;
})(EventEmitter);
});
}).call(this);

19
dist/robot.js vendored
View File

@ -17,6 +17,8 @@
require('./basestar');
require('./digital-pin');
namespace = require('node-namespace');
Connection = require("./connection");
@ -37,6 +39,7 @@
opts = {};
}
this.registerDriver = __bind(this.registerDriver, this);
this.stop = __bind(this.stop, this);
this.startDevices = __bind(this.startDevices, this);
this.startConnections = __bind(this.startConnections, this);
this.start = __bind(this.start, this);
@ -163,6 +166,22 @@
return Async.parallel(starters, callback);
};
Robot.prototype.stop = function() {
var connection, device, n, _ref, _ref1, _results;
_ref = this.devices;
for (n in _ref) {
device = _ref[n];
device.stop();
}
_ref1 = this.connections;
_results = [];
for (n in _ref1) {
connection = _ref1[n];
_results.push(connection.disconnect());
}
return _results;
};
Robot.prototype.requireAdaptor = function(adaptorName, connection) {
if (this.robot.adaptors[adaptorName] != null) {
if (typeof this.robot.adaptors[adaptorName] === 'string') {

18
examples/pure_gpio.coffee Normal file
View File

@ -0,0 +1,18 @@
require('../dist/digital-pin')
pin4 = new Cylon.IO.DigitalPin(pin: 4, mode: 'w')
pin4.on('open', (data) ->
console.log("Pin files have been created")
)
pin4.on('digitalWrite', (value) ->
console.log("Value writen to pin -> #{ value }")
)
pin4.on('connect', (data) ->
console.log("Pin mode has been setup!")
pin4.setHigh()
)
pin4.connect()

View File

@ -0,0 +1,15 @@
Cylon = require('..')
# Initialize the robot
Cylon.robot
connection:
name: 'raspi', adaptor: 'raspi'
device:
name: 'led', driver: 'led', pin: 11
work: (my) ->
# we do our thing here
every 1.second(), -> my.led.toggle()
.start()

View File

@ -0,0 +1,17 @@
Cylon = require('..')
# Initialize the robot
Cylon.robot
connection:
name: 'raspi', adaptor: 'raspi'
devices:
[
{name: 'led', driver: 'led', pin: 11},
{name: 'button', driver: 'button', pin: 7}
]
work: (my) ->
my.button.on 'push', () -> my.led.toggle()
.start()

View File

@ -14,6 +14,8 @@ require('./utils')
require('./logger')
require('./api')
readLine = require "readline"
Logger.setup()
# Cylon is the global namespace for the project, and also in charge of
@ -39,6 +41,17 @@ class Cylon
# Returns a Master instance
constructor: ->
@self = this
if process.platform is "win32"
rl = readLine.createInterface
input: process.stdin
output: process.stdout
rl.on "SIGINT", ->
process.emit "SIGINT"
process.on "SIGINT", ->
Cylon.getInstance().stop()
process.exit()
# Public: Creates a new Robot
#
@ -119,6 +132,15 @@ class Cylon
do @startAPI
robot.start() for robot in robots
# Public: Stops the API and the robots
#
# Returns nothing
stop: ->
#do @stopAPI
robot.stop() for robot in robots
# Creates a new instance of the Cylon API server, or returns the
# already-existing one.
#

View File

@ -48,6 +48,13 @@ namespace 'Cylon', ->
Logger.info msg
@driver.start(callback)
# Public: Stops the device driver
#
# Returns result of supplied callback
stop: =>
Logger.info "Stopping device '#{ @name }'"
@driver.stop()
# Public: Exports basic data for the Connection
#
# Returns an Object containing Connection data

110
src/digital-pin.coffee Normal file
View File

@ -0,0 +1,110 @@
###
* Linux IO DigitalPin
* cylonjs.com
*
* Copyright (c) 2013 The Hybrid Group
* Licensed under the Apache 2.0 license.
###
'use strict';
FS = require('fs')
EventEmitter = require('events').EventEmitter
namespace = require 'node-namespace'
# DigitalPin class to interface with linux GPIO in raspi and beaglebone
#
namespace 'Cylon.IO', ->
class @DigitalPin extends EventEmitter
GPIO_PATH = "/sys/class/gpio"
GPIO_DIRECTION_READ = "in"
GPIO_DIRECTION_WRITE = "out"
HIGH = 1
LOW = 0
constructor: (opts) ->
@self = this
@pinNum = opts.pin
@status = 'low'
@ready = false
@mode = opts.mode
connect: (mode = null) ->
@mode ?= mode
# Creates the GPIO file to read/write from
FS.writeFile("#{ GPIO_PATH }/export", "#{ @pinNum }", (err) =>
if(err)
@self.emit('error', 'Error while creating pin files')
else
@self._setMode(@mode, true)
@self.emit('open')
)
close: ->
FS.writeFile("#{ GPIO_PATH }/unexport", "#{ @pinNum }", (err) =>
if(err)
@self.emit('error', 'Error while closing pin files')
else
@self.emit('close')
)
digitalWrite: (value) ->
@self._setMode('w') unless @mode == 'w'
@status = if (value == 1) then 'high' else 'low'
FS.writeFile(@pinFile, value, (err) =>
if (err)
@self.emit('error', "Error occurred while writing value #{ value } to pin #{ @pinNum }")
else
@self.emit('digitalWrite', value)
)
digitalRead: (interval) ->
@self._setMode('r') unless @mode == 'r'
readData = null
setInterval(() =>
FS.readFile(@pinFile, (err, data) =>
if err
@self.emit('error', "Error occurred while reading from pin #{ @pinNum }")
else
readData = data
@self.emit('digitalRead', data)
)
, interval)
# Sets the mode for the GPIO pin by writing the correct values to the pin reference files
_setMode: (mode, emitConnect = false) ->
if mode == 'w'
FS.writeFile("#{ GPIO_PATH }/gpio#{ @pinNum }/direction", GPIO_DIRECTION_WRITE, (err) =>
if (err)
@self.emit('error', "Setting up pin direction failed")
else
@pinFile = "#{ GPIO_PATH }/gpio#{ @pinNum }/value"
@ready = true
@self.emit('connect', mode) if emitConnect
)
else if mode =='r'
FS.writeFile("#{ GPIO_PATH }/gpio#{ @pinNum }/direction", GPIO_DIRECTION_READ, (err) =>
if (err)
@self.emit('error', "Setting up pin direction failed")
else
@pinFile = "#{ GPIO_PATH }/gpio#{ @pinNum }/value"
@ready = true
@self.emit('connect', mode) if emitConnect
)
setHigh: ->
@self.digitalWrite(1)
setLow: ->
@self.digitalWrite(0)
toggle: ->
if @status == 'low'
@self.setHigh()
else
@self.setLow()

View File

@ -10,6 +10,7 @@
require './cylon'
require './basestar'
require './digital-pin'
namespace = require 'node-namespace'
@ -149,6 +150,18 @@ namespace 'Cylon', ->
Async.parallel starters, callback
# Public: Stops the Robot working.
#
# Stops the devices, disconnects the connections.
#
# Returns nothing
stop: =>
for n, device of @devices
device.stop()
for n, connection of @connections
connection.disconnect()
# Public: Requires a hardware adaptor and adds it to @robot.adaptors
#
# adaptorName - module name of adaptor to require