From 0513ecc26ede77cb740eb83310fe11e2baf682f4 Mon Sep 17 00:00:00 2001
From: Sathya Laufer
Date: Tue, 19 Jun 2018 18:24:40 +0200
Subject: [PATCH 1/5] Started implementing serial device nodes
---
CMakeLists.txt | 12 +
Makefile.am | 2 +-
configure.ac | 2 +-
modbus/modbus-host/MyNode.cpp | 2 +-
mqtt/mqtt-broker/MyNode.cpp | 2 +-
serial/Makefile.am | 28 ++
serial/serial-in/Factory.cpp | 42 ++
serial/serial-in/Factory.h | 44 ++
serial/serial-in/MyNode.cpp | 116 ++++++
serial/serial-in/MyNode.h | 58 +++
serial/serial-in/locales/en-US/serial-in | 11 +
serial/serial-in/serial-in.hni | 53 +++
serial/serial-out/Factory.cpp | 42 ++
serial/serial-out/Factory.h | 44 ++
serial/serial-out/MyNode.cpp | 84 ++++
serial/serial-out/MyNode.h | 54 +++
serial/serial-out/locales/en-US/serial-out | 11 +
serial/serial-out/serial-out.hni | 54 +++
serial/serial-port/Factory.cpp | 42 ++
serial/serial-port/Factory.h | 44 ++
serial/serial-port/MyNode.cpp | 404 +++++++++++++++++++
serial/serial-port/MyNode.h | 98 +++++
serial/serial-port/locales/en-US/serial-port | 43 ++
serial/serial-port/serial-port.hni | 187 +++++++++
24 files changed, 1475 insertions(+), 4 deletions(-)
create mode 100644 serial/Makefile.am
create mode 100644 serial/serial-in/Factory.cpp
create mode 100644 serial/serial-in/Factory.h
create mode 100644 serial/serial-in/MyNode.cpp
create mode 100644 serial/serial-in/MyNode.h
create mode 100644 serial/serial-in/locales/en-US/serial-in
create mode 100644 serial/serial-in/serial-in.hni
create mode 100644 serial/serial-out/Factory.cpp
create mode 100644 serial/serial-out/Factory.h
create mode 100644 serial/serial-out/MyNode.cpp
create mode 100644 serial/serial-out/MyNode.h
create mode 100644 serial/serial-out/locales/en-US/serial-out
create mode 100644 serial/serial-out/serial-out.hni
create mode 100644 serial/serial-port/Factory.cpp
create mode 100644 serial/serial-port/Factory.h
create mode 100644 serial/serial-port/MyNode.cpp
create mode 100644 serial/serial-port/MyNode.h
create mode 100644 serial/serial-port/locales/en-US/serial-port
create mode 100644 serial/serial-port/serial-port.hni
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d633dfaa..c08fe7d7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -124,6 +124,18 @@ set(SOURCE_FILES
pulsecounter/Factory.h
pulsecounter/MyNode.cpp
pulsecounter/MyNode.h
+ serial/serial-port/Factory.cpp
+ serial/serial-port/Factory.h
+ serial/serial-port/MyNode.cpp
+ serial/serial-port/MyNode.h
+ serial/serial-in/Factory.cpp
+ serial/serial-in/Factory.h
+ serial/serial-in/MyNode.cpp
+ serial/serial-in/MyNode.h
+ serial/serial-out/Factory.cpp
+ serial/serial-out/Factory.h
+ serial/serial-out/MyNode.cpp
+ serial/serial-out/MyNode.h
storage/file/Factory.cpp
storage/file/Factory.h
storage/file/MyNode.cpp
diff --git a/Makefile.am b/Makefile.am
index 87624489..3b782739 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,3 +1,3 @@
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4 -I cfg
-SUBDIRS = average basic-logic comment debug function gpio http influxdb light link modbus mqtt notification parsers passthrough ping pulsecounter press-pattern synchronous storage template timers tls-config tls-server-config variable
+SUBDIRS = average basic-logic comment debug function gpio http influxdb light link modbus mqtt notification parsers passthrough ping pulsecounter press-pattern serial synchronous storage template timers tls-config tls-server-config variable
diff --git a/configure.ac b/configure.ac
index 79331432..4df7c5a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -62,4 +62,4 @@ esac
#AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [enable debugging, default: no]), [case "${enableval}" in yes) debug=true ;; no) debug=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;; esac], [debug=false])
#AM_CONDITIONAL(DEBUG, test x"$debug" = x"true")
-AC_OUTPUT(Makefile average/Makefile basic-logic/Makefile comment/Makefile debug/Makefile function/Makefile gpio/Makefile http/Makefile influxdb/Makefile light/Makefile link/Makefile modbus/Makefile mqtt/Makefile notification/Makefile parsers/Makefile passthrough/Makefile ping/Makefile press-pattern/Makefile pulsecounter/Makefile synchronous/Makefile storage/Makefile template/Makefile timers/Makefile tls-config/Makefile tls-server-config/Makefile variable/Makefile)
+AC_OUTPUT(Makefile average/Makefile basic-logic/Makefile comment/Makefile debug/Makefile function/Makefile gpio/Makefile http/Makefile influxdb/Makefile light/Makefile link/Makefile modbus/Makefile mqtt/Makefile notification/Makefile parsers/Makefile passthrough/Makefile ping/Makefile press-pattern/Makefile pulsecounter/Makefile serial/Makefile synchronous/Makefile storage/Makefile template/Makefile timers/Makefile tls-config/Makefile tls-server-config/Makefile variable/Makefile)
diff --git a/modbus/modbus-host/MyNode.cpp b/modbus/modbus-host/MyNode.cpp
index 6d0517bd..99d4b6fa 100644
--- a/modbus/modbus-host/MyNode.cpp
+++ b/modbus/modbus-host/MyNode.cpp
@@ -334,7 +334,7 @@ Flows::PVariable MyNode::writeRegisters(Flows::PArray parameters)
{
try
{
- if(parameters->size() != 4 && parameters->size() != 6) return Flows::Variable::createError(-1, "Method expects four or sic parameters. " + std::to_string(parameters->size()) + " given.");
+ if(parameters->size() != 4 && parameters->size() != 6) return Flows::Variable::createError(-1, "Method expects four or six parameters. " + std::to_string(parameters->size()) + " given.");
if (!_modbus) return Flows::Variable::createError(-32500, "Unknown application error.");
if((Modbus::ModbusType)parameters->at(0)->integerValue == Modbus::ModbusType::tHoldingRegister && parameters->size() == 6)
diff --git a/mqtt/mqtt-broker/MyNode.cpp b/mqtt/mqtt-broker/MyNode.cpp
index 675d855e..fdcda464 100644
--- a/mqtt/mqtt-broker/MyNode.cpp
+++ b/mqtt/mqtt-broker/MyNode.cpp
@@ -201,7 +201,7 @@ Flows::PVariable MyNode::registerNode(Flows::PArray parameters)
try
{
if(parameters->size() != 1) return Flows::Variable::createError(-1, "Method expects exactly one parameter. " + std::to_string(parameters->size()) + " given.");
- if(parameters->at(0)->type != Flows::VariableType::tString) return Flows::Variable::createError(-1, "Parameter is not of type string.");
+ if(parameters->at(0)->type != Flows::VariableType::tString || parameters->at(0)->stringValue.empty()) return Flows::Variable::createError(-1, "Parameter is not of type string.");
if(_mqtt) _mqtt->registerNode(parameters->at(0)->stringValue);
diff --git a/serial/Makefile.am b/serial/Makefile.am
new file mode 100644
index 00000000..5667845d
--- /dev/null
+++ b/serial/Makefile.am
@@ -0,0 +1,28 @@
+AUTOMAKE_OPTIONS = subdir-objects
+
+AM_CPPFLAGS = -Wall -std=c++11 -DFORTIFY_SOURCE=2 -DGCRYPT_NO_DEPRECATED
+AM_LDFLAGS = -Wl,-rpath=/lib/homegear -Wl,-rpath=/usr/lib/homegear -Wl,-rpath=/usr/local/lib/homegear
+LIBS += -Wl,-Bdynamic -lhomegear-node -lhomegear-base
+
+libdir = $(localstatedir)/lib/homegear/node-blue/nodes/serial
+
+lib_LTLIBRARIES = serial-port.la serial-in.la serial-out.la
+
+serial_port_la_SOURCES = serial-port/Factory.cpp serial-port/MyNode.cpp
+serial_port_la_LDFLAGS =-module -avoid-version -shared
+
+serial_in_la_SOURCES = serial-in/Factory.cpp serial-in/MyNode.cpp
+serial_in_la_LDFLAGS =-module -avoid-version -shared
+
+serial_out_la_SOURCES = serial-out/Factory.cpp serial-out/MyNode.cpp
+serial_out_la_LDFLAGS =-module -avoid-version -shared
+
+serial_ladir = $(libdir)
+serial_la_DATA = serial-port/serial-port.hni serial-in/serial-in.hni serial-out/serial-out.hni
+locale_en_usdir = $(libdir)/locales/en-US
+locale_en_us_DATA = serial-port/locales/en-US/serial-port serial-in/locales/en-US/serial-in serial-out/locales/en-US/serial-out
+
+install-exec-hook:
+ rm -f $(DESTDIR)$(libdir)/serial-port.la
+ rm -f $(DESTDIR)$(libdir)/serial-in.la
+ rm -f $(DESTDIR)$(libdir)/serial-out.la
diff --git a/serial/serial-in/Factory.cpp b/serial/serial-in/Factory.cpp
new file mode 100644
index 00000000..6304ad24
--- /dev/null
+++ b/serial/serial-in/Factory.cpp
@@ -0,0 +1,42 @@
+/* Copyright 2013-2017 Sathya Laufer
+ *
+ * Homegear is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Homegear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Homegear. If not, see .
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "Factory.h"
+#include "MyNode.h"
+#include "../config.h"
+
+Flows::INode* MyFactory::createNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected)
+{
+ return new MyNode::MyNode(path, nodeNamespace, type, frontendConnected);
+}
+
+Flows::NodeFactory* getFactory()
+{
+ return (Flows::NodeFactory*) (new MyFactory);
+}
diff --git a/serial/serial-in/Factory.h b/serial/serial-in/Factory.h
new file mode 100644
index 00000000..6e79b886
--- /dev/null
+++ b/serial/serial-in/Factory.h
@@ -0,0 +1,44 @@
+/* Copyright 2013-2017 Sathya Laufer
+ *
+ * Homegear is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Homegear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Homegear. If not, see .
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef FACTORY_H
+#define FACTORY_H
+
+#include
+#include "MyNode.h"
+
+class MyFactory : Flows::NodeFactory
+{
+public:
+ virtual Flows::INode* createNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected);
+};
+
+extern "C" Flows::NodeFactory* getFactory();
+
+#endif
diff --git a/serial/serial-in/MyNode.cpp b/serial/serial-in/MyNode.cpp
new file mode 100644
index 00000000..8d065bf3
--- /dev/null
+++ b/serial/serial-in/MyNode.cpp
@@ -0,0 +1,116 @@
+/* Copyright 2013-2017 Sathya Laufer
+ *
+ * Homegear is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Homegear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Homegear. If not, see .
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include
+#include "MyNode.h"
+
+namespace MyNode
+{
+
+MyNode::MyNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected) : Flows::INode(path, nodeNamespace, type, frontendConnected)
+{
+ _localRpcMethods.emplace("packetReceived", std::bind(&MyNode::packetReceived, this, std::placeholders::_1));
+}
+
+MyNode::~MyNode()
+{
+}
+
+bool MyNode::init(Flows::PNodeInfo info)
+{
+ try
+ {
+ auto settingsIterator = info->info->structValue->find("server");
+ if(settingsIterator != info->info->structValue->end()) _server = settingsIterator->second->stringValue;
+
+ return true;
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+ return false;
+}
+
+void MyNode::configNodesStarted()
+{
+ try
+ {
+ if(_server.empty())
+ {
+ _out->printError("Error: This node has no Modbus server assigned.");
+ return;
+ }
+
+ Flows::PArray parameters = std::make_shared();
+ parameters->push_back(std::make_shared(_id));
+
+ Flows::PVariable result = invokeNodeMethod(_server, "registerNode", parameters, true);
+ if (result->errorStruct) _out->printError("Error: Could not register node: " + result->structValue->at("faultString")->stringValue);
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+}
+
+//{{{ RPC methods
+ Flows::PVariable MyNode::packetReceived(Flows::PArray parameters)
+ {
+ try
+ {
+ if(parameters->size() != 1) return Flows::Variable::createError(-1, "Method expects exactly one parameter. " + std::to_string(parameters->size()) + " given.");
+ if(parameters->at(0)->type != Flows::VariableType::tBinary && parameters->at(0)->type != Flows::VariableType::tString) return Flows::Variable::createError(-1, "Parameter 1 is not of type String or Binary.");
+
+ Flows::PVariable message = std::make_shared(Flows::VariableType::tStruct);
+ message->structValue->emplace("payload", parameters->at(0));
+
+ return std::make_shared();
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+ return Flows::Variable::createError(-32500, "Unknown application error.");
+ }
+//}}}
+
+}
diff --git a/serial/serial-in/MyNode.h b/serial/serial-in/MyNode.h
new file mode 100644
index 00000000..9deac0b3
--- /dev/null
+++ b/serial/serial-in/MyNode.h
@@ -0,0 +1,58 @@
+/* Copyright 2013-2017 Sathya Laufer
+ *
+ * Homegear is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Homegear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Homegear. If not, see .
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef MYNODE_H_
+#define MYNODE_H_
+
+#include
+#include
+#include
+
+namespace MyNode
+{
+
+class MyNode: public Flows::INode
+{
+public:
+ MyNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected);
+ virtual ~MyNode();
+
+ virtual bool init(Flows::PNodeInfo info);
+ virtual void configNodesStarted();
+private:
+ std::string _server;
+
+ //{{{ RPC methods
+ Flows::PVariable packetReceived(Flows::PArray parameters);
+ //}}}
+};
+
+}
+
+#endif
diff --git a/serial/serial-in/locales/en-US/serial-in b/serial/serial-in/locales/en-US/serial-in
new file mode 100644
index 00000000..d67f74f1
--- /dev/null
+++ b/serial/serial-in/locales/en-US/serial-in
@@ -0,0 +1,11 @@
+{
+ "serial/serial-in.hni": {
+ "serial-in": {
+ "help": "Reads data from a local serial port.
Can either
- wait for a \"split\" character (default \n). Also accepts hex notation (0x0d).
- Wait for a timeout in milliseconds from the first character received
- Wait to fill a fixed sized buffer
It then outputs $message['payload']
as either a UTF8 ascii string or a binary Buffer object.
msg.port
is set to the name of the port selected.
If no split character is specified, or a timeout or buffer size of 0, then a stream of single characters is sent - again either as ascii chars or size 1 binary buffers.
",
+ "label": {
+ "serialport": "Serial Port",
+ "serial": "serial"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/serial/serial-in/serial-in.hni b/serial/serial-in/serial-in.hni
new file mode 100644
index 00000000..c18aec74
--- /dev/null
+++ b/serial/serial-in/serial-in.hni
@@ -0,0 +1,53 @@
+
+
+
+
\ No newline at end of file
diff --git a/serial/serial-out/Factory.cpp b/serial/serial-out/Factory.cpp
new file mode 100644
index 00000000..6304ad24
--- /dev/null
+++ b/serial/serial-out/Factory.cpp
@@ -0,0 +1,42 @@
+/* Copyright 2013-2017 Sathya Laufer
+ *
+ * Homegear is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Homegear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Homegear. If not, see .
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "Factory.h"
+#include "MyNode.h"
+#include "../config.h"
+
+Flows::INode* MyFactory::createNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected)
+{
+ return new MyNode::MyNode(path, nodeNamespace, type, frontendConnected);
+}
+
+Flows::NodeFactory* getFactory()
+{
+ return (Flows::NodeFactory*) (new MyFactory);
+}
diff --git a/serial/serial-out/Factory.h b/serial/serial-out/Factory.h
new file mode 100644
index 00000000..6e79b886
--- /dev/null
+++ b/serial/serial-out/Factory.h
@@ -0,0 +1,44 @@
+/* Copyright 2013-2017 Sathya Laufer
+ *
+ * Homegear is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Homegear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Homegear. If not, see .
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef FACTORY_H
+#define FACTORY_H
+
+#include
+#include "MyNode.h"
+
+class MyFactory : Flows::NodeFactory
+{
+public:
+ virtual Flows::INode* createNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected);
+};
+
+extern "C" Flows::NodeFactory* getFactory();
+
+#endif
diff --git a/serial/serial-out/MyNode.cpp b/serial/serial-out/MyNode.cpp
new file mode 100644
index 00000000..384e353d
--- /dev/null
+++ b/serial/serial-out/MyNode.cpp
@@ -0,0 +1,84 @@
+/* Copyright 2013-2017 Sathya Laufer
+ *
+ * Homegear is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Homegear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Homegear. If not, see .
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "MyNode.h"
+
+namespace MyNode
+{
+
+MyNode::MyNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected) : Flows::INode(path, nodeNamespace, type, frontendConnected)
+{
+}
+
+MyNode::~MyNode()
+{
+}
+
+bool MyNode::init(Flows::PNodeInfo info)
+{
+ try
+ {
+ auto settingsIterator = info->info->structValue->find("server");
+ if(settingsIterator != info->info->structValue->end()) _server = settingsIterator->second->stringValue;
+
+ return true;
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+ return false;
+}
+
+void MyNode::input(const Flows::PNodeInfo info, uint32_t index, const Flows::PVariable message)
+{
+ try
+ {
+ Flows::PVariable payload = std::make_shared();
+ *payload = *(message->structValue->at("payload"));
+
+ Flows::PArray parameters = std::make_shared();
+ parameters->push_back(payload);
+ invokeNodeMethod(_server, "write", parameters, false);
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+}
+
+}
diff --git a/serial/serial-out/MyNode.h b/serial/serial-out/MyNode.h
new file mode 100644
index 00000000..229358c3
--- /dev/null
+++ b/serial/serial-out/MyNode.h
@@ -0,0 +1,54 @@
+/* Copyright 2013-2017 Sathya Laufer
+ *
+ * Homegear is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Homegear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Homegear. If not, see .
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef MYNODE_H_
+#define MYNODE_H_
+
+#include
+#include
+
+namespace MyNode
+{
+
+class MyNode: public Flows::INode
+{
+public:
+ MyNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected);
+ virtual ~MyNode();
+
+ virtual bool init(Flows::PNodeInfo info);
+private:
+ std::string _server;
+
+ virtual void input(const Flows::PNodeInfo info, uint32_t index, const Flows::PVariable message);
+};
+
+}
+
+#endif
diff --git a/serial/serial-out/locales/en-US/serial-out b/serial/serial-out/locales/en-US/serial-out
new file mode 100644
index 00000000..7ca5b798
--- /dev/null
+++ b/serial/serial-out/locales/en-US/serial-out
@@ -0,0 +1,11 @@
+{
+ "serial/serial-out.hni": {
+ "serial-out": {
+ "help": "Provides a connection to an outbound serial port.
Only the $message['payload']
is sent.
Optionally the new line character used to split the input can be appended to every message sent out to the serial port.
",
+ "label": {
+ "serialport": "Serial Port",
+ "serial": "serial"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/serial/serial-out/serial-out.hni b/serial/serial-out/serial-out.hni
new file mode 100644
index 00000000..ef4be02a
--- /dev/null
+++ b/serial/serial-out/serial-out.hni
@@ -0,0 +1,54 @@
+
+
+
+
\ No newline at end of file
diff --git a/serial/serial-port/Factory.cpp b/serial/serial-port/Factory.cpp
new file mode 100644
index 00000000..6304ad24
--- /dev/null
+++ b/serial/serial-port/Factory.cpp
@@ -0,0 +1,42 @@
+/* Copyright 2013-2017 Sathya Laufer
+ *
+ * Homegear is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Homegear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Homegear. If not, see .
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "Factory.h"
+#include "MyNode.h"
+#include "../config.h"
+
+Flows::INode* MyFactory::createNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected)
+{
+ return new MyNode::MyNode(path, nodeNamespace, type, frontendConnected);
+}
+
+Flows::NodeFactory* getFactory()
+{
+ return (Flows::NodeFactory*) (new MyFactory);
+}
diff --git a/serial/serial-port/Factory.h b/serial/serial-port/Factory.h
new file mode 100644
index 00000000..6e79b886
--- /dev/null
+++ b/serial/serial-port/Factory.h
@@ -0,0 +1,44 @@
+/* Copyright 2013-2017 Sathya Laufer
+ *
+ * Homegear is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Homegear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Homegear. If not, see .
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef FACTORY_H
+#define FACTORY_H
+
+#include
+#include "MyNode.h"
+
+class MyFactory : Flows::NodeFactory
+{
+public:
+ virtual Flows::INode* createNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected);
+};
+
+extern "C" Flows::NodeFactory* getFactory();
+
+#endif
diff --git a/serial/serial-port/MyNode.cpp b/serial/serial-port/MyNode.cpp
new file mode 100644
index 00000000..f64327cc
--- /dev/null
+++ b/serial/serial-port/MyNode.cpp
@@ -0,0 +1,404 @@
+/* Copyright 2013-2017 Sathya Laufer
+ *
+ * Homegear is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Homegear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Homegear. If not, see .
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "MyNode.h"
+
+namespace MyNode
+{
+
+MyNode::MyNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected) : Flows::INode(path, nodeNamespace, type, frontendConnected)
+{
+ _stopThread = false;
+
+ _bl = std::make_shared();
+
+ _localRpcMethods.emplace("registerNode", std::bind(&MyNode::registerNode, this, std::placeholders::_1));
+ _localRpcMethods.emplace("write", std::bind(&MyNode::write, this, std::placeholders::_1));
+}
+
+MyNode::~MyNode()
+{
+}
+
+bool MyNode::init(Flows::PNodeInfo info)
+{
+ try
+ {
+ _nodeInfo = info;
+ return true;
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+ return false;
+}
+
+bool MyNode::start()
+{
+ try
+ {
+ auto settingsIterator = _nodeInfo->info->structValue->find("serialport");
+ if(settingsIterator != _nodeInfo->info->structValue->end()) _serialPort = settingsIterator->second->stringValue;
+
+ if(_serialPort.empty())
+ {
+ _out->printError("Error: No serial device specified.");
+ return false;
+ }
+
+ settingsIterator = _nodeInfo->info->structValue->find("serialbaud");
+ if(settingsIterator != _nodeInfo->info->structValue->end()) _baudRate = Flows::Math::getNumber(settingsIterator->second->stringValue);
+
+ if(_baudRate <= 0)
+ {
+ _out->printError("Error: Invalid baudrate specified.");
+ return false;
+ }
+
+ settingsIterator = _nodeInfo->info->structValue->find("databits");
+ if(settingsIterator != _nodeInfo->info->structValue->end())
+ {
+ int32_t bits = Flows::Math::getNumber(settingsIterator->second->stringValue);
+
+ if(bits == 8) _dataBits = BaseLib::SerialReaderWriter::CharacterSize::Eight;
+ else if(bits == 7) _dataBits = BaseLib::SerialReaderWriter::CharacterSize::Seven;
+ else if(bits == 6) _dataBits = BaseLib::SerialReaderWriter::CharacterSize::Six;
+ else if(bits == 5) _dataBits = BaseLib::SerialReaderWriter::CharacterSize::Five;
+ else
+ {
+ _out->printError("Error: Invalid character size specified.");
+ return false;
+ }
+ }
+
+ settingsIterator = _nodeInfo->info->structValue->find("parity");
+ if(settingsIterator != _nodeInfo->info->structValue->end())
+ {
+ _evenParity = false;
+ _oddParity = false;
+ _evenParity = (settingsIterator->second->stringValue == "even");
+ _oddParity = (settingsIterator->second->stringValue == "odd");
+ }
+
+ settingsIterator = _nodeInfo->info->structValue->find("stopbits");
+ if(settingsIterator != _nodeInfo->info->structValue->end()) _stopBits = Flows::Math::getNumber(settingsIterator->second->stringValue);
+
+ settingsIterator = _nodeInfo->info->structValue->find("newline");
+ if(settingsIterator != _nodeInfo->info->structValue->end())
+ {
+ _newLine = settingsIterator->second->stringValue.empty() ? '\n' : settingsIterator->second->stringValue.front();
+ _timeout = Flows::Math::getNumber(settingsIterator->second->stringValue);
+ if(_timeout < 0) _timeout = 1;
+ else if(_timeout > 5000) _timeout = 5000;
+ _fixedCount = Flows::Math::getNumber(settingsIterator->second->stringValue);
+ if(_fixedCount < 1) _fixedCount = 1;
+ }
+
+ settingsIterator = _nodeInfo->info->structValue->find("bin");
+ if(settingsIterator != _nodeInfo->info->structValue->end()) _binaryOutput = settingsIterator->second->booleanValue;
+
+ settingsIterator = _nodeInfo->info->structValue->find("out");
+ if(settingsIterator != _nodeInfo->info->structValue->end())
+ {
+ std::string& splitType = settingsIterator->second->stringValue;
+ if(splitType == "no") _splitType = SplitType::no;
+ else if(splitType == "char") _splitType = SplitType::character;
+ else if(splitType == "time") _splitType = SplitType::timeout;
+ else if(splitType == "count") _splitType = SplitType::fixedLength;
+ }
+
+ settingsIterator = _nodeInfo->info->structValue->find("addchar");
+ if(settingsIterator != _nodeInfo->info->structValue->end()) _addCharacter = settingsIterator->second->booleanValue;
+
+ _serial = std::make_shared(_bl.get(), _serialPort, _baudRate, 0, true, -1);
+ reopen();
+
+ _stopThread = false;
+ _bl->threadManager.start(_readThread, true, &MyNode::listenThread, this);
+
+ return true;
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+ return false;
+}
+
+void MyNode::stop()
+{
+ try
+ {
+ _stopThread = true;
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+}
+
+void MyNode::waitForStop()
+{
+ try
+ {
+ _stopThread = true;
+ _bl->threadManager.join(_readThread);
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+}
+
+Flows::PVariable MyNode::getConfigParameterIncoming(std::string name)
+{
+ try
+ {
+ auto settingsIterator = _nodeInfo->info->structValue->find(name);
+ if(settingsIterator != _nodeInfo->info->structValue->end()) return settingsIterator->second;
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+ return std::make_shared();
+}
+
+void MyNode::reopen()
+{
+ try
+ {
+ _serial->closeDevice();
+ _serial->openDevice(_evenParity, _oddParity, false, _dataBits, _stopBits == 2);
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+}
+
+void MyNode::packetReceived(Flows::PVariable data)
+{
+ try
+ {
+ Flows::PArray parameters = std::make_shared();
+ parameters->push_back(data);
+ std::lock_guard nodesGuard(_nodesMutex);
+ for (auto& node : _nodes)
+ {
+ invokeNodeMethod(node, "packetReceived", parameters, false);
+ }
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+}
+
+void MyNode::listenThread()
+{
+ while(!_stopThread)
+ {
+ try
+ {
+ int32_t readBytes = 0;
+ if(_splitType == SplitType::character)
+ {
+ std::string data;
+ readBytes = _serial->readLine(data);
+
+ if(readBytes > 0)
+ {
+ if(_binaryOutput)
+ {
+ std::vector buffer(data.begin(), data.end());
+ packetReceived(std::make_shared(buffer));
+ }
+ else packetReceived(std::make_shared(std::move(data)));
+ }
+ }
+ else if(_splitType == SplitType::no)
+ {
+ char data;
+ readBytes = _serial->readChar(data);
+
+ if(readBytes > 0)
+ {
+ if(_binaryOutput)
+ {
+ std::vector buffer{data};
+ packetReceived(std::make_shared(buffer));
+ }
+ else packetReceived(std::make_shared(std::string{data}));
+ }
+ }
+ else if(_splitType == SplitType::timeout)
+ {
+ std::vector buffer;
+ buffer.reserve(1024);
+ char data;
+ readBytes = 1;
+ while(readBytes > 0)
+ {
+ readBytes = _serial->readChar(data, _timeout);
+ if(readBytes > 0)
+ {
+ if(buffer.size() + 1 > buffer.capacity()) buffer.reserve(buffer.capacity() + 1024);
+ buffer.push_back(data);
+ }
+ }
+
+ if(readBytes > 0)
+ {
+ if(_binaryOutput) packetReceived(std::make_shared(buffer));
+ else packetReceived(std::make_shared(std::string(buffer.begin(), buffer.end())));
+ }
+ }
+ else if(_splitType == SplitType::fixedLength)
+ {
+ std::vector buffer(_dataBuffer.begin(), _dataBuffer.end());
+ buffer.reserve(1024);
+ char data;
+ readBytes = 1;
+ while(readBytes > 0)
+ {
+ readBytes = _serial->readChar(data);
+ if(readBytes > 0)
+ {
+ if(buffer.size() + 1 > buffer.capacity()) buffer.reserve(buffer.capacity() + 1024);
+ buffer.push_back(data);
+
+ if(buffer.size() >= (unsigned)_fixedCount)
+ {
+ if(_binaryOutput) packetReceived(std::make_shared(buffer));
+ else packetReceived(std::make_shared(std::string(buffer.begin(), buffer.end())));
+ }
+ }
+ else if(readBytes == 0)
+ {
+ _dataBuffer.clear();
+ _dataBuffer.insert(_dataBuffer.end(), buffer.begin(), buffer.end());
+ }
+ }
+ }
+
+ if(readBytes == -1) reopen();
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+ }
+}
+
+//{{{ RPC methods
+Flows::PVariable MyNode::registerNode(Flows::PArray parameters)
+{
+ try
+ {
+ if(parameters->size() != 1) return Flows::Variable::createError(-1, "Method expects exactly one parameter. " + std::to_string(parameters->size()) + " given.");
+ if(parameters->at(0)->type != Flows::VariableType::tString || parameters->at(0)->stringValue.empty()) return Flows::Variable::createError(-1, "Parameter is not of type string.");
+
+ std::lock_guard nodesGuard(_nodesMutex);
+ _nodes.emplace(parameters->at(0)->stringValue);
+
+ return std::make_shared();
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+ return Flows::Variable::createError(-32500, "Unknown application error.");
+}
+
+Flows::PVariable MyNode::write(Flows::PArray parameters)
+{
+ try
+ {
+ if(parameters->size() != 1) return Flows::Variable::createError(-1, "Method expects exactly one parameter.");
+ if(parameters->at(0)->type != Flows::VariableType::tString && parameters->at(0)->type != Flows::VariableType::tBinary) return Flows::Variable::createError(-1, "Parameter is not of type Binary or String.");
+ if(parameters->at(0)->binaryValue.empty() && parameters->at(0)->stringValue.empty()) return Flows::Variable::createError(-1, "No data given.");
+
+
+ if(parameters->at(0)->type == Flows::VariableType::tString) parameters->at(0)->binaryValue.insert(parameters->at(0)->binaryValue.end(), parameters->at(0)->stringValue.begin(), parameters->at(0)->stringValue.end());
+ if(_addCharacter && _splitType == SplitType::character) parameters->at(0)->binaryValue.push_back(_newLine);
+ _serial->writeData(parameters->at(0)->binaryValue);
+
+ return std::make_shared();
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+ return Flows::Variable::createError(-32500, "Unknown application error.");
+}
+//}}}
+
+}
diff --git a/serial/serial-port/MyNode.h b/serial/serial-port/MyNode.h
new file mode 100644
index 00000000..fa74ca84
--- /dev/null
+++ b/serial/serial-port/MyNode.h
@@ -0,0 +1,98 @@
+/* Copyright 2013-2017 Sathya Laufer
+ *
+ * Homegear is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Homegear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Homegear. If not, see .
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef MYNODE_H_
+#define MYNODE_H_
+
+#include
+#include
+
+namespace MyNode
+{
+
+class MyNode: public Flows::INode
+{
+public:
+ MyNode(std::string path, std::string nodeNamespace, std::string type, const std::atomic_bool* frontendConnected);
+ virtual ~MyNode();
+
+ virtual bool init(Flows::PNodeInfo info);
+ virtual bool start();
+ virtual void stop();
+ virtual void waitForStop();
+
+ virtual Flows::PVariable getConfigParameterIncoming(std::string name);
+private:
+ enum class SplitType
+ {
+ no,
+ character,
+ timeout,
+ fixedLength
+ };
+
+ Flows::PNodeInfo _nodeInfo;
+
+ std::mutex _nodesMutex;
+ std::set _nodes;
+
+ std::shared_ptr _bl;
+ std::shared_ptr _serial;
+ std::atomic_bool _stopThread;
+ std::thread _readThread;
+ std::vector _dataBuffer;
+
+ //{{{ Settings
+ std::string _serialPort;
+ int32_t _baudRate = 57600;
+ BaseLib::SerialReaderWriter::CharacterSize _dataBits = BaseLib::SerialReaderWriter::CharacterSize::Eight;
+ bool _evenParity = false;
+ bool _oddParity = false;
+ int32_t _stopBits = 1;
+ char _newLine = '\n';
+ int32_t _timeout = 0;
+ int32_t _fixedCount = 1;
+ bool _binaryOutput = true;
+ SplitType _splitType;
+ bool _addCharacter = false;
+ //}}}
+
+ void listenThread();
+ void reopen();
+ void packetReceived(Flows::PVariable data);
+
+ //{{{ RPC methods
+ Flows::PVariable registerNode(Flows::PArray parameters);
+ Flows::PVariable write(Flows::PArray parameters);
+ //}}}
+};
+
+}
+
+#endif
diff --git a/serial/serial-port/locales/en-US/serial-port b/serial/serial-port/locales/en-US/serial-port
new file mode 100644
index 00000000..d86fdabf
--- /dev/null
+++ b/serial/serial-port/locales/en-US/serial-port
@@ -0,0 +1,43 @@
+{
+ "serial/serial-port.hni": {
+ "serial-port": {
+ "help": "Provides configuration options for a serial port.
The search button should return a list of available serial ports to choose from, or you can type in the location if known.
The input can be split on a fixed character, after a timeout, or after a fixed number of characters.
If using a character, it can be specified as either the character, the escaped shortcut (e.g. \n), or the hex code (e.g. 0x0d).
",
+ "label": {
+ "serialport": "Serial Port",
+ "settings": "Settings",
+ "baudrate": "Baud Rate",
+ "databits": "Data Bits",
+ "parity": "Parity",
+ "stopbits": "Stop Bits",
+ "input": "Input",
+ "split": "Split input",
+ "deliver": "and deliver",
+ "output": "Output",
+ "none": "none"
+ },
+ "placeholder": {
+ "serialport": "for example: /dev/ttyUSB0/"
+ },
+ "parity": {
+ "none": "None",
+ "even": "Even",
+ "odd": "Odd"
+ },
+ "split": {
+ "no": "no",
+ "character": "on the character",
+ "timeout": "after a timeout of",
+ "lengths": "into fixed lengths of"
+ },
+ "output": {
+ "ascii": "ascii strings",
+ "binary": "binary buffers"
+ },
+ "addsplit": "add split character to output messages",
+ "tip": {
+ "split": "Tip: the \"Split on\" character is used to split the input into separate messages. It can also be added to every message sent out to the serial port.",
+ "timeout": "Tip: In timeout mode timeout starts from arrival of first character."
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/serial/serial-port/serial-port.hni b/serial/serial-port/serial-port.hni
new file mode 100644
index 00000000..4a101c81
--- /dev/null
+++ b/serial/serial-port/serial-port.hni
@@ -0,0 +1,187 @@
+
+
+
+
\ No newline at end of file
From 6c571599d2ee54617e61647e5f99074f3e7d5521 Mon Sep 17 00:00:00 2001
From: Sathya Laufer
Date: Wed, 20 Jun 2018 00:37:53 +0200
Subject: [PATCH 2/5] Fixes to serial-port
---
serial/serial-port/MyNode.cpp | 36 ++++++++++++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/serial/serial-port/MyNode.cpp b/serial/serial-port/MyNode.cpp
index f64327cc..7c3c2151 100644
--- a/serial/serial-port/MyNode.cpp
+++ b/serial/serial-port/MyNode.cpp
@@ -117,7 +117,41 @@ bool MyNode::start()
settingsIterator = _nodeInfo->info->structValue->find("newline");
if(settingsIterator != _nodeInfo->info->structValue->end())
{
- _newLine = settingsIterator->second->stringValue.empty() ? '\n' : settingsIterator->second->stringValue.front();
+ if(settingsIterator->second->stringValue.empty())
+ {
+ _newLine = '\n';
+ }
+ else
+ {
+ if(settingsIterator->second->stringValue.size() > 1 && Flows::Math::isNumber(settingsIterator->second->stringValue, true))
+ {
+ _newLine = (char)(uint8_t)Flows::Math::getNumber(settingsIterator->second->stringValue, true);
+ }
+ else if(settingsIterator->second->stringValue.size() == 2)
+ {
+ switch(settingsIterator->second->stringValue.at(1))
+ {
+ case 'b':
+ _newLine = '\b';
+ break;
+ case 'f':
+ _newLine = '\f';
+ break;
+ case 'n':
+ _newLine = '\n';
+ break;
+ case 'r':
+ _newLine = '\r';
+ break;
+ case 't':
+ _newLine = '\t';
+ break;
+ default:
+ _newLine = settingsIterator->second->stringValue.front();
+ }
+ }
+ else _newLine = settingsIterator->second->stringValue.front();
+ }
_timeout = Flows::Math::getNumber(settingsIterator->second->stringValue);
if(_timeout < 0) _timeout = 1;
else if(_timeout > 5000) _timeout = 5000;
From 7596dd21d16320678e20395ed6dc641ffe01a6f5 Mon Sep 17 00:00:00 2001
From: Sathya Laufer
Date: Wed, 20 Jun 2018 18:44:44 +0200
Subject: [PATCH 3/5] Finished first working version of serial node
---
serial/serial-in/MyNode.cpp | 4 ++-
serial/serial-out/MyNode.cpp | 3 ++-
serial/serial-port/MyNode.cpp | 28 ++++++++++----------
serial/serial-port/locales/en-US/serial-port | 2 +-
4 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/serial/serial-in/MyNode.cpp b/serial/serial-in/MyNode.cpp
index 8d065bf3..22808fab 100644
--- a/serial/serial-in/MyNode.cpp
+++ b/serial/serial-in/MyNode.cpp
@@ -46,7 +46,7 @@ bool MyNode::init(Flows::PNodeInfo info)
{
try
{
- auto settingsIterator = info->info->structValue->find("server");
+ auto settingsIterator = info->info->structValue->find("serial");
if(settingsIterator != info->info->structValue->end()) _server = settingsIterator->second->stringValue;
return true;
@@ -99,6 +99,8 @@ void MyNode::configNodesStarted()
Flows::PVariable message = std::make_shared(Flows::VariableType::tStruct);
message->structValue->emplace("payload", parameters->at(0));
+ output(0, message);
+
return std::make_shared();
}
catch(const std::exception& ex)
diff --git a/serial/serial-out/MyNode.cpp b/serial/serial-out/MyNode.cpp
index 384e353d..aded94ef 100644
--- a/serial/serial-out/MyNode.cpp
+++ b/serial/serial-out/MyNode.cpp
@@ -44,7 +44,7 @@ bool MyNode::init(Flows::PNodeInfo info)
{
try
{
- auto settingsIterator = info->info->structValue->find("server");
+ auto settingsIterator = info->info->structValue->find("serial");
if(settingsIterator != info->info->structValue->end()) _server = settingsIterator->second->stringValue;
return true;
@@ -69,6 +69,7 @@ void MyNode::input(const Flows::PNodeInfo info, uint32_t index, const Flows::PVa
Flows::PArray parameters = std::make_shared();
parameters->push_back(payload);
+
invokeNodeMethod(_server, "write", parameters, false);
}
catch(const std::exception& ex)
diff --git a/serial/serial-port/MyNode.cpp b/serial/serial-port/MyNode.cpp
index 7c3c2151..a6e1e34c 100644
--- a/serial/serial-port/MyNode.cpp
+++ b/serial/serial-port/MyNode.cpp
@@ -294,16 +294,16 @@ void MyNode::listenThread()
if(_splitType == SplitType::character)
{
std::string data;
- readBytes = _serial->readLine(data);
+ readBytes = _serial->readLine(data, 500000, _newLine);
- if(readBytes > 0)
+ if(readBytes == 0)
{
if(_binaryOutput)
{
std::vector buffer(data.begin(), data.end());
packetReceived(std::make_shared(buffer));
}
- else packetReceived(std::make_shared(std::move(data)));
+ else packetReceived(std::make_shared(BaseLib::HelperFunctions::getHexString(data)));
}
}
else if(_splitType == SplitType::no)
@@ -311,14 +311,14 @@ void MyNode::listenThread()
char data;
readBytes = _serial->readChar(data);
- if(readBytes > 0)
+ if(readBytes == 0)
{
if(_binaryOutput)
{
std::vector buffer{data};
packetReceived(std::make_shared(buffer));
}
- else packetReceived(std::make_shared(std::string{data}));
+ else packetReceived(std::make_shared(BaseLib::HelperFunctions::getHexString(std::string{data})));
}
}
else if(_splitType == SplitType::timeout)
@@ -326,21 +326,21 @@ void MyNode::listenThread()
std::vector buffer;
buffer.reserve(1024);
char data;
- readBytes = 1;
- while(readBytes > 0)
+ readBytes = 0;
+ while(readBytes == 0)
{
- readBytes = _serial->readChar(data, _timeout);
- if(readBytes > 0)
+ readBytes = _serial->readChar(data, _timeout * 1000);
+ if(readBytes == 0)
{
if(buffer.size() + 1 > buffer.capacity()) buffer.reserve(buffer.capacity() + 1024);
buffer.push_back(data);
}
}
- if(readBytes > 0)
+ if(!buffer.empty())
{
if(_binaryOutput) packetReceived(std::make_shared(buffer));
- else packetReceived(std::make_shared(std::string(buffer.begin(), buffer.end())));
+ else packetReceived(std::make_shared(BaseLib::HelperFunctions::getHexString(buffer)));
}
}
else if(_splitType == SplitType::fixedLength)
@@ -352,7 +352,7 @@ void MyNode::listenThread()
while(readBytes > 0)
{
readBytes = _serial->readChar(data);
- if(readBytes > 0)
+ if(readBytes == 0)
{
if(buffer.size() + 1 > buffer.capacity()) buffer.reserve(buffer.capacity() + 1024);
buffer.push_back(data);
@@ -360,10 +360,10 @@ void MyNode::listenThread()
if(buffer.size() >= (unsigned)_fixedCount)
{
if(_binaryOutput) packetReceived(std::make_shared(buffer));
- else packetReceived(std::make_shared(std::string(buffer.begin(), buffer.end())));
+ else packetReceived(std::make_shared(BaseLib::HelperFunctions::getHexString(buffer)));
}
}
- else if(readBytes == 0)
+ else if(readBytes == 1)
{
_dataBuffer.clear();
_dataBuffer.insert(_dataBuffer.end(), buffer.begin(), buffer.end());
diff --git a/serial/serial-port/locales/en-US/serial-port b/serial/serial-port/locales/en-US/serial-port
index d86fdabf..f348937b 100644
--- a/serial/serial-port/locales/en-US/serial-port
+++ b/serial/serial-port/locales/en-US/serial-port
@@ -1,7 +1,7 @@
{
"serial/serial-port.hni": {
"serial-port": {
- "help": "Provides configuration options for a serial port.
The search button should return a list of available serial ports to choose from, or you can type in the location if known.
The input can be split on a fixed character, after a timeout, or after a fixed number of characters.
If using a character, it can be specified as either the character, the escaped shortcut (e.g. \n), or the hex code (e.g. 0x0d).
",
+ "help": "Provides configuration options for a serial port.
The input can be split on a fixed character, after a timeout, or after a fixed number of characters.
If using a character, it can be specified as either the character, the escaped shortcut (e.g. \n), or the hex code (e.g. 0x0d).
",
"label": {
"serialport": "Serial Port",
"settings": "Settings",
From cdfc705847af4bdef4e5dbc777835162c9b47233 Mon Sep 17 00:00:00 2001
From: Sathya Laufer
Date: Wed, 20 Jun 2018 20:30:35 +0200
Subject: [PATCH 4/5] Added help texts to serial nodes
---
serial/serial-out/locales/en-US/serial-out | 1 +
serial/serial-out/serial-out.hni | 5 +++++
2 files changed, 6 insertions(+)
diff --git a/serial/serial-out/locales/en-US/serial-out b/serial/serial-out/locales/en-US/serial-out
index 7ca5b798..cf71b4f5 100644
--- a/serial/serial-out/locales/en-US/serial-out
+++ b/serial/serial-out/locales/en-US/serial-out
@@ -2,6 +2,7 @@
"serial/serial-out.hni": {
"serial-out": {
"help": "Provides a connection to an outbound serial port.
Only the $message['payload']
is sent.
Optionally the new line character used to split the input can be appended to every message sent out to the serial port.
",
+ "input1Description": "A binary input. The type of the binary data can be string
though, too. Note that hexadecimal input is not converted to it's binary equivalent.",
"label": {
"serialport": "Serial Port",
"serial": "serial"
diff --git a/serial/serial-out/serial-out.hni b/serial/serial-out/serial-out.hni
index ef4be02a..1a1d6d9e 100644
--- a/serial/serial-out/serial-out.hni
+++ b/serial/serial-out/serial-out.hni
@@ -39,6 +39,11 @@
},
color:"BurlyWood",
inputs:1,
+ inputInfo: [
+ {
+ types: ["binary"]
+ }
+ ],
outputs:0,
icon: "serial.png",
align: "right",
From 58e06180260c91336174624d46c023742a682f50 Mon Sep 17 00:00:00 2001
From: Sathya Laufer
Date: Fri, 22 Jun 2018 00:54:58 +0200
Subject: [PATCH 5/5] Fixed: contant node does not output float values for
numbers without decimal places
---
variable/constant/MyNode.cpp | 42 ++++++++++++++++++++++++++++------
variable/constant/MyNode.h | 2 ++
variable/constant/constant.hni | 2 +-
3 files changed, 38 insertions(+), 8 deletions(-)
diff --git a/variable/constant/MyNode.cpp b/variable/constant/MyNode.cpp
index a140bb29..be15c6db 100644
--- a/variable/constant/MyNode.cpp
+++ b/variable/constant/MyNode.cpp
@@ -44,40 +44,40 @@ bool MyNode::init(Flows::PNodeInfo info)
{
try
{
- std::string payloadType = "int";
+ _payloadType = "int";
auto settingsIterator = info->info->structValue->find("payloadType");
- if(settingsIterator != info->info->structValue->end()) payloadType = settingsIterator->second->stringValue;
+ if(settingsIterator != info->info->structValue->end()) _payloadType = settingsIterator->second->stringValue;
std::string payload;
settingsIterator = info->info->structValue->find("payload");
if(settingsIterator != info->info->structValue->end()) payload = settingsIterator->second->stringValue;
_value = std::make_shared();
- if(payloadType == "bool")
+ if(_payloadType == "bool")
{
_value->setType(Flows::VariableType::tBoolean);
_value->booleanValue = payload == "true";
}
- else if(payloadType == "int")
+ else if(_payloadType == "int")
{
_value->setType(Flows::VariableType::tInteger64);
_value->integerValue64 = Flows::Math::getNumber64(payload);
_value->integerValue = (int32_t)_value->integerValue64;
_value->floatValue = _value->integerValue64;
}
- else if(payloadType == "float")
+ else if(_payloadType == "float")
{
_value->setType(Flows::VariableType::tFloat);
_value->floatValue = Flows::Math::getDouble(payload);
_value->integerValue = _value->floatValue;
_value->integerValue64 = _value->floatValue;
}
- else if(payloadType == "string")
+ else if(_payloadType == "string")
{
_value->setType(Flows::VariableType::tString);
_value->stringValue = payload;
}
- else if(payloadType == "array" || payloadType == "struct")
+ else if(_payloadType == "array" || _payloadType == "struct")
{
Flows::JsonDecoder jsonDecoder;
_value = jsonDecoder.decode(payload);
@@ -121,4 +121,32 @@ void MyNode::startUpComplete()
}
}
+void MyNode::setNodeVariable(std::string variable, Flows::PVariable value)
+{
+ try
+ {
+ if(variable == "nodeOutput" && value)
+ {
+ if(_payloadType == "float" && value->type != Flows::VariableType::tFloat)
+ {
+ value->type = Flows::VariableType::tFloat;
+ value->floatValue = value->integerValue64;
+ }
+
+ Flows::PVariable message = std::make_shared(Flows::VariableType::tStruct);
+ message->structValue->emplace("payload", value);
+
+ output(0, message);
+ }
+ }
+ catch(const std::exception& ex)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what());
+ }
+ catch(...)
+ {
+ _out->printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ }
+}
+
}
diff --git a/variable/constant/MyNode.h b/variable/constant/MyNode.h
index ea28e8b2..91a6dc7f 100644
--- a/variable/constant/MyNode.h
+++ b/variable/constant/MyNode.h
@@ -44,8 +44,10 @@ class MyNode: public Flows::INode
virtual bool init(Flows::PNodeInfo info);
virtual void startUpComplete();
+ virtual void setNodeVariable(std::string variable, Flows::PVariable value);
private:
bool _outputOnStartup = true;
+ std::string _payloadType;
Flows::PVariable _value;
};
diff --git a/variable/constant/constant.hni b/variable/constant/constant.hni
index 75b46972..15f07786 100644
--- a/variable/constant/constant.hni
+++ b/variable/constant/constant.hni
@@ -85,7 +85,7 @@
else if (this.payloadType == 'float') value = parseFloat(this.payload);
else if (this.payloadType == 'array' || this.payloadType == 'struct') value = JSON.parse(this.payload);
else value = this.payload;
- RED.comms.homegear().invoke("nodeOutput", null, this.id, 0, {'payload': value});
+ RED.comms.homegear().invoke('setNodeVariable', null, this.id, "nodeOutput", value);
}
}
});