abstract from knxd
This commit is contained in:
+18
-7
@@ -103,14 +103,24 @@ if(HAVE_MQTT)
|
||||
endif(mqtt STREQUAL ON)
|
||||
endif(HAVE_MQTT)
|
||||
|
||||
find_library(HAVE_KNX eibclient)
|
||||
option(knx "disable support for KNX handling." ON)
|
||||
if(knx STREQUAL ON)
|
||||
message(STATUS "KNX enabled")
|
||||
set(HAVE_KNX 1)
|
||||
else(knx STREQUAL ON)
|
||||
unset(HAVE_KNX)
|
||||
endif(knx STREQUAL ON)
|
||||
|
||||
if(HAVE_KNX)
|
||||
option(knx "disable support for KNX handling." ON)
|
||||
if(knx STREQUAL ON)
|
||||
message(STATUS "KNX enabled")
|
||||
else(knx STREQUAL ON)
|
||||
unset(HAVE_KNX)
|
||||
endif(knx STREQUAL ON)
|
||||
find_library(HAVE_KNXD eibclient)
|
||||
if(HAVE_KNXD)
|
||||
option(knxd "enable support for KNX handling via knxd." OFF)
|
||||
if(knxd STREQUAL ON)
|
||||
message(STATUS "KNX via knxd enabled")
|
||||
else(knxd STREQUAL ON)
|
||||
set(HAVE_KNXD 0)
|
||||
endif(knxd STREQUAL ON)
|
||||
endif(HAVE_KNXD)
|
||||
endif(HAVE_KNX)
|
||||
|
||||
find_library(HAVE_SSL ssl)
|
||||
@@ -169,6 +179,7 @@ endif(BUILD_TESTING)
|
||||
add_subdirectory(src/ebusd)
|
||||
add_subdirectory(src/lib/utils)
|
||||
add_subdirectory(src/lib/ebus)
|
||||
add_subdirectory(src/lib/knx)
|
||||
add_subdirectory(src/tools)
|
||||
|
||||
if(EXISTS "${ROOT}/etc/debian_version")
|
||||
|
||||
+7
-1
@@ -2,7 +2,13 @@ ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = docs \
|
||||
src/lib/utils \
|
||||
src/lib/ebus \
|
||||
src/lib/ebus
|
||||
|
||||
if KNX
|
||||
SUBDIRS += src/lib/knx
|
||||
endif
|
||||
|
||||
SUBDIRS += \
|
||||
src/ebusd \
|
||||
src/tools
|
||||
|
||||
|
||||
+4
-1
@@ -7,9 +7,12 @@
|
||||
/* Defined if MQTT handling is enabled. */
|
||||
#cmakedefine HAVE_MQTT
|
||||
|
||||
/* Defined if KNX is enabled. */
|
||||
/* Defined if KNX handling is enabled. */
|
||||
#cmakedefine HAVE_KNX
|
||||
|
||||
/* Defined if KNX handling via knxd is enabled. */
|
||||
#cmakedefine HAVE_KNXD
|
||||
|
||||
/* Defined if SSL is enabled. */
|
||||
#cmakedefine HAVE_SSL
|
||||
|
||||
|
||||
+13
-5
@@ -65,13 +65,18 @@ AM_CONDITIONAL([MQTT], [test "x$with_mqtt" != "xno"])
|
||||
|
||||
AC_ARG_WITH(knx, AS_HELP_STRING([--without-knx], [disable support for KNX handling]), [], [with_knx=yes])
|
||||
if test "x$with_knx" != "xno"; then
|
||||
AC_CHECK_LIB([eibclient], [EIBSocketURL],
|
||||
[AC_DEFINE_UNQUOTED(HAVE_KNX, [1], [Defined if KNX handling is enabled.])
|
||||
EXTRA_LIBS+=" -leibclient"],
|
||||
[AC_MSG_RESULT([Could not find EIBSocketURL in libeibclient.])
|
||||
with_knx="no"])
|
||||
AC_DEFINE_UNQUOTED(HAVE_KNX, [1], [Defined if KNX handling is enabled.])
|
||||
AC_ARG_WITH(knxd, AS_HELP_STRING([--with-knxd], [enable support for KNX handling via knxd]), [
|
||||
AS_IF([test "x$with_knxd" == "xyes"],
|
||||
[AC_CHECK_LIB([eibclient], [EIBSocketURL],
|
||||
[AC_DEFINE_UNQUOTED(HAVE_KNXD, [1], [Defined if KNX handling via knxd is enabled.])],
|
||||
[AC_MSG_RESULT([Could not find EIBSocketURL in libeibclient.])
|
||||
with_knxd="no"])
|
||||
])
|
||||
], [])
|
||||
fi
|
||||
AM_CONDITIONAL([KNX], [test "x$with_knx" != "xno"])
|
||||
AM_CONDITIONAL([KNXD], [test "x$with_knxd" == "xyes"])
|
||||
|
||||
AC_ARG_WITH(ssl, AS_HELP_STRING([--without-ssl], [disable support for SSL]), [], [with_ssl=yes])
|
||||
if test "x$with_ssl" != "xno"; then
|
||||
@@ -141,6 +146,9 @@ AM_COND_IF([CONTRIB], [AC_CONFIG_FILES([
|
||||
src/lib/ebus/contrib/Makefile
|
||||
src/lib/ebus/contrib/test/Makefile
|
||||
])])
|
||||
AM_COND_IF([KNX], [AC_CONFIG_FILES([
|
||||
src/lib/knx/Makefile
|
||||
])])
|
||||
|
||||
AC_DEFINE_UNQUOTED(PACKAGE_PIDFILE, LOCALSTATEDIR "/run/" PACKAGE ".pid", [The path and name of the PID file.])
|
||||
AC_DEFINE_UNQUOTED(PACKAGE_LOGFILE, LOCALSTATEDIR "/log/" PACKAGE ".log", [The path and name of the log file.])
|
||||
|
||||
@@ -15,7 +15,8 @@ endif(HAVE_MQTT)
|
||||
|
||||
if(HAVE_KNX)
|
||||
set(ebusd_SOURCES ${ebusd_SOURCES} knxhandler.cpp knxhandler.h)
|
||||
set(ebusd_LIBS ${ebusd_LIBS} eibclient)
|
||||
set(ebusd_LIBS ${ebusd_LIBS} knx)
|
||||
include_directories(../lib/knx)
|
||||
endif(HAVE_KNX)
|
||||
|
||||
if(HAVE_SSL)
|
||||
|
||||
@@ -16,15 +16,17 @@ ebusd_SOURCES = \
|
||||
if MQTT
|
||||
ebusd_SOURCES += mqtthandler.cpp mqtthandler.h
|
||||
endif
|
||||
if KNX
|
||||
ebusd_SOURCES += knxhandler.cpp knxhandler.h
|
||||
endif
|
||||
|
||||
ebusd_LDADD = ../lib/utils/libutils.a \
|
||||
../lib/ebus/libebus.a \
|
||||
-lpthread \
|
||||
@EXTRA_LIBS@
|
||||
|
||||
if KNX
|
||||
ebusd_SOURCES += knxhandler.cpp knxhandler.h
|
||||
ebusd_LDADD += ../lib/knx/libknx.a
|
||||
endif
|
||||
|
||||
if SSL
|
||||
ebusd_LDADD += -lssl -lcrypto
|
||||
endif
|
||||
|
||||
+48
-50
@@ -184,7 +184,7 @@ KnxHandler::KnxHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap* m
|
||||
logOtherError("knx", "invalid assignment %s to %s", key.c_str(), val.c_str());
|
||||
continue;
|
||||
}
|
||||
auto dest = static_cast<eibaddr_t>(v << 11);
|
||||
auto dest = static_cast<knx_addr_t>(v << 11);
|
||||
if (pos2 == string::npos) {
|
||||
// 2 level
|
||||
v = parseInt(val.substr(pos+1).c_str(), 10, 0, 0x7ff, &res);
|
||||
@@ -192,7 +192,7 @@ KnxHandler::KnxHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap* m
|
||||
logOtherError("knx", "invalid 2-level assignment %s to %s", key.c_str(), val.c_str());
|
||||
continue;
|
||||
}
|
||||
dest |= static_cast<eibaddr_t>(v);
|
||||
dest |= static_cast<knx_addr_t>(v);
|
||||
} else {
|
||||
// 3 level
|
||||
v = parseInt(val.substr(pos+1, pos2).c_str(), 10, 0, 0x07, &res);
|
||||
@@ -200,13 +200,13 @@ KnxHandler::KnxHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap* m
|
||||
logOtherError("knx", "invalid 3-level assignment %s to %s", key.c_str(), val.c_str());
|
||||
continue;
|
||||
}
|
||||
dest |= static_cast<eibaddr_t>(v << 8);
|
||||
dest |= static_cast<knx_addr_t>(v << 8);
|
||||
v = parseInt(val.substr(pos+1, pos2).c_str(), 10, 0, 0xff, &res);
|
||||
if (res != RESULT_OK) {
|
||||
logOtherError("knx", "invalid 3-level assignment %s to %s", key.c_str(), val.c_str());
|
||||
continue;
|
||||
}
|
||||
dest |= static_cast<eibaddr_t>(v);
|
||||
dest |= static_cast<knx_addr_t>(v);
|
||||
}
|
||||
if (key.substr(0, 7) != "global/") {
|
||||
messageCnt++;
|
||||
@@ -248,7 +248,7 @@ KnxHandler::KnxHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap* m
|
||||
KnxHandler::~KnxHandler() {
|
||||
join();
|
||||
if (m_con) {
|
||||
EIBClose(m_con);
|
||||
delete m_con;
|
||||
m_con = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -348,7 +348,10 @@ float int16ToFloat(uint16_t val) {
|
||||
return static_cast<float>(sig * exp2(exp) * (negative ? -0.01 : 0.01));
|
||||
}
|
||||
|
||||
result_t KnxHandler::sendGroupValue(eibaddr_t dest, apci_t apci, dtlf_t& lengthFlag, unsigned int value, const SingleDataField *field) const {
|
||||
result_t KnxHandler::sendGroupValue(knx_addr_t dest, apci_t apci, dtlf_t& lengthFlag, unsigned int value, const SingleDataField *field) const {
|
||||
if (!m_con || !m_con->isConnected() || !m_con->getAddress()) {
|
||||
return RESULT_EMPTY;
|
||||
}
|
||||
uint8_t data[] = {0, 0, 0, 0, 0, 0};
|
||||
data[0] = static_cast<uint8_t>(apci>>8);
|
||||
data[1] = static_cast<uint8_t>(apci&0xff);
|
||||
@@ -408,7 +411,8 @@ result_t KnxHandler::sendGroupValue(eibaddr_t dest, apci_t apci, dtlf_t& lengthF
|
||||
return RESULT_ERR_INVALID_NUM;
|
||||
}
|
||||
len += lengthFlag.length;
|
||||
if (EIBSendGroup(m_con, dest, len, data) < 0) {
|
||||
const char* err = m_con->sendGroup(dest, len, data);
|
||||
if (err) {
|
||||
logOtherError("knx", "unable to send %s, dest %4.4x, len %d",
|
||||
apci==APCI_GROUPVALUE_WRITE ? "write" : apci==APCI_GROUPVALUE_READ ? "read" : "response",
|
||||
dest, len);
|
||||
@@ -421,7 +425,7 @@ result_t KnxHandler::sendGroupValue(eibaddr_t dest, apci_t apci, dtlf_t& lengthF
|
||||
}
|
||||
|
||||
void KnxHandler::sendGlobalValue(global_t index, unsigned int value, bool response) {
|
||||
if (!m_con) {
|
||||
if (!m_con || !m_con->isConnected() || !m_con->getAddress()) {
|
||||
return;
|
||||
}
|
||||
const auto vit = m_subscribedGlobals.find(index);
|
||||
@@ -432,18 +436,18 @@ void KnxHandler::sendGlobalValue(global_t index, unsigned int value, bool respon
|
||||
if (git == m_subscribedGroups.end()) {
|
||||
return;
|
||||
}
|
||||
sendGroupValue(static_cast<eibaddr_t>(vit->second&0xffff),
|
||||
sendGroupValue(static_cast<knx_addr_t>(vit->second&0xffff),
|
||||
response ? APCI_GROUPVALUE_RESPONSE : APCI_GROUPVALUE_WRITE,
|
||||
git->second.lengthFlag, value);
|
||||
}
|
||||
|
||||
result_t KnxHandler::receiveTelegram(int maxlen, uint8_t *buf, int *recvlen,
|
||||
eibaddr_t *src, eibaddr_t *dest) {
|
||||
result_t KnxHandler::receiveTelegram(int maxlen, knx_transfer_t* typ, uint8_t *buf, int *recvlen,
|
||||
knx_addr_t *src, knx_addr_t *dest) {
|
||||
struct timespec tdiff = {
|
||||
.tv_sec = 2,
|
||||
.tv_nsec = 0,
|
||||
};
|
||||
int fd = EIB_Poll_FD(m_con);
|
||||
int fd = m_con->getPollFd();
|
||||
#ifdef HAVE_PPOLL
|
||||
nfds_t nfds = 1;
|
||||
struct pollfd fds[nfds];
|
||||
@@ -482,28 +486,17 @@ result_t KnxHandler::receiveTelegram(int maxlen, uint8_t *buf, int *recvlen,
|
||||
newData = FD_ISSET(fd, &readfds);
|
||||
#endif
|
||||
#endif
|
||||
int len = EIB_Poll_Complete(m_con);
|
||||
if (len == -1) {
|
||||
// read failed
|
||||
return RESULT_ERR_GENERIC_IO;
|
||||
}
|
||||
if (!newData) {
|
||||
// timeout
|
||||
return RESULT_ERR_TIMEOUT;
|
||||
}
|
||||
len = EIBGetGroup_Src(m_con, maxlen, buf, src, dest);
|
||||
if (len < 0) {
|
||||
return RESULT_ERR_GENERIC_IO;
|
||||
}
|
||||
if (len < 2) {
|
||||
return RESULT_ERR_GENERIC_IO;
|
||||
}
|
||||
*recvlen = len;
|
||||
return RESULT_OK;
|
||||
*typ = m_con->getPollData(maxlen, buf, recvlen, src, dest);
|
||||
return *typ == KNX_TRANSFER_NONE ? RESULT_EMPTY : RESULT_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
void printResponse(eibaddr_t src, eibaddr_t dest, int len, const uint8_t *data) {
|
||||
void printResponse(knx_addr_t src, knx_addr_t dest, int len, const uint8_t *data) {
|
||||
int tctrl = data[0]>>2;
|
||||
int apci = ((data[0]&0x03)<<8) | data[1];
|
||||
if ((apci & APCI_GROUPVALUE_READ_MASK) == 0) {
|
||||
apci &= ~APCI_GROUPVALUE_READ_MASK;
|
||||
@@ -518,17 +511,22 @@ void printResponse(eibaddr_t src, eibaddr_t dest, int len, const uint8_t *data)
|
||||
if (len>5) {
|
||||
value = (value<<8) | data[5]; // up to 32 bits
|
||||
}
|
||||
logOtherDebug("knx", "recv from %4.4x to %4.4x, %s (%d), len %d", src, dest,
|
||||
logOtherDebug("knx", "recv from %4.4x to %4.4x, %s (0x%3.3x, tctrl 0x%2.2x), len %d", src, dest,
|
||||
apci==APCI_GROUPVALUE_WRITE ? "write" : apci==APCI_GROUPVALUE_READ ? "read"
|
||||
: apci==APCI_GROUPVALUE_RESPONSE ? "response" : "other",
|
||||
apci, len);
|
||||
apci, tctrl, len);
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
void KnxHandler::handleReceivedTelegram(eibaddr_t src, eibaddr_t dest, int len, const uint8_t *data) {
|
||||
void KnxHandler::handleReceivedTelegram(knx_transfer_t typ, knx_addr_t src, knx_addr_t dest, int len, const uint8_t *data) {
|
||||
if (typ != KNX_TRANSFER_GROUP) {
|
||||
logOtherNotice("knx", "skipping non-group PDU %3.3x", typ);
|
||||
return;
|
||||
}
|
||||
int apci = ((data[0]&0x03)<<8) | data[1];
|
||||
if ((apci & APCI_GROUPVALUE_READ_MASK) == 0) {
|
||||
apci &= ~APCI_GROUPVALUE_READ_MASK;
|
||||
int groupReadWriteApci = apci & APCI_GROUPVALUE_READ_WRITE_MASK;
|
||||
if (groupReadWriteApci == APCI_GROUPVALUE_WRITE || groupReadWriteApci == APCI_GROUPVALUE_READ) {
|
||||
apci = groupReadWriteApci;
|
||||
}
|
||||
bool isWrite = apci==APCI_GROUPVALUE_WRITE;
|
||||
if (apci!=APCI_GROUPVALUE_READ && !isWrite) {
|
||||
@@ -638,7 +636,8 @@ void KnxHandler::handleReceivedTelegram(eibaddr_t src, eibaddr_t dest, int len,
|
||||
fval = int16ToFloat(static_cast<uint16_t>(value));
|
||||
} else if (lengthFlag.length == 4) {
|
||||
// convert from IEEE 754
|
||||
fval = uintToFloat(value);
|
||||
bool negative = (value & (1u << 31)) != 0;
|
||||
fval = uintToFloat(value, negative);
|
||||
} else {
|
||||
logOtherNotice("knx", "unable to decode write request from %4.4x to %4.4x for %s/%s/%s, value %d",
|
||||
src, dest, circuit.c_str(), name.c_str(), fieldName.c_str(), value);
|
||||
@@ -703,24 +702,22 @@ void KnxHandler::run() {
|
||||
int len = 0;
|
||||
time_t definitionsSince = 0;
|
||||
while (isRunning()) {
|
||||
bool wasConnected = m_con != nullptr;
|
||||
bool wasConnected = m_con != nullptr && m_con->isConnected();
|
||||
bool needsWait = true;
|
||||
if (!m_con) {
|
||||
m_con = EIBSocketURL(g_url);
|
||||
const char* err = nullptr;
|
||||
if (!m_con) {
|
||||
err = "open error";
|
||||
} else if (EIBOpen_GroupSocket(m_con, 0) < 0) {
|
||||
err = "open group error";
|
||||
EIBClose_sync(m_con);
|
||||
m_con = nullptr;
|
||||
} else {
|
||||
m_con = KnxConnection::create();
|
||||
const char* err = m_con->open(g_url);
|
||||
if (!err) {
|
||||
m_lastErrorLogTime = 0;
|
||||
logOtherNotice("knx", "connected");
|
||||
sendGlobalValue(GLOBAL_VERSION, VERSION_INT);
|
||||
sendGlobalValue(GLOBAL_RUNNING, 1);
|
||||
}
|
||||
if (err) {
|
||||
if (m_con) {
|
||||
delete m_con;
|
||||
m_con = nullptr;
|
||||
}
|
||||
time(&now);
|
||||
if (now > m_lastErrorLogTime + 10) { // log at most every 10 seconds
|
||||
m_lastErrorLogTime = now;
|
||||
@@ -792,7 +789,7 @@ void KnxHandler::run() {
|
||||
continue;
|
||||
}
|
||||
// store association
|
||||
eibaddr_t dest = git->second;
|
||||
knx_addr_t dest = git->second;
|
||||
auto subKey = static_cast<uint32_t>(dest | (isWrite ? FLAG_WRITE : FLAG_READ));
|
||||
auto sit = m_subscribedGroups.find(subKey);
|
||||
if (sit != m_subscribedGroups.cend()) {
|
||||
@@ -866,19 +863,20 @@ void KnxHandler::run() {
|
||||
}
|
||||
}
|
||||
if (m_con) {
|
||||
eibaddr_t src, dest;
|
||||
knx_addr_t src, dest;
|
||||
knx_transfer_t typ;
|
||||
// APDU data starting with octet 6 according to spec, contains 2 bits of application layer
|
||||
result_t res = RESULT_OK;
|
||||
do {
|
||||
res = receiveTelegram(8, data, &len, &src, &dest);
|
||||
res = receiveTelegram(sizeof(data), &typ, data, &len, &src, &dest);
|
||||
if (res != RESULT_OK) {
|
||||
if (res == RESULT_ERR_GENERIC_IO) {
|
||||
EIBClose_sync(m_con);
|
||||
delete m_con;
|
||||
m_con = nullptr;
|
||||
}
|
||||
} else {
|
||||
needsWait = false;
|
||||
handleReceivedTelegram(src, dest, len, data);
|
||||
handleReceivedTelegram(typ, src, dest, len, data);
|
||||
}
|
||||
} while (res == RESULT_OK);
|
||||
}
|
||||
@@ -913,7 +911,7 @@ void KnxHandler::run() {
|
||||
if (!field || field->isIgnored()) {
|
||||
continue;
|
||||
}
|
||||
eibaddr_t dest = destFlags&0xffff;
|
||||
knx_addr_t dest = destFlags&0xffff;
|
||||
unsigned int value = 0;
|
||||
result = message->decodeLastDataNumField(nullptr, index, &value);
|
||||
sendGroupValue(dest, APCI_GROUPVALUE_WRITE, sit->second.lengthFlag, value, field);
|
||||
|
||||
+10
-9
@@ -19,7 +19,6 @@
|
||||
#ifndef EBUSD_KNXHANDLER_H_
|
||||
#define EBUSD_KNXHANDLER_H_
|
||||
|
||||
#include <eibclient.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <list>
|
||||
@@ -29,11 +28,12 @@
|
||||
#include "ebusd/bushandler.h"
|
||||
#include "lib/ebus/message.h"
|
||||
#include "lib/ebus/stringhelper.h"
|
||||
#include "lib/knx/knx.h"
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
/** @file ebusd/knxhandler.h
|
||||
* A data handler enabling KNX support via knx.
|
||||
* A data handler enabling KNX support.
|
||||
*/
|
||||
|
||||
using std::map;
|
||||
@@ -65,7 +65,7 @@ enum apci_t {
|
||||
APCI_GROUPVALUE_WRITE = 0x080, //!< A_GroupValue_Write-PDU
|
||||
};
|
||||
|
||||
#define APCI_GROUPVALUE_READ_MASK 0x3c0
|
||||
#define APCI_GROUPVALUE_READ_WRITE_MASK 0x3c0
|
||||
|
||||
#define FLAG_READ 0x400000
|
||||
#define FLAG_WRITE 0x800000
|
||||
@@ -144,7 +144,7 @@ class KnxHandler : public DataSink, public DataSource, public WaitThread {
|
||||
* @param field the message field or nullptr for non field related.
|
||||
* @return the result code.
|
||||
*/
|
||||
result_t sendGroupValue(eibaddr_t dest, apci_t apci, dtlf_t& lengthFlag, unsigned int value, const SingleDataField *field = nullptr) const;
|
||||
result_t sendGroupValue(knx_addr_t dest, apci_t apci, dtlf_t& lengthFlag, unsigned int value, const SingleDataField *field = nullptr) const;
|
||||
|
||||
/**
|
||||
* Send a global value to the registered group address.
|
||||
@@ -164,16 +164,17 @@ class KnxHandler : public DataSink, public DataSource, public WaitThread {
|
||||
* @return the result code, either RESULT_OK on success, RESULT_ERR_GENERIC_IO on I/O error (e.g. socket closed),
|
||||
* or RESULT_ERR_TIMEOUT if no data is available.
|
||||
*/
|
||||
result_t receiveTelegram(int maxlen, uint8_t *buf, int *recvlen, eibaddr_t *src, eibaddr_t *dest);
|
||||
result_t receiveTelegram(int maxlen, knx_transfer_t* typ, uint8_t *buf, int *recvlen, knx_addr_t *src, knx_addr_t *dest);
|
||||
|
||||
/**
|
||||
* Handle a received KNX telegram.
|
||||
* @param typ the poll data type.
|
||||
* @param src the source address.
|
||||
* @param dest the destination group address.
|
||||
* @param len the telegram length (starting with ovctet 6).
|
||||
* @param data the telegram data buffer.
|
||||
*/
|
||||
void handleReceivedTelegram(eibaddr_t src, eibaddr_t dest, int len, const uint8_t *data);
|
||||
void handleReceivedTelegram(knx_transfer_t typ, knx_addr_t src, knx_addr_t dest, int len, const uint8_t *data);
|
||||
|
||||
protected:
|
||||
// @copydoc
|
||||
@@ -188,7 +189,7 @@ class KnxHandler : public DataSink, public DataSource, public WaitThread {
|
||||
StringReplacers m_replacers;
|
||||
|
||||
/** the group address for relevant message fields before being subscribed to by "circuit/message/field" name. */
|
||||
map<string, eibaddr_t> m_messageFieldGroupAddress;
|
||||
map<string, knx_addr_t> m_messageFieldGroupAddress;
|
||||
|
||||
/**
|
||||
* the group addresses that need to be responded to.
|
||||
@@ -209,8 +210,8 @@ class KnxHandler : public DataSink, public DataSource, public WaitThread {
|
||||
/** the time the run thread was entered. */
|
||||
time_t m_start;
|
||||
|
||||
/** the knx structure if initialized, or nullptr. */
|
||||
EIBConnection* m_con;
|
||||
/** the knx connection if initialized, or nullptr. */
|
||||
KnxConnection* m_con;
|
||||
|
||||
/** the last update check result. */
|
||||
string m_lastUpdateCheckResult;
|
||||
|
||||
@@ -794,7 +794,6 @@ result_t NumberDataType::readSymbols(size_t offset, size_t length, const SymbolS
|
||||
}
|
||||
|
||||
result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output) const {
|
||||
int signedValue;
|
||||
if (!hasFlag(REQ) && value == m_replacement) {
|
||||
return RESULT_EMPTY;
|
||||
}
|
||||
@@ -814,9 +813,10 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
|
||||
} else {
|
||||
negative = false;
|
||||
}
|
||||
int signedValue;
|
||||
if (m_bitCount == 32) {
|
||||
if (hasFlag(EXP)) { // IEEE 754 binary32
|
||||
float val = uintToFloat(value);
|
||||
float val = uintToFloat(value, negative);
|
||||
if (val != val) { // !isnan(val)
|
||||
return RESULT_EMPTY;
|
||||
}
|
||||
@@ -830,7 +830,6 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
|
||||
*output = static_cast<float>(val);
|
||||
return RESULT_OK;
|
||||
}
|
||||
// less than 32 bit
|
||||
if (!negative) {
|
||||
if (m_divisor < 0) {
|
||||
*output = static_cast<float>(value) * static_cast<float>(-m_divisor);
|
||||
@@ -860,7 +859,6 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
|
||||
result_t NumberDataType::readFromRawValue(unsigned int value,
|
||||
OutputFormat outputFormat, ostream* output) const {
|
||||
size_t length = (m_bitCount < 8) ? 1 : (m_bitCount/8);
|
||||
int signedValue;
|
||||
// initialize output
|
||||
*output << setw(0) << std::resetiosflags(output->flags()) << dec << std::skipws << setprecision(6);
|
||||
|
||||
@@ -888,6 +886,7 @@ result_t NumberDataType::readFromRawValue(unsigned int value,
|
||||
} else {
|
||||
negative = false;
|
||||
}
|
||||
int signedValue;
|
||||
if (m_bitCount == 32) {
|
||||
if (hasFlag(EXP)) { // IEEE 754 binary32
|
||||
float val = uintToFloat(value, negative);
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
add_definitions(-Wconversion -Wno-unused-parameter)
|
||||
|
||||
set(libknx_a_SOURCES
|
||||
knx.h knx.cpp
|
||||
)
|
||||
|
||||
set(libknx_a_LIBS
|
||||
)
|
||||
|
||||
if(HAVE_KNXD)
|
||||
set(libknx_a_SOURCES ${libknx_a_SOURCES} knxd.h)
|
||||
set(libknx_a_LIBS ${libknx_a_LIBS} eibclient)
|
||||
endif(HAVE_KNXD)
|
||||
|
||||
add_library(knx ${libknx_a_SOURCES})
|
||||
|
||||
target_link_libraries(knx ${libknx_a_LIBS})
|
||||
@@ -0,0 +1,18 @@
|
||||
AM_CXXFLAGS = -I$(top_srcdir)/src \
|
||||
-isystem$(top_srcdir) \
|
||||
-Wno-conversion
|
||||
|
||||
noinst_LIBRARIES = libknx.a
|
||||
|
||||
libknx_a_SOURCES = \
|
||||
knx.h knx.cpp
|
||||
|
||||
if KNXD
|
||||
libknx_a_SOURCES += knxd.h
|
||||
libknx_a_LIBADD = -leibclient
|
||||
else
|
||||
libknx_a_SOURCES += knxnet.h
|
||||
endif
|
||||
|
||||
distclean-local:
|
||||
-rm -f Makefile.in
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* ebusd - daemon for communication with eBUS heating systems.
|
||||
* Copyright (C) 2022 John Baier <ebusd@ebusd.eu>
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "lib/knx/knx.h"
|
||||
|
||||
#ifdef HAVE_KNXD
|
||||
#include "lib/knx/knxd.h"
|
||||
#else
|
||||
#include "lib/knx/knxnet.h"
|
||||
#endif
|
||||
|
||||
KnxConnection* KnxConnection::create() {
|
||||
#ifdef HAVE_KNXD
|
||||
return new KnxdConnection();
|
||||
#else
|
||||
return new KnxNetConnection();
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* ebusd - daemon for communication with eBUS heating systems.
|
||||
* Copyright (C) 2022 John Baier <ebusd@ebusd.eu>
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIB_KNX_KNX_H_
|
||||
#define LIB_KNX_KNX_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// base KNX address type (group or individual)
|
||||
typedef uint16_t knx_addr_t;
|
||||
|
||||
// the transfer types (lower 8 bits of transport control field with sequence=0, plus bit 8 with address type)
|
||||
enum knx_transfer_t {
|
||||
KNX_TRANSFER_NONE = -1, // no transfer available
|
||||
KNX_TRANSFER_GROUP = 0x100, // data group or broadcast PDU
|
||||
KNX_TRANSFER_TAG_GROUP = 0x104, // data tag group PDU
|
||||
KNX_TRANSFER_INDIVIDUAL = 0x000, // data individual PDU
|
||||
KNX_TRANSFER_CONNECTED = 0x040, // data connected PDU
|
||||
KNX_TRANSFER_CONNECT = 0x080, // connect PDU
|
||||
KNX_TRANSFER_DISCONNECT = 0x081, // disconnect PDU
|
||||
KNX_TRANSFER_ACK = 0x0c2, // ACK PDU
|
||||
KNX_TRANSFER_NAK = 0x0c3, // NAK PDU
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An abstract KNX connection.
|
||||
*/
|
||||
class KnxConnection {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
*/
|
||||
KnxConnection() {}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~KnxConnection() {}
|
||||
|
||||
/**
|
||||
* Create a new KnxConnection.
|
||||
* @param url the URL to connect to.
|
||||
* @return the new KnxConnection, or @a nullptr on error.
|
||||
*/
|
||||
static KnxConnection* create();
|
||||
|
||||
/**
|
||||
* Open a connection to the specified URL.
|
||||
* @param url the URL to connect to.
|
||||
* @return nullptr on success, or an error message.
|
||||
*/
|
||||
virtual const char* open(const char* url) = 0;
|
||||
|
||||
/**
|
||||
* @return true if connected, false otherwise.
|
||||
*/
|
||||
virtual bool isConnected() const = 0;
|
||||
|
||||
/**
|
||||
* Close the connection.
|
||||
*/
|
||||
virtual void close() = 0;
|
||||
|
||||
/**
|
||||
* @return the file descriptor for polling.
|
||||
*/
|
||||
virtual int getPollFd() const = 0;
|
||||
|
||||
/**
|
||||
* Get the available data (after the file descriptor was checked for availability).
|
||||
* @param size the size of the data buffer.
|
||||
* @param data the data buffer to copy the data to.
|
||||
* @param len pointer to store the actual data length to.
|
||||
* @param src optional pointer to store the source address (if any, depending on poll data type).
|
||||
* @param dst optional pointer to store the destination address (if any, depending on poll data type).
|
||||
* @return the polled transfer data type.
|
||||
*/
|
||||
virtual knx_transfer_t getPollData(int size, uint8_t* data, int* len, knx_addr_t* src, knx_addr_t* dst) = 0;
|
||||
|
||||
/**
|
||||
* Send a group APDU.
|
||||
* @param dst the destination address.
|
||||
* @param len the APDU length.
|
||||
* @param data the APDU data buffer.
|
||||
* @return nullptr on success, or an error message.
|
||||
*/
|
||||
virtual const char* sendGroup(knx_addr_t dst, int len, const uint8_t* data) = 0;
|
||||
|
||||
/**
|
||||
* @return true if connection allows programming via ETS.
|
||||
*/
|
||||
virtual bool isProgrammable() { return false; };
|
||||
|
||||
/**
|
||||
* @return the individual address, or 0 if not programmed yet, or any non-zero value if not programmable.
|
||||
*/
|
||||
virtual knx_addr_t getAddress() { return 0xffff; };
|
||||
|
||||
/**
|
||||
* @param address the individual address to set.
|
||||
*/
|
||||
virtual void setAddress(knx_addr_t address) {
|
||||
// default implementation does nothing
|
||||
}
|
||||
};
|
||||
|
||||
#endif // LIB_KNX_KNX_H_
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* ebusd - daemon for communication with eBUS heating systems.
|
||||
* Copyright (C) 2022 John Baier <ebusd@ebusd.eu>
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIB_KNX_KNXD_H_
|
||||
#define LIB_KNX_KNXD_H_
|
||||
|
||||
#include <eibclient.h>
|
||||
#include "lib/knx/knx.h"
|
||||
|
||||
class KnxdConnection : public KnxConnection {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
*/
|
||||
KnxdConnection()
|
||||
: KnxConnection(), m_con(nullptr) {}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~KnxdConnection() {
|
||||
close();
|
||||
}
|
||||
|
||||
// @copydoc
|
||||
const char* open(const char* url) override {
|
||||
close();
|
||||
m_con = EIBSocketURL(url);
|
||||
if (!m_con) {
|
||||
return "open error";
|
||||
}
|
||||
if (EIBOpen_GroupSocket(m_con, 0) < 0) {
|
||||
EIBClose_sync(m_con);
|
||||
m_con = nullptr;
|
||||
return "open group error";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// @copydoc
|
||||
bool isConnected() const override {
|
||||
return m_con != nullptr;
|
||||
}
|
||||
|
||||
void close() override {
|
||||
if (m_con) {
|
||||
EIBClose_sync(m_con);
|
||||
m_con = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// @copydoc
|
||||
int getPollFd() const override {
|
||||
return EIB_Poll_FD(m_con);
|
||||
}
|
||||
|
||||
// @copydoc
|
||||
knx_transfer_t getPollData(int size, uint8_t* data, int* len, knx_addr_t* src, knx_addr_t* dst) override {
|
||||
int ret = EIB_Poll_Complete(m_con);
|
||||
if (ret == -1) {
|
||||
// read failed
|
||||
return KNX_TRANSFER_NONE;
|
||||
}
|
||||
ret = EIBGetGroup_Src(m_con, size, data, src, dst);
|
||||
if (ret < 2) {
|
||||
return KNX_TRANSFER_NONE;
|
||||
}
|
||||
if (len) {
|
||||
*len = ret;
|
||||
}
|
||||
return KNX_TRANSFER_GROUP;
|
||||
}
|
||||
|
||||
// @copydoc
|
||||
const char* sendGroup(knx_addr_t dst, int len, const uint8_t* data) override {
|
||||
if (EIBSendGroup(m_con, dst, len, data) < 0) {
|
||||
return "send error";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
/** the knx structure if connected, or nullptr. */
|
||||
EIBConnection* m_con;
|
||||
};
|
||||
|
||||
#endif // LIB_KNX_KNXD_H_
|
||||
Reference in New Issue
Block a user