Permalink
Browse files

getters and setters for options / more examples in README

added:
  mode()
  chipSelect()
  bitsPerWord()
  bitOrder()
    ORDER_MSB
    ORDER_LSB
  maxSpeed()
  halfDuplex()
  loopback()

Not all options work on all platforms.
  • Loading branch information...
1 parent 206e31f commit bf1f72d835a1fe846791bde5696b6117c846fe5e Anders Brownworth committed Feb 1, 2013
Showing with 203 additions and 57 deletions.
  1. +89 −28 README.md
  2. +109 −27 spi.js
  3. +3 −0 src/spi_binding.cc
  4. +2 −2 src/spi_binding.h
View
@@ -6,29 +6,31 @@ A NodeJS interface to the SPI bus typically found on embedded linux machines.
There is a native interface and a wrapped JS interface with a slightly
better API.
-*Note: The first version will be blocking. I know this is antithetical to
+*Note: The first version will be blocking. I know this is antithetical to
the node.js philosophy, but I think its important to get the code working in a
blocking manner first, and then introduce the async calls using eio.*
Basic Usage
===========
```javascript
-var spi = require("spi");
-
-var MyDevice = new spi.Spi("/dev/spidev0.1", {
- "mode": 0, // do mode first if you need something other than Mode 0
- "chipSelect": spi.NO_CS
- "maxSpeed": 1000000, // In Hz
- "size": 8, // How many bits per word
-});
-
-var out_buffer = new Buffer([ 0x23, 0x48, 0xAF, 0x19, 0x19, 0x19 ]);
-
-MyDevice.transfer(out_buffer, outbuffer.Length(),
- function(device, recv_buffer) {
- // Do something with the data in the recv buffer, if anything exists
-});
+var SPI = require('spi');
+
+var spi = new SPI.Spi('/dev/spidev0.0', {
+ 'mode': SPI.MODE['MODE_0'], // always set mode as the first option
+ 'chipSelect': SPI.CS['none'] // 'none', 'high', 'low'
+ }, function(s){s.open();});
+
+var txbuf = new Buffer([ 0x23, 0x48, 0xAF, 0x19, 0x19, 0x19 ]);
+var rxbuf = new Buffer([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]);
+
+spi.transfer(txbuf, rxbuf, function(device, buf) {
+ // rxbuf and buf should be the same here
+ var s = "";
+ for (var i=0; i < buf.length; i++)
+ s = s + buf[i] + " ";
+ console.log(s + "- " + new Date().getTime());
+ });
```
How you should **really** use the library
@@ -47,21 +49,58 @@ being sent via the SPI bus, but it uses node-spi to do it's work.
Native Api Reference
====================
-This section documents the native api which is defined in module \_spi.node.
+This section documents the native api which is defined in module _spi.node.
This is the interface that the normal Spi interface uses, but having a good
understanding of this part is important, as some people may want to use the
native interface directly.
Creating, Opening, and Closing the device
-----------------------------------------
-**\_spi.Spi constructor** - The constructor takes a single argument, the path
-to the spi dev file in /dev. We do not check that the file exists until you
-call open.
+**\_spi.Spi constructor** - The constructor only requires the path to the spi
+dev file in /dev. Options and a callback are not required but can be specified.
+
+Example:
+```javascript
+var spi = new SPI.Spi('/dev/spidev0.1');
+```
+
+Options can include:
+* **mode**: Can be one of 'MODE_0', 'MODE_1', 'MODE_2' or 'MODE_3'. It should always be the first option.
+* **chipSelect**: Can be one of 'none', 'high' or 'low'.
+* **maxSpeed**: The maximum bitrate in Hz.
+* **size**: (AKA: bits per word) Anything other than 8 is not yet supported on the Raspberry Pi.
+* **bitOrder**: true = MSB first, false = LSB first.
+* **delay**:
+* **3Wire**:
+
+Example:
+```javascript
+var spi = new SPI.Spi('/dev/spidev0.0', {'mode': SPI.MODE['MODE_0']});
+```
+
+The callback returns a handle to the newly created SPI object. It might be
+handy to .open() it if you don't need to change options.
+
+Example:
+```javascript
+var spi = new SPI.Spi('/dev/spidev0.0', {}, function(s){s.open;});
+```
**open()** - This function takes no arguments and will open the device, setting
all of the options that were previously set. Once the device is open, we do not
-allow you to change the settings to the device.
+allow you to change the settings on the device.
+
+Example:
+```javascript
+var spi = new SPI.Spi('/dev/spidev0.0', {'mode': SPI.MODE['MODE_0']});
+
+// get/set aditional options
+spi.maxSpeed(20000); // in Hz
+console.log('max speed: ' + spi.maxSpeed());
+
+spi.open(); // once opened, you can't change the options
+```
**close()** - This function should always be called before ending. Right now
the destructor for the underlying C++ class does not call close(), but that
@@ -110,21 +149,43 @@ if you'd like.
Getting and Sending Data
------------------------
+**transfer()** - This takes two buffers, a write and a read buffer. SPI
+only reads when a byte is written so communicaton is usually full duplex.
-**transfer()** - This takes two buffers, a write buffer and a read buffer.
-If you only want to do one way transfer, then pass null to that argument. For
-example, writes would look like this:
-
+Exmple:
```javascript
var buff = new Buffer([0x12, 0x12, 0x12]);
spi.transfer(buff, null);
```
-Reads would look like this:
+As a convenience feature, read and write functions pad zeros in the opposite
+direction to make simple read and writes work.
+
+**read(buffer, callback)** - Reads as much data as the given buffer is big.
+The results of the read are available in the callback.
+
+Example:
+```javascript
+var buf1 = new Buffer(8);
+spi.read(buf1, function(device, buf2) {
+ var s = "";
+ for (var i=0; i < buf.length; i++)
+ s = s + buf[i] + " ";
+ console.log(s);
+ });
+```
+
+**write(buffer, callback)** - Writes out the given buffer.
+Example:
```javascript
-var buff = new Buffer(8);
-spi.transfer(null, buff);
+var buf = new Buffer([0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0]);
+spi.write(buf, function(device, buf2) {
+ var s = "";
+ for (var i=0; i < buf.length; i++)
+ s = s + buf[i] + " ";
+ console.log(s);
+ });
```
Remember that these native apis are currently blocking. I will update, once I
View
@@ -32,61 +32,143 @@ var CS = {
low: _spi.CS_LOW
};
+var ORDER = {
+ msb: _spi.ORDER_MSB,
+ lsb: _spi.ORDER_LSB
+};
+
function isFunction(object) {
- return object && typeof object == 'function';
+ return object && typeof object == 'function';
}
var Spi = function(device, options, callback) {
- this._spi = new _spi._spi();
-
- if (callback == undefined) {
- callback = options;
- options = {};
- }
+ this._spi = new _spi._spi();
- options = options || {}; // Default to an empty object
+ options = options || {}; // Default to an empty object
- for(var attrname in options) {
- var value = options[attrname];
- if (attrname in this._spi) {
- // console.trace("Setting " + attrname + "=" + value);
- this._spi[attrname](value);
+ for(var attrname in options) {
+ var value = options[attrname];
+ if (attrname in this._spi) {
+ this._spi[attrname](value);
+ }
+ else
+ console.log("Unknown option: " + attrname + "=" + value);
}
- }
- this.device = device;
+ this.device = device;
- this._spi.open(device);
-
- isFunction(callback) && callback(this); // TODO: Update once open is async;
+ isFunction(callback) && callback(this); // TODO: Update once open is async;
}
Spi.prototype.open = function() {
- return this._spi.open(this.device);
+ return this._spi.open(this.device);
}
Spi.prototype.close = function() {
- return this._spi.close();
+ return this._spi.close();
}
Spi.prototype.write = function(buf, callback) {
- this._spi.transfer(buf, null);
+ this._spi.transfer(buf, new Buffer(buf.length));
- isFunction(callback) && callback(this, buf); // TODO: Update once open is async;
+ isFunction(callback) && callback(this, buf); // TODO: Update once open is async;
}
Spi.prototype.read = function(buf, callback) {
- this._spi.transfer(null, buf);
+ this._spi.transfer(new Buffer(buf.length), buf);
- isFunction(callback) && callback(this, buf); // TODO: Update once open is async;
+ isFunction(callback) && callback(this, buf); // TODO: Update once open is async;
}
+
Spi.prototype.transfer = function(txbuf, rxbuf, callback) {
- rxbuf = new Buffer(txbuf.length); // tx and rx buffers need to be the same size
- this._spi.transfer(txbuf, rxbuf);
+ // tx and rx buffers need to be the same size
+ this._spi.transfer(txbuf, rxbuf);
+
+ isFunction(callback) && callback(this, rxbuf); // TODO: Update once open is async;
+}
+
+Spi.prototype.mode = function(mode) {
+ if (typeof(mode) != 'undefined')
+ if (mode == MODE['MODE_0'] || mode == MODE['MODE_1'] ||
+ mode == MODE['MODE_2'] || mode == MODE['MODE_3'])
+ return this._spi['mode'](mode);
+ else {
+ console.log('Illegal mode');
+ return -1;
+ }
+ else
+ return this._spi['mode']();
+}
+
+Spi.prototype.chipSelect = function(cs) {
+ if (typeof(cs) != 'undefined')
+ if (cs == CS['none'] || cs == CS['high'] || cs == MODE['low'])
+ return this._spi['chipSelect'](cs);
+ else {
+ console.log('Illegal chip selection');
+ return -1;
+ }
+ else
+ return this._spi['chipSelect']();
+}
+
+Spi.prototype.bitsPerWord = function(bpw) {
+ if (typeof(bpw) != 'undefined')
+ if (bpw > 1)
+ return this._spi['bitsPerWord'](bpw);
+ else {
+ console.log('Illegal bits per word');
+ return -1;
+ }
+ else
+ return this._spi['bitsPerWord']();
+}
+
+Spi.prototype.bitOrder = function(bo) {
+ if (typeof(bo) != 'undefined')
+ if (bo == ORDER['msb'] || bo == ORDER['lsb'])
+ return this._spi['bitOrder'](bo);
+ else {
+ console.log('Illegal bit order');
+ return -1;
+ }
+ else
+ return this._spi['bitOrder']();
+}
+
+Spi.prototype.maxSpeed = function(speed) {
+ if (typeof(speed) != 'undefined')
+ if (speed > 0)
+ return this._spi['maxSpeed'](speed);
+ else {
+ console.log('Speed must be positive');
+ return -1;
+ }
+ else
+ return this._spi['maxSpeed']();
+}
+
+Spi.prototype.halfDuplex = function(duplex) {
+ if (typeof(duplex) != 'undefined')
+ if (duplex)
+ return this._spi['halfDuplex'](true);
+ else
+ return this._spi['halfDuplex'](false);
+ else
+ return this._spi['halfDuplex']();
+}
- isFunction(callback) && callback(this, rxbuf); // TODO: Update once open is async;
+Spi.prototype.loopback = function(loop) {
+ if (typeof(loop) != 'undefined')
+ if (loop)
+ return this._spi['loopback'](true);
+ else
+ return this._spi['loopback'](false);
+ else
+ return this._spi['loopback']();
}
module.exports.MODE = MODE;
module.exports.CS = CS;
+module.exports.ORDER = ORDER;
module.exports.Spi = Spi;
View
@@ -146,6 +146,9 @@ void Spi::Initialize(Handle<Object> target) {
target->Set(v8::String::NewSymbol("NO_CS"), v8::Integer::New(SPI_NO_CS));
target->Set(v8::String::NewSymbol("CS_LOW"), v8::Integer::New(0));
target->Set(v8::String::NewSymbol("CS_HIGH"), v8::Integer::New(SPI_CS_HIGH));
+
+ target->Set(v8::String::NewSymbol("ORDER_MSB"), v8::Boolean::New(false));
+ target->Set(v8::String::NewSymbol("ORDER_LSB"), v8::Boolean::New(true));
}
// new Spi(string device)
View
@@ -38,8 +38,8 @@ class Spi : ObjectWrap {
Spi() : m_fd(-1),
m_mode(0),
m_max_speed(1000000), // default speed in Hz () 1MHz
- m_delay(0), // default bits per word
- m_bits_per_word(8) { } // expose delay to options
+ m_delay(0), // expose delay to options
+ m_bits_per_word(8) { } // default bits per word
~Spi() { } // Probably close fd if it's open
SPI_FUNC(New);

0 comments on commit bf1f72d

Please sign in to comment.