From 430300fa04f0dbcc1a8615d6b4aa198a8c06e7db Mon Sep 17 00:00:00 2001 From: Maxwell Hadley Date: Wed, 26 Feb 2014 18:37:11 +0000 Subject: [PATCH] Added discrete-out node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The output node is currently in 145-digital-in. This situation is hopefully only temporary… --- hardware/BBB/145-digital-in.html | 128 ++++++++++++++++++++++++++++++- hardware/BBB/145-digital-in.js | 92 +++++++++++++++++++--- 2 files changed, 208 insertions(+), 12 deletions(-) diff --git a/hardware/BBB/145-digital-in.html b/hardware/BBB/145-digital-in.html index 23aa28bd..8f6e4e78 100644 --- a/hardware/BBB/145-digital-in.html +++ b/hardware/BBB/145-digital-in.html @@ -61,6 +61,14 @@ +
+ + +
@@ -80,10 +88,10 @@ @@ -102,7 +115,8 @@ of the active time, not the pin state value sent on the first output. defaults: { // defines the editable properties of the node pin: { value:"", required:true }, activeLow: { value:false, required:true }, - debounce: { value:false, required: true }, + debounce: { value:false, required:true }, + outputOn: { value:"both", required:true }, updateInterval: { value:60, required:true, validate:RED.validators.number() }, topic: { value:"" }, name: { value:"" } @@ -230,3 +244,111 @@ any other input message will reset it to zero. }); + + + + + + + + diff --git a/hardware/BBB/145-digital-in.js b/hardware/BBB/145-digital-in.js index 57a3dbc8..c401f494 100644 --- a/hardware/BBB/145-digital-in.js +++ b/hardware/BBB/145-digital-in.js @@ -37,6 +37,15 @@ function DiscreteInputNode(n) { this.activeState = 1; this.updateInterval = n.updateInterval * 1000; // How often to send totalActiveTime messages this.debounce = n.debounce; // Enable switch contact debouncing algorithm + if (n.outputOn === "rising") { + this.activeEdges = [false, true]; + } else if (n.outputOn === "falling") { + this.activeEdges = [true, false]; + } else if (n.outputOn === "both") { + this.activeEdges = [true, true]; + } else { + node.error("Invalid edge type: " + n.outputOn); + } // Working variables this.interruptAttached = false; // Flag: should we detach interrupt when we are closed? @@ -93,10 +102,12 @@ function DiscreteInputNode(n) { } else if (!isNaN(node.lastActiveTime)) { node.totalActiveTime += now - node.lastActiveTime; } - var msg = {}; - msg.topic = node.topic; - msg.payload = node.currentState; - node.send([msg, null]); + if (node.activeEdges[node.currentState]) { + var msg = {}; + msg.topic = node.topic; + msg.payload = node.currentState; + node.send([msg, null]); + } }; // This function is called by the timer. It updates the ActiveTime variables, and sends a @@ -131,10 +142,17 @@ function DiscreteInputNode(n) { if (node.currentState === node.activeState) { node.lastActiveTime = Date.now(); } + // On startup, send an initial activeTime message, but only send an + // initial currentState message if we are in both edges active mode if (node.starting) { node.starting = false; - var msg = [{topic:node.topic}, {topic:node.topic}]; - msg[0].payload = node.currentState; + var msg; + if (node.activeEdges[0] && node.activeEdges[1]) { + msg = [{topic:node.topic}, {topic:node.topic}]; + msg[0].payload = node.currentState; + } else { + msg = [null, {topic:node.topic}]; + } msg[1].payload = node.totalActiveTime; node.send(msg); } @@ -239,8 +257,8 @@ function PulseInputNode(n) { // Don't set up interrupts & intervals until after the close event handler has been installed bonescript.detachInterrupt(node.pin); process.nextTick(function () { - bonescript.pinMode(node.pin, bonescript.INPUT); - bonescript.digitalRead(node.pin, function (x) { + bonescript.pinMode(node.pin, bonescript.INPUT); + bonescript.digitalRead(node.pin, function (x) { // Initialise the currentState based on the value read node.currentState = Number(x.value); // Attempt to attach an interrupt handler to the pin. If we succeed, @@ -260,15 +278,71 @@ function PulseInputNode(n) { node.error("Failed to attach interrupt"); } }); - }); + }); } else { node.error("Unconfigured input pin"); } } +// Node constructor for discrete-out +function DiscreteOutputNode(n) { + RED.nodes.createNode(this, n); + + // Store local copies of the node configuration (as defined in the .html) + this.topic = n.topic; // the topic is not currently used + this.pin = n.pin; // The Beaglebone Black pin identifying string + this.defaultState = Number(n.defaultState); // What state to set up as + this.inverting = n.inverting; + this.toggle = n.toggle; + + // Working variables + this.currentState = this.defaultState; + + var node = this; + + // If the input message paylod is numeric, values > 0.5 are 'true', otherwise use + // the truthiness of the payload. Apply the inversion flag before setting the output + var inputCallback = function (msg) { + var newState; + if (node.toggle) { + newState = node.currentState === 0 ? 1 : 0; + } else { + if (isFinite(Number(msg.payload))) { + newState = Number(msg.payload) > 0.5 ? true : false; + } else if (msg.payload) { + newState = true; + } else { + newState = false; + } + if (node.inverting) { + newState = !newState; + } + } + bonescript.digitalWrite(node.pin, newState ? 1 : 0); + node.currentState = newState; + }; + + // If we have a valid pin, set it as an output and set the default state + if (["P8_7", "P8_8", "P8_9", "P8_10", "P8_11", "P8_12", "P8_13", "P8_14", "P8_15", + "P8_16", "P8_17", "P8_18", "P8_19", "P8_26", "P9_11", "P9_12", "P9_13", "P9_14", + "P9_15", "P9_16", "P9_17", "P9_18", "P9_21", "P9_22", "P9_23", "P9_24", "P9_26", + "P9_27", "P9_30", "P9_41", "P9_42", "USR0", "USR1", "USR2", "USR3"].indexOf(node.pin) >= 0) { + // Don't set up interrupts & intervals until after the close event handler has been installed + bonescript.detachInterrupt(node.pin); + process.nextTick(function () { + bonescript.pinMode(node.pin, bonescript.OUTPUT); + node.on("input", inputCallback); + setTimeout(function () { bonescript.digitalWrite(node.pin, node.defaultState); }, 50); + }); + } else { + node.error("Unconfigured output pin"); + } +} + // Register the nodes by name. This must be called before overriding any of the Node functions. RED.nodes.registerType("discrete-in", DiscreteInputNode); RED.nodes.registerType("pulse-in", PulseInputNode); +RED.nodes.registerType("discrete-out", DiscreteOutputNode); // On close, detach the interrupt (if we attached one) and clear any active timers DiscreteInputNode.prototype.close = function () {