node-red-nodes/io/serialport/25-serial.js

502 lines
24 KiB
JavaScript
Raw Permalink Normal View History

module.exports = function(RED) {
"use strict";
var settings = RED.settings;
var events = require("events");
2022-02-24 18:15:10 +01:00
const { SerialPort } = require('serialport');
var bufMaxSize = 32768; // Max serial buffer size, for inputs...
const serialReconnectTime = settings.serialReconnectTime || 15000;
// TODO: 'serialPool' should be encapsulated in SerialPortNode
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
// Configuration Node
function SerialPortNode(n) {
RED.nodes.createNode(this,n);
this.serialport = n.serialport;
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
this.newline = n.newline; /* overloaded: split character, timeout, or character count */
this.addchar = n.addchar || "";
this.serialbaud = parseInt(n.serialbaud) || 57600;
this.databits = parseInt(n.databits) || 8;
this.parity = n.parity || "none";
this.stopbits = parseInt(n.stopbits) || 1;
this.dtr = n.dtr || "none";
this.rts = n.rts || "none";
this.cts = n.cts || "none";
this.dsr = n.dsr || "none";
this.bin = n.bin || "false";
this.out = n.out || "char";
this.waitfor = n.waitfor || "";
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
this.responsetimeout = n.responsetimeout || 10000;
}
RED.nodes.registerType("serial-port",SerialPortNode);
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
// receives msgs and sends them to the serial port
function SerialOutNode(n) {
RED.nodes.createNode(this,n);
this.serial = n.serial;
this.serialConfig = RED.nodes.getNode(this.serial);
if (this.serialConfig) {
var node = this;
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
node.port = serialPool.get(this.serialConfig);
node.on("input",function(msg) {
if (msg.hasOwnProperty("baudrate")) {
var baud = parseInt(msg.baudrate);
if (isNaN(baud)) {
node.error(RED._("serial.errors.badbaudrate"),msg);
} else {
node.port.update({baudRate: baud},function(err,res) {
if (err) {
var errmsg = err.toString().replace("Serialport","Serialport "+node.port.serial.path);
node.error(errmsg,msg);
}
});
}
}
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
if (!msg.hasOwnProperty("payload")) { return; } // do nothing unless we have a payload
var payload = node.port.encodePayload(msg.payload);
node.port.write(payload,function(err,res) {
if (err) {
var errmsg = err.toString().replace("Serialport","Serialport "+node.port.serial.path);
node.error(errmsg,msg);
}
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
});
});
node.port.on('ready', function() {
node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
});
node.port.on('closed', function() {
node.status({fill:"red",shape:"ring",text:"node-red:common.status.not-connected"});
});
2017-01-29 18:45:44 +01:00
}
else {
2021-03-11 22:24:35 +01:00
this.error(RED._("serial.errors.missing-conf"), {});
}
this.on("close", function(done) {
if (this.serialConfig) {
serialPool.close(this.serialConfig.serialport,done);
2017-01-29 18:45:44 +01:00
}
else {
done();
}
});
}
RED.nodes.registerType("serial out",SerialOutNode);
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
// receives data from the serial port and emits msgs
function SerialInNode(n) {
RED.nodes.createNode(this,n);
this.serial = n.serial;
this.serialConfig = RED.nodes.getNode(this.serial);
if (this.serialConfig) {
var node = this;
node.status({fill:"grey",shape:"dot",text:"node-red:common.status.not-connected"});
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
node.port = serialPool.get(this.serialConfig);
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
this.port.on('data', function(msgout) {
node.send(msgout);
});
this.port.on('ready', function() {
node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
});
this.port.on('closed', function() {
node.status({fill:"red",shape:"ring",text:"node-red:common.status.not-connected"});
});
}
else {
2021-03-11 22:24:35 +01:00
this.error(RED._("serial.errors.missing-conf"), {});
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
}
this.on("close", function(done) {
if (this.serialConfig) {
serialPool.close(this.serialConfig.serialport,done);
2017-01-29 18:45:44 +01:00
}
else {
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
done();
}
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
});
}
RED.nodes.registerType("serial in",SerialInNode);
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
/******* REQUEST *********/
function SerialRequestNode(n) {
RED.nodes.createNode(this,n);
this.serial = n.serial;
this.serialConfig = RED.nodes.getNode(this.serial);
if (this.serialConfig) {
var node = this;
node.port = serialPool.get(this.serialConfig);
// Serial Out
node.on("input",function(msg) {
if (msg.hasOwnProperty("baudrate")) {
var baud = parseInt(msg.baudrate);
if (isNaN(baud)) {
node.error(RED._("serial.errors.badbaudrate"),msg);
} else {
node.port.update({baudRate: baud},function(err,res) {
if (err) {
var errmsg = err.toString().replace("Serialport","Serialport "+node.port.serial.path);
node.error(errmsg,msg);
}
});
}
}
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
if (!msg.hasOwnProperty("payload")) { return; } // do nothing unless we have a payload
if (msg.hasOwnProperty("count") && (typeof msg.count === "number") && (node.serialConfig.out === "count")) {
node.serialConfig.newline = msg.count;
}
if (msg.hasOwnProperty("flush") && msg.flush === true) { node.port.serial.flush(); }
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
node.status({fill:"yellow",shape:"dot",text:"serial.status.waiting"});
node.port.enqueue(msg,node,function(err,res) {
if (err) {
var errmsg = err.toString().replace("Serialport","Serialport "+node.port.serial.path);
node.error(errmsg,msg);
}
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
});
});
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
// Serial In
this.port.on('data', function(msgout, sender) {
// serial request will only process incoming data pertaining to its own request (i.e. when it's at the head of the queue)
if (sender !== node) { return; }
node.status({fill:"green",shape:"dot",text:"node-red:common.status.ok"});
msgout.status = "OK";
node.send(msgout);
});
this.port.on('timeout', function(msgout, sender) {
if (sender !== node) { return; }
msgout.status = "ERR_TIMEOUT";
node.status({fill:"red",shape:"ring",text:"serial.status.timeout"});
node.send(msgout);
});
// Common part
node.port.on('ready', function() {
node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
});
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
node.port.on('closed', function() {
node.status({fill:"red",shape:"ring",text:"node-red:common.status.not-connected"});
});
2017-01-29 18:45:44 +01:00
}
else {
2021-03-11 22:24:35 +01:00
this.error(RED._("serial.errors.missing-conf"), {});
}
this.on("close", function(done) {
if (this.serialConfig) {
serialPool.close(this.serialConfig.serialport,done);
2017-01-29 18:45:44 +01:00
}
else {
done();
}
});
}
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
RED.nodes.registerType("serial request", SerialRequestNode);
var serialPool = (function() {
var connections = {};
return {
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
get:function(serialConfig) {
// make local copy of configuration -- perhaps not needed?
var port = serialConfig.serialport,
baud = serialConfig.serialbaud,
databits = serialConfig.databits,
parity = serialConfig.parity,
stopbits = serialConfig.stopbits,
dtr = serialConfig.dtr,
rts = serialConfig.rts,
cts = serialConfig.cts,
dsr = serialConfig.dsr,
newline = serialConfig.newline,
spliton = serialConfig.out,
waitfor = serialConfig.waitfor,
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
binoutput = serialConfig.bin,
addchar = serialConfig.addchar,
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
responsetimeout = serialConfig.responsetimeout;
var id = port;
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
// just return the connection object if already have one
// key is the port (file path)
if (connections[id]) { return connections[id]; }
// State variables to be used by the on('data') handler
var i = 0; // position in the buffer
// .newline is misleading as its meaning depends on the split input policy:
// "char" : a msg will be sent after a character with value .newline is received
// "time" : a msg will be sent after .newline milliseconds
// "count" : a msg will be sent after .newline characters
// if we use "count", we already know how big the buffer will be
var bufSize = (spliton === "count") ? Number(newline): bufMaxSize;
waitfor = waitfor.replace("\\n","\n").replace("\\r","\r").replace("\\t","\t").replace("\\e","\e").replace("\\f","\f").replace("\\0","\0"); // jshint ignore:line
if (waitfor.substr(0,2) == "0x") { waitfor = parseInt(waitfor,16); }
if (waitfor.length === 1) { waitfor = waitfor.charCodeAt(0); }
var active = (waitfor === "") ? true : false;
var buf = new Buffer.alloc(bufSize);
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
var splitc; // split character
// Parse the split character onto a 1-char buffer we can immediately compare against
if (newline.substr(0,2) == "0x") {
splitc = new Buffer.from([newline]);
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
}
else {
splitc = new Buffer.from(newline.replace("\\n","\n").replace("\\r","\r").replace("\\t","\t").replace("\\e","\e").replace("\\f","\f").replace("\\0","\0")); // jshint ignore:line
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
}
if (addchar === true) { addchar = splitc; }
addchar = addchar.replace("\\n","\n").replace("\\r","\r").replace("\\t","\t").replace("\\e","\e").replace("\\f","\f").replace("\\0","\0"); // jshint ignore:line
if (addchar.substr(0,2) == "0x") { addchar = new Buffer.from([addchar]); }
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
connections[id] = (function() {
var obj = {
_emitter: new events.EventEmitter(),
serial: null,
_closing: false,
tout: null,
queue: [],
on: function(a,b) { this._emitter.on(a,b); },
close: function(cb) { this.serial.close(cb); },
encodePayload: function (payload) {
if (!Buffer.isBuffer(payload)) {
if (typeof payload === "object") {
payload = JSON.stringify(payload);
}
else {
payload = payload.toString();
}
if (addchar !== "") { payload += addchar; }
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
}
else if (addchar !== "") {
payload = Buffer.concat([payload,addchar]);
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
}
return payload;
},
write: function(m,cb) { this.serial.write(m,cb); },
update: function(m,cb) { this.serial.update(m,cb); },
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
enqueue: function(msg,sender,cb) {
var payload = this.encodePayload(msg.payload);
var qobj = {
sender: sender,
msg: msg,
payload: payload,
cb: cb,
}
this.queue.push(qobj);
// If we're enqueing the first message in line,
// we shall send it right away
if (this.queue.length === 1) {
this.writehead();
}
},
writehead: function() {
if (!this.queue.length) { return; }
var qobj = this.queue[0];
this.write(qobj.payload,qobj.cb);
var msg = qobj.msg;
var timeout = msg.timeout || responsetimeout;
this.tout = setTimeout(function () {
this.tout = null;
var msgout = obj.dequeue() || {};
msgout.port = port;
// if we have some leftover stuff, just send it
if (i !== 0) {
var m = buf.slice(0,i);
m = Buffer.from(m);
i = 0;
if (binoutput !== "bin") { m = m.toString(); }
msgout.payload = m;
}
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
/* Notify the sender that a timeout occurred */
obj._emitter.emit('timeout',msgout,qobj.sender);
}, timeout);
},
dequeue: function() {
// if we are trying to dequeue stuff from an
// empty queue, that's an unsolicited message
if (!this.queue.length) { return null; }
var msg = Object.assign({}, this.queue[0].msg);
msg = Object.assign(msg, {
request_payload: msg.payload,
request_msgid: msg._msgid,
});
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
delete msg.payload;
if (this.tout) {
clearTimeout(obj.tout);
obj.tout = null;
}
this.queue.shift();
this.writehead();
return msg;
},
}
//newline = newline.replace("\\n","\n").replace("\\r","\r");
var olderr = "";
var setupSerial = function() {
2022-02-24 18:15:10 +01:00
obj.serial = new SerialPort({
path: port,
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
baudRate: baud,
dataBits: databits,
parity: parity,
stopBits: stopbits,
//parser: serialp.parsers.raw,
autoOpen: true
}, function(err, results) {
if (err) {
if (err.toString() !== olderr) {
olderr = err.toString();
RED.log.error("[serialconfig:"+serialConfig.id+"] "+RED._("serial.errors.error",{port:port,error:olderr}), {});
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
}
obj.tout = setTimeout(function() {
setupSerial();
}, serialReconnectTime);
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
}
});
obj.serial.on('error', function(err) {
RED.log.error("[serialconfig:"+serialConfig.id+"] "+RED._("serial.errors.error",{port:port,error:err.toString()}), {});
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
obj._emitter.emit('closed');
if (obj.tout) { clearTimeout(obj.tout); }
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
obj.tout = setTimeout(function() {
setupSerial();
}, serialReconnectTime);
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
});
obj.serial.on('close', function() {
if (!obj._closing) {
if (olderr !== "unexpected") {
olderr = "unexpected";
RED.log.error("[serialconfig:"+serialConfig.id+"] "+RED._("serial.errors.unexpected-close",{port:port}), {});
}
obj._emitter.emit('closed');
if (obj.tout) { clearTimeout(obj.tout); }
obj.tout = setTimeout(function() {
setupSerial();
}, serialReconnectTime);
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
}
});
obj.serial.on('open',function() {
olderr = "";
RED.log.info("[serialconfig:"+serialConfig.id+"] "+RED._("serial.onopen",{port:port,baud:baud,config: databits+""+parity.charAt(0).toUpperCase()+stopbits}));
// Set flow control pins if necessary. Must be set all in same command.
var flags = {};
if (dtr != "none") { flags.dtr = (dtr!="low"); }
if (rts != "none") { flags.rts = (rts!="low"); }
if (cts != "none") { flags.cts = (cts!="low"); }
if (dsr != "none") { flags.dsr = (dsr!="low"); }
if (dtr != "none" || rts != "none" || cts != "none" || dsr != "none") { obj.serial.set(flags); }
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
if (obj.tout) { clearTimeout(obj.tout); obj.tout = null; }
//obj.serial.flush();
obj._emitter.emit('ready');
});
obj.serial.on('data',function(d) {
function emitData(data) {
if (active === true) {
var m = Buffer.from(data);
var last_sender = null;
if (obj.queue.length) { last_sender = obj.queue[0].sender; }
if (binoutput !== "bin") { m = m.toString(); }
var msgout = obj.dequeue() || {};
msgout.payload = m;
msgout.port = port;
obj._emitter.emit('data', msgout, last_sender);
}
active = (waitfor === "") ? true : false;
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
}
for (var z=0; z<d.length; z++) {
var c = d[z];
if (c === waitfor) { active = true; }
if (!active) { continue; }
2020-06-15 16:31:44 +02:00
// handle the trivial case first -- single char buffer
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
if ((newline === 0)||(newline === "")) {
emitData(new Buffer.from([c]));
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
continue;
}
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
// save incoming data into local buffer
buf[i] = c;
i += 1;
// do the timer thing
if (spliton === "time" || spliton === "interbyte") {
// start the timeout at the first character in case of regular timeout
// restart it at the last character of the this event in case of interbyte timeout
if ((spliton === "time" && i === 1) ||
(spliton === "interbyte" && z === d.length-1)) {
// if we had a response timeout set, clear it:
// we'll emit at least 1 character at some point anyway
if (obj.tout) {
clearTimeout(obj.tout);
obj.tout = null;
}
obj.tout = setTimeout(function () {
obj.tout = null;
emitData(buf.slice(0, i));
i=0;
}, newline);
}
}
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
// count bytes into a buffer...
else if (spliton === "count") {
newline = serialConfig.newline;
Serial request (#426) * serial: simplify serialPool.get serialPool.get() has a lot of arguments. Just pass the whole serialConfig object instead. Also introduce early termination to remove one level of indentation. (Just set your diff tool to ignore all whitespace changes to see how very little this patch changes) * serial: move splitting logic onto serialPool All SerialIn and SerialOut nodes for a given port share the same splitting logic as it is indeed set by the common configuration node. Move the code from SerialIn into serialPool so that it can be reused by the serial request node. Notice how the 'data' event will no longer carry single bytes, but the whole payload instead. Also move the output encoding logic into serialPool. * serial: add serial request node Add a "serial request" node to handle simple request/response protocols. This node allows for multiple instances, all sharing the same underlying device. Responses coming from the serial line will only be propagated to the output of the node where the request was originally received (contrary to the "serial in" nodes which all emit the data received from the serial line). Every request received as an input to the node, is transmitted to the serial line, and a matching response must be received before the next one can be transmitted. Any input message received in the meantime is internally enqueued. The node is essentially a merge of serial in and serial out. It shares the same configuration with serial in and serial out for any given port and will not affect the behavior of the existing nodes. This means you can use, alongside with the request node: - as many serial in nodes as you want -- e.g. to "sniff" - serial out to inject mailicious/tampering data onto the serial line, skipping the queueing mechanism * serial request: provide some visual feedback on the node add status indication: - yellow "waiting" when a message is enqueued for sending - green "OK" after an answer is received - red "timeout" after a timeout occurs More sofisticated output would include an indication of the number of messages enqueued and the actual timeout remaining after sending. * serial request: make default response timeout configurable Notice it's a global setting (i.e. stored in the configuration node) as opposed to per-node, but it can be overridden by setting msg.timeout. * serial request: cosmetic changes - added documentation about msg.port - timeout field made wider so to accommodate default value of 10000ms - replaced harcoded text with localizable strings for "waiting" and "timeout" messages * serial: cleanup: remove node.tout this was probably some leftover code from previous implementations. Now all timeouts are handled within the connection objects. * serial: cleanup: set obj.tout to null after clearing it clearing a Timeout without setting it back to null *might* have adverse effects on later code which would check its null-ity. Let's just do it. * serial: cosmetic: add some comments * serial request: fix "split on timeout" case In the case of "split on timeout" case, we're reusing the same .tout for two different purposes: 1) to send a timeout message, in case no answer is received at all [request] 2) to split messages, after receiving the first character [in+request] So in the case of serial request, checking whether .tout is already set is no longer a valid condition for 2). Let's just check whether i === 1, and clear the timeout set up by 1) if it's already there. * serial: add "split on silence" behavior add a fourth logic to split incoming data into messages. The existing "split on timeout" logic starts the timeout upon reception of the first character. This might lead to unwanted behavior if for instance Node-RED is restarted, as data might accumulate into OS buffers (see #410). A different logic might be to only emit a message when enough time has passed, without any new data being received (line silent), a.k.a. interbyte timeout.
2018-07-09 12:14:08 +02:00
if ( i >= parseInt(newline)) {
emitData(buf.slice(0,i));
i=0;
}
}
// look to match char...
else if (spliton === "char") {
if ((c === splitc[0]) || (i === bufMaxSize)) {
emitData(buf.slice(0,i));
i=0;
}
}
}
});
// obj.serial.on("disconnect",function() {
// RED.log.error(RED._("serial.errors.disconnected",{port:port}));
// });
}
setupSerial();
return obj;
}());
return connections[id];
},
close: function(port,done) {
if (connections[port]) {
if (connections[port].tout != null) {
clearTimeout(connections[port].tout);
}
connections[port]._closing = true;
try {
connections[port].close(function() {
2021-03-11 22:24:35 +01:00
RED.log.info(RED._("serial.errors.closed",{port:port}), {});
done();
});
}
catch(err) { }
delete connections[port];
2017-01-29 18:45:44 +01:00
}
else {
done();
}
}
}
}());
RED.httpAdmin.get("/serialports", RED.auth.needsPermission('serial.read'), function(req,res) {
2022-02-24 18:15:10 +01:00
SerialPort.list().then(
ports => {
const a = ports.map(p => p.path);
res.json(a);
},
err => {
res.json([RED._("serial.errors.list")]);
}
)
});
}