diff --git a/README.md b/README.md index 53f2bb4..1707caa 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,13 @@ In contrast, *this* module is implemented in pure JavaScript on top of native [S [Streams](https://github.com/substack/stream-handbook#readme)! -``` -var radio = require('nrf').connect(spiDev, cePin, irqPin); -radio.channel(0x4c).dataRate('1Mbps').crcBytes(2).autoRetransmit({count:15, delay:4000}); -radio.begin(function () { +```js +var radio = require('nrf') + .channel(0x4c).dataRate('1Mbps') + .crcBytes(2).autoRetransmit({count:15, delay:4000}) + .use(spiDev, cePin, irqPin); + +radio.on('ready', function () { var rx = radio.openPipe('rx', 0xF0F0F0F0E1), tx = radio.openPipe('tx', 0xF0F0F0F0D2); rx.pipe(tx); // echo back everything diff --git a/examples/RF24-pingpair.js b/examples/RF24-pingpair.js new file mode 100644 index 0000000..2c50d51 --- /dev/null +++ b/examples/RF24-pingpair.js @@ -0,0 +1,67 @@ +/* + * These are settings for Tessel to work out of the box with + * maniacbug's RF24 pingpair example (https://github.com/maniacbug/RF24/blob/07a4bcf425d91c99105dbdbad0226296c7cd3a93/examples/pingpair/pingpair.pde) + * Useful for bridging an Arduino + nRF24 to Tessel + nRF24 + */ + +var tessel = require('tessel'), + NRF24 = require("../"), + pipes = [0xF0F0F0F0E1, 0xF0F0F0F0D2], + role = 'ping'; // swap this to pong if you want to wait for receive + +var nrf = NRF24.channel(0x4c) // set the RF channel to 76. Frequency = 2400 + RF_CH [MHz] = 2476MHz + .transmitPower('PA_MAX') // set the transmit power to max + .dataRate('1Mbps') + .crcBytes(2) // 2 byte CRC + .autoRetransmit({count:15, delay:4000}) + .use(tessel.port['A']); + +nrf._debug = false; + +nrf.on('ready', function () { + if (role === 'ping') { + console.log("PING out"); + /* + * The Arduino pong code needs to have its timeout changed. On line #205 + * https://github.com/maniacbug/RF24/blob/07a4bcf425d91c99105dbdbad0226296c7cd3a93/examples/pingpair/pingpair.pde#L205 + * the delay(20) needs to be swapped out with delay(2000) + */ + + var tx = nrf.openPipe('tx', pipes[1]), // transmit address F0F0F0F0D2 + rx = nrf.openPipe('rx', pipes[1], {size: 8}); // receive address F0F0F0F0D2 + tx.on('ready', function () { // NOTE: hoping to get rid of need to wait for "ready" + var n = 0; + setInterval(function () { + var b = new Buffer(8); // set buff len of 8 for compat with maniac bug's RF24 lib + b.fill(0); + b.writeUInt32BE(n++, 4); // offset by 4 because our buffer length is 8 bytes + console.log("Sending", n); + tx.write(b); + }, 5e3); // transmit every 5 seconds + }); + rx.on('data', function (d) { + console.log("Got response back:", d.readUInt32BE(4)); //offset by 4 again + }); + } else { + console.log("PONG back"); + /* + * The Arduino ping code needs to have its timeout changed. On line #161 + * https://github.com/maniacbug/RF24/blob/07a4bcf425d91c99105dbdbad0226296c7cd3a93/examples/pingpair/pingpair.pde#L161 + * instead of "if (millis() - started_waiting_at > 200 )" + * change to "if (millis() - started_waiting_at > 2000 )" + */ + + var rx = nrf.openPipe('rx', pipes[0], {size: 8}); + tx = nrf.openPipe('tx', pipes[0], {autoAck: false}); + rx.on('data', function (d) { + console.log("Got data, will respond", d); + tx.write(d); + }); + tx.on('error', function (e) { + console.warn("Error sending reply.", e); + }); + } +}); + +// hold this process open +process.ref(); \ No newline at end of file diff --git a/examples/nrf.js b/examples/nrf.js new file mode 100644 index 0000000..b8c22cb --- /dev/null +++ b/examples/nrf.js @@ -0,0 +1,68 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/publicdomain/zero/1.0/ + +/********************************************* +This nRF24 example requires two nRF24 modules +(and ideally two Tessels). Put one Tessel + +nRF24 module on "ping" mode and the other +pair on "pong" mode to make them send +information back and forth. +*********************************************/ + +var tessel = require('tessel'); +var NRF24 = require('../'); // Replace '../' with 'rf-nrf24' in your own code +var pipes = [0xF0F0F0F0E1, 0xF0F0F0F0D2]; + +var role = 'ping'; // 'ping' to send; 'pong' to receive + +// Set up NRF +var nrf = NRF24.channel(0x4c) // set the RF channel to 76. Frequency = 2400 + RF_CH [MHz] = 2476MHz + .transmitPower('PA_MAX') // set the transmit power to max + .dataRate('1Mbps') + .crcBytes(2) // 2 byte CRC + .autoRetransmit({count:15, delay:4000}) + .use(tessel.port['A']); + +nrf._debug = false; + +// Wait for the module to connect +nrf.on('ready', function () { + setTimeout(function(){ + nrf.printDetails(); + }, 5000); + + if (role === 'ping') { + console.log('PING out'); + // If set to 'ping' mode, send data + var tx = nrf.openPipe('tx', pipes[0], {autoAck: false}), // transmit address F0F0F0F0D2 + rx = nrf.openPipe('rx', pipes[1], {size: 4}); // receive address F0F0F0F0D2 + tx.on('ready', function () { + var n = 0; + setInterval(function () { + var buff = new Buffer(4); // set buff len of 8 for compat with maniac bug's RF24 lib + buff.fill(0); + buff.writeUInt32BE(n++); + console.log("Sending", n); + tx.write(buff); + }, 5e3); // transmit every 5 seconds + }); + rx.on('data', function (data) { + console.log("Got response back:", data); + }); + } else { + console.log("PONG back"); + // If set to 'pong' mode, receive data + var rx = nrf.openPipe('rx', pipes[0], {size: 4}); + tx = nrf.openPipe('tx', pipes[1], {autoAck: false}); + rx.on('data', function (data) { + console.log("Got data, will respond", data); + tx.write(data); + }); + tx.on('error', function (err) { + console.warn("Error sending reply.", err); + }); + } +}); + +// hold this process open +process.ref(); diff --git a/examples/nrf24.js b/examples/nrf24.js new file mode 100644 index 0000000..f8253be --- /dev/null +++ b/examples/nrf24.js @@ -0,0 +1,58 @@ +/* tessel to tessel + * requires 2 nrf24 modules (and ideally two tessels) + * put one tessel+nrf on "ping" mode and another one on "pong" mode + */ + +var tessel = require('tessel'), + NRF24 = require("../"), + pipes = [0xF0F0F0F0E1, 0xF0F0F0F0D2], + role = 'ping'; // swap this to pong if you want to wait for receive + +var nrf = NRF24.channel(0x4c) // set the RF channel to 76. Frequency = 2400 + RF_CH [MHz] = 2476MHz + .transmitPower('PA_MAX') // set the transmit power to max + .dataRate('1Mbps') + .crcBytes(2) // 2 byte CRC + .autoRetransmit({count:15, delay:4000}) + .use(tessel.port['A']); + +nrf._debug = false; + +nrf.on('ready', function () { + setTimeout(function(){ + nrf.printDetails(); + }, 5000); + + if (role === 'ping') { + console.log("PING out"); + + var tx = nrf.openPipe('tx', pipes[0], {autoAck: false}), // transmit address F0F0F0F0D2 + rx = nrf.openPipe('rx', pipes[1], {size: 4}); // receive address F0F0F0F0D2 + tx.on('ready', function () { + var n = 0; + setInterval(function () { + var b = new Buffer(4); // set buff len of 8 for compat with maniac bug's RF24 lib + b.fill(0); + b.writeUInt32BE(n++); + console.log("Sending", n); + tx.write(b); + }, 5e3); // transmit every 5 seconds + }); + rx.on('data', function (d) { + console.log("Got response back:", d); + }); + } else { + console.log("PONG back"); + var rx = nrf.openPipe('rx', pipes[0], {size: 4}); + tx = nrf.openPipe('tx', pipes[1], {autoAck: false}); + rx.on('data', function (d) { + console.log("Got data, will respond", d); + tx.write(d); + }); + tx.on('error', function (e) { + console.warn("Error sending reply.", e); + }); + } +}); + +// hold this process open +process.ref(); \ No newline at end of file diff --git a/index.js b/index.js index 5995dd7..a0e2b71 100644 --- a/index.js +++ b/index.js @@ -2,10 +2,15 @@ var q = require('queue-async'), stream = require('stream'), util = require('util'), events = require('events'), - SPI = require('pi-spi'), - GPIO = require('pi-pins'), _m = require("./magicnums"); +var tessel; +try { + tessel = require('tessel'); +} catch (e) {} + +var nrfOpts = {}; + function forEachWithCB(fn, cb) { var process = q(1); this.forEach(function (d) { process.defer(fn, d); }); @@ -22,25 +27,140 @@ function _extend(obj) { function _nop() {} // used when a cb is not provided +function nrfWrapper(){} -exports.connect = function (spi,ce,irq) { - var _spi = spi, _ce = ce, _irq = irq; // only for printDetails! - var nrf = new events.EventEmitter(), - spi = SPI.initialize(spi), - ce = GPIO.connect(ce), - irq = (arguments.length > 2) && GPIO.connect(irq); - - nrf._T = _extend({}, _m.TIMING, {pd2stby:4500}); // may need local override of pd2stby +nrfWrapper.use =function(hardware, ce, irq, callback) { + var nrfObj; + // if we just have hardware assume it's a tessel + if (arguments.length <= 2){ + callback = arguments[1]; + nrfObj = new nrf('tessel', hardware); + } else if (arguments.length >= 3){ + // if we have everything assume it's an RPi + nrfObj = new nrf('pi', hardware, ce, irq); + } + // go through and apply all options + forEachWithCB.call(Object.keys(nrfOpts), function(key, cb){ + nrfObj[key](nrfOpts[key], cb); + }, function(){ + // on finish emit ready + nrfObj.begin(function(){ + nrfObj.emit('ready'); + callback && callback(); + }); + }) + + return nrfObj; +} + +nrfWrapper.channel = function(val){ + nrfOpts.channel = val; + return this; +} + +nrfWrapper.dataRate = function(val){ + nrfOpts.dataRate = val; + return this; +} + +nrfWrapper.transmitPower = function(val){ + nrfOpts.transmitPower = val; + return this; +} + +nrfWrapper.crcBytes = function(val){ + nrfOpts.crcBytes = val; + return this; +} + +nrfWrapper.addressWidth = function(val){ + nrfOpts.addressWidth = val; + return this; +} + +nrfWrapper.autoRetransmit = function(val){ + nrfOpts.autoRetransmit = val; + return this; +} + +module.exports = nrfWrapper; + +function nrf(type, hardware) { + var _spi = type; + var _ce, _irq, ce, irq, spi; + var nrf = new events.EventEmitter(); - nrf.blockMicroseconds = function (us) { - // NOTE: setImmediate/process.nextTick too slow (especially on Pi) so we just spinloop for µs - var start = process.hrtime(); - while (1) { - var diff = process.hrtime(start); - if (diff[0] * 1e9 + diff[1] >= us*1e3) break; + if (type == 'tessel') { + _ce = "builtin"; + _irq = "builtin"; + spi = new hardware.SPI({chipSelect:hardware.digital[1], chipSelectActive: 0}), + ce = hardware.digital[2], + irq = hardware.digital[3]; + + // Tessel's transfer always returns as much data as sent + nrf._transfer = function (writeBuf, readLen, cb) { + if (readLen > writeBuf.length) { + var tmpBuff = Buffer(readLen); + tmpBuff.fill(0); + writeBuf.copy(tmpBuff); + writeBuf = tmpBuff; + } + + spi.transfer(writeBuf, function (e,d) { + if (e) cb(e); + else cb(null, d); + }); + }; + + nrf.blockMicroseconds = function (us) { + tessel.sleep(us); + if (nrf._debug) console.log("slept for "+us+"µs."); + }; + + nrf.setCE = function (state, block) { + if (typeof state === 'string') { + ce.input(); + if (state === 'high') state = true; + else if (state === 'low') state = false; + else throw Error("Unsupported setCE mode: "+state); + } + if (state) ce.high(); + else ce.low(); + if (nrf._debug) console.log("Set CE "+state+"."); + if (block) nrf.blockMicroseconds(nrf._T[block]); // (assume ce changed TX/RX mode) } - if (nrf._debug) console.log("blocked for "+us+"µs."); - }; + + } else if (type == 'pi'){ + spi = hardware; + ce = arguments[2]; + irq = arguments[3]; + + nrf._transfer = function(buff, len, cb) { + spi.transfer(buff, len, cb); + } + + nrf.blockMicroseconds = function (us) { + // NOTE: setImmediate/process.nextTick too slow (especially on Pi) so we just spinloop for µs + var start = process.hrtime(); + while (1) { + var diff = process.hrtime(start); + if (diff[0] * 1e9 + diff[1] >= us*1e3) break; + } + if (nrf._debug) console.log("blocked for "+us+"µs."); + }; + + nrf.setCE = function (state, block) { + if (typeof state === 'string') ce.mode(state); + else ce.value(state); + if (nrf._debug) console.log("Set CE "+state+"."); + if (block) nrf.blockMicroseconds(nrf._T[block]); // (assume ce changed TX/RX mode) + }; + + } else { + throw "Error: nRF can only be used with the Pi or the Tessel at the moment"; + } + + nrf._T = _extend({}, _m.TIMING, {pd2stby:4500}); // may need local override of pd2stby nrf.execCommand = function (cmd, data, cb) { // (can omit data, or specify readLen instead) if (typeof data === 'function' || typeof data === 'undefined') { @@ -73,12 +193,13 @@ exports.connect = function (spi,ce,irq) { readLen = data; } - spi.transfer(writeBuf, readLen && readLen+1, function (e,d) { + nrf._transfer(writeBuf, readLen && readLen+1, function (e,d) { if (nrf._debug && readLen) console.log(' - exec read:', d); if (e) return cb(e); else return cb(null, d && Array.prototype.reverse.call(d.slice(1))); }); }; + function registersForMnemonics(list) { var registersNeeded = Object.create(null); @@ -96,6 +217,7 @@ exports.connect = function (spi,ce,irq) { }); return registersNeeded; } + function maskForMnemonic(mnem) { var _r = _m.REGISTER_MAP[mnem], @@ -128,6 +250,7 @@ exports.connect = function (spi,ce,irq) { cb(e,states); }); }; + var _statusReg = _m.REGISTER_MAP['STATUS'][0]; nrf.setStates = function (vals, cb) { @@ -169,13 +292,8 @@ exports.connect = function (spi,ce,irq) { } forEachWithCB.call(Object.keys(registersNeeded), processInquiryForRegister, cb); }; + - nrf.setCE = function (state, block) { - if (typeof state === 'string') ce.mode(state); - else ce.value(state); - if (nrf._debug) console.log("Set CE "+state+"."); - if (block) nrf.blockMicroseconds(nrf._T[block]); // (assume ce changed TX/RX mode) - }; nrf.pulseCE = function (block) { nrf.setCE(true,'hce'); nrf.setCE(false,block); @@ -387,9 +505,12 @@ exports.connect = function (spi,ce,irq) { irqOn = false; nrf._irqOn = function () { if (irqOn) return; - else if (irq) { + else if (irq && !tessel) { irq.mode('in'); irq.addListener('fall', irqListener); + } else if (irq) { + // hybrid mode: polling, but of IRQ pin instead of nrf status + irq.watch('fall', irqListener); } else { console.warn("Recommend use with IRQ pin, fallback handling is suboptimal."); irqListener = setInterval(function () { // TODO: clear interval when there are no listeners? @@ -400,7 +521,8 @@ exports.connect = function (spi,ce,irq) { }; nrf._irqOff = function () { if (!irqOn) return; - else if (irq) irq.removeListener('fall', irqListener); + else if (irq && !tessel) irq.removeListener('fall', irqListener); + else if (tessel) irq.unwatch('fall'); else clearInterval(irqListener); irqOn = false; }; @@ -418,9 +540,11 @@ exports.connect = function (spi,ce,irq) { if (e) return nrf.emit('error', e); nrf._irqOn(); // NOTE: on before any pipes to facilite lower-level sendPayload use ready = true; - nrf.emit('ready'); + // nrf.emit('ready'); + if (cb) cb(); }); - if (cb) nrf.once('ready', cb); + // .use now emits and handles .ready + // if (cb) nrf.once('ready', cb); }; nrf.end = function (cb) { var pipes = txPipes.concat(rxPipes); @@ -637,7 +761,7 @@ exports.connect = function (spi,ce,irq) { _h(d.RX_PW_P0),_h(d.RX_PW_P1),_h(d.RX_PW_P2), _h(d.RX_PW_P3),_h(d.RX_PW_P4),_h(d.RX_PW_P5) ); - nrf.getStates(['EN_AA','EN_RXADDR','RF_CH','RF_SETUP','CONFIG','DYNPD','FEATURE'], function (e,d) { + nrf.getStates(['CONFIG','EN_AA','EN_RXADDR','RF_CH','RF_SETUP','DYNPD','FEATURE'], function (e,d) { console.log("EN_AA:\t\t",_h(d.EN_AA)); console.log("EN_RXADDR:\t",_h(d.EN_RXADDR)); console.log("RF_CH:\t\t",_h(d.RF_CH)); @@ -652,7 +776,7 @@ exports.connect = function (spi,ce,irq) { logFinalDetails(); } else nrf.setStates({RF_DR_LOW:true}, function () { nrf.getStates(['RF_DR_LOW'], function (e,d2) { - // (non-plus chips hold this bit zero even after settting) + // (non-plus chips hold this bit zero even after setting) if (d2.RF_DR_LOW) isPlus = true; // …then set back to original (false) value again nrf.setStates({RF_DR_LOW:false}, function () { @@ -672,7 +796,9 @@ exports.connect = function (spi,ce,irq) { }); }); }); - function _h(n) { return (Buffer.isBuffer(n)) ? '0x'+n.toString('hex') : '0x'+n.toString(16); } + function _h(n) { + return (Buffer.isBuffer(n)) ? '0x'+n.toString('hex') : '0x'+n.toString(16); + } }; nrf.on('interrupt', function (d) { if (nrf._debug) console.log("IRQ.", d); }); diff --git a/magicnums.js b/magicnums.js index 959b6ed..acb3c1a 100644 --- a/magicnums.js +++ b/magicnums.js @@ -1,4 +1,13 @@ -function _b(v) { return parseInt(v.replace(' ',''),2); } +//function _b(v) { return parseInt(v.replace(' ',''),2); } +// WORKAROUND: https://github.com/tessel/beta/issues/206 +function _b(v) { + if (v.length !== 9) throw Error("Proper conversion not implemented for this size string!"); + var n = 0; + Array.prototype.forEach.call(v.replace(' ',''), function (l, i) { + if (l === '1') n += 1 << (7 - i); + }); + return n; +} exports.COMMANDS = { R_REGISTER: _b('0000 0000'), diff --git a/package.json b/package.json index 6f5a00c..d4c2f91 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "nRF24L01 driver library", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "tinytap -e 'tessel run {}' test/*.js" }, "repository": { "type": "git", @@ -27,5 +27,12 @@ "pi-spi": "~0.8.1", "queue-async": "~1.0.4", "pi-pins": "^1.0.0" + }, + "hardware": { + "pi-spi": false, + "pi-pins": false + }, + "devDependencies": { + "tinytap": "~0.0.2" } } diff --git a/test-tessel.js b/test-tessel.js new file mode 100644 index 0000000..b2a715e --- /dev/null +++ b/test-tessel.js @@ -0,0 +1,78 @@ +var tessel = require('tessel'), + NRF24 = require("./index"), + nrf = NRF24.use(tessel.port('a')), + pipes = ['F0F0F0F0E1', 'F0F0F0F0D2'], + role = 'ping'; +//nrf._debug = true; +//nrf.printDetails(); + +nrf.channel(0x4c).transmitPower('PA_MAX').dataRate('1Mbps').crcBytes(2).autoRetransmit({count:15, delay:4000}).begin(function () { + if (role === 'listen') { + // HACK: listen for "ambient" broadcast i.e. https://github.com/natevw/greenhouse/blob/master/config.h#L5 + var rx = nrf.openPipe('rx', pipes[0], {autoAck:false}); + rx.on('data', function (d) { + Array.prototype.reverse.call(d); // WORKAROUND: https://github.com/natevw/node-nrf/issues/3 + console.log("******** Got data ********", d); + + if (d.slice(0,4).toString() === 'aqua') { + //printf("Received broadcast: now=%u switchAugerCount=%u remoteAugerCount=%u waterTemp=%u humidity=%u airTemp=%u nc=%u\n", …) + var info = { + now: d.readUInt32LE(1*4), + switchAugerCount: d.readUInt32LE(2*4), + remoteAugerCount: d.readUInt32LE(3*4), + waterTempC: waterTemp(d.readUInt32LE(4*4)), + humidity: d.readUInt32LE(5*4), + airTempC: airTemp(d.readUInt32LE(6*4)), + nc: powerStatus(d.readUInt32LE(7*4)) + }; + info.waterTempF = c2f(info.waterTempC); + info.airTempF = c2f(info.airTempC); + console.log(info); + + // pinched from https://github.com/natevw/rooflux/blob/greenhouse/display.html#L65 + function c2f(c) { return 1.8 * c + 32; } + function waterTemp(b) { + var sign = (b & 0xf800) ? -1 : 1; + return sign * (b & ~0xf800) / (1 << 4); + } + function airTemp(b) { + return (b/1024*3.3-0.5)*100; + } + function powerStatus(b) { + if (b === 0) return "Normal"; + else if (b > 1024) return "Bogus data…"; + else if (b > 300) return "On battery!"; + else return "Unknown: "+b; + } + } + }); + } else if (role === 'ping') { + console.log("PING out"); + var tx = nrf.openPipe('tx', pipes[0]), + rx = nrf.openPipe('rx', pipes[1]); + tx.on('ready', function () { // NOTE: hoping to get rid of need to wait for "ready" + // (new CountStream).pipe(tx); + var n = 0; + setInterval(function () { + console.log("Sending", n); + var b = new Buffer(4); + b.writeUInt32BE(n++, 0); + tx.write(b); + }, 1e3); + }); + rx.on('data', function (d) { + console.log("Got response back:", d.readUInt32BE(0)); + }); + } else { + console.log("PONG back"); + var rx = nrf.openPipe('rx', pipes[0]), + tx = nrf.openPipe('tx', pipes[1]); + rx.on('data', function (d) { + console.log("Got data, will respond", d.readUInt32BE(0)); + tx.write(d); + }); + tx.on('error', function (e) { + console.warn("Error sending reply.", e); + }); + } +}); \ No newline at end of file diff --git a/test.js b/test.js index daa355f..71635e5 100644 --- a/test.js +++ b/test.js @@ -2,6 +2,8 @@ var NRF24 = require("./index"), spiDev = "/dev/spidev0.0", + SPI = require('pi-spi'), + GPIO = require('pi-pins'), cePin = 24, irqPin = 25, //var ce = require("./gpio").connect(cePin) pipes = [0xF0F0F0F0E1, 0xF0F0F0F0D2], role = 'ping'; @@ -20,9 +22,15 @@ CountStream.prototype._read = function () { this.push(b); }; -var nrf = NRF24.connect(spiDev, cePin, irqPin); +var nrf = NRF24.channel(0x4c) + .transmitPower('PA_MAX') + .dataRate('1Mbps') + .crcBytes(2) + .autoRetransmit({count:15, delay:4000}) + .use(SPI.initialize(spiDev), GPIO.connect(cePin), GPIO.connect(irqPin)); + //nrf._debug = true; -nrf.channel(0x4c).transmitPower('PA_MAX').dataRate('1Mbps').crcBytes(2).autoRetransmit({count:15, delay:4000}).begin(function () { +nrf.on('ready', function () { if (role === 'ping') { console.log("PING out"); var tx = nrf.openPipe('tx', pipes[0]), diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..bca10a4 --- /dev/null +++ b/test/test.js @@ -0,0 +1,69 @@ +/* tessel to tessel + * requires 2 nrf24 modules (and ideally two tessels) + * put one tessel+nrf on "ping" mode and another one on "pong" mode + */ + +var tessel = require('tessel'), + NRF24 = require("../"), + pipes = [0xF0F0F0F0E1, 0xF0F0F0F0D2]; + +console.log('1..3'); + +function go (port, role) { + var nrf = NRF24.channel(0x4c) // set the RF channel to 76. Frequency = 2400 + RF_CH [MHz] = 2476MHz + .transmitPower('PA_MAX') // set the transmit power to max + .dataRate('1Mbps') + .crcBytes(2) // 2 byte CRC + .autoRetransmit({count:15, delay:4000}) + .use(port); + + nrf._debug = false; + + var sendack = false, resack = false; + nrf.on('ready', function () { + if (role === 'ping') { + console.log("# PING out"); + + var tx = nrf.openPipe('tx', pipes[0], {autoAck: false}), // transmit address F0F0F0F0D2 + rx = nrf.openPipe('rx', pipes[1], {size: 4}); // receive address F0F0F0F0D2 + tx.on('ready', function () { + var n = 0; + setImmediate(function loop () { + var b = new Buffer(4); // set buff len of 8 for compat with maniac bug's RF24 lib + b.fill(0); + b.writeUInt32BE(n++); + console.log("# sending", n); + !sendack && console.log('ok - sending'); + sendack = true; + tx.write(b); + setTimeout(loop, 5e3) + }); // transmit every 5 seconds + }); + rx.on('data', function (d) { + console.log("# got response back:", d); + console.log('ok - responded'); + process.exit(0); + }); + } else { + console.log("# PONG back"); + var rx = nrf.openPipe('rx', pipes[0], {size: 4}); + tx = nrf.openPipe('tx', pipes[1], {autoAck: false}); + rx.on('data', function (d) { + console.log("# got data, will respond", d); + !resack && console.log('ok - responding'); + resack = true; + tx.write(d); + }); + tx.on('error', function (e) { + console.log("not ok - Error sending reply.", e); + process.exit(1); + }); + } + }); +} + +// hold this process open +process.ref(); + +go(tessel.port['B'], 'ping'); +go(tessel.port['GPIO'], 'pong'); \ No newline at end of file