abstract from knxd
This commit is contained in:
+18
-7
@@ -103,14 +103,24 @@ if(HAVE_MQTT)
|
|||||||
endif(mqtt STREQUAL ON)
|
endif(mqtt STREQUAL ON)
|
||||||
endif(HAVE_MQTT)
|
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)
|
if(HAVE_KNX)
|
||||||
option(knx "disable support for KNX handling." ON)
|
find_library(HAVE_KNXD eibclient)
|
||||||
if(knx STREQUAL ON)
|
if(HAVE_KNXD)
|
||||||
message(STATUS "KNX enabled")
|
option(knxd "enable support for KNX handling via knxd." OFF)
|
||||||
else(knx STREQUAL ON)
|
if(knxd STREQUAL ON)
|
||||||
unset(HAVE_KNX)
|
message(STATUS "KNX via knxd enabled")
|
||||||
endif(knx STREQUAL ON)
|
else(knxd STREQUAL ON)
|
||||||
|
set(HAVE_KNXD 0)
|
||||||
|
endif(knxd STREQUAL ON)
|
||||||
|
endif(HAVE_KNXD)
|
||||||
endif(HAVE_KNX)
|
endif(HAVE_KNX)
|
||||||
|
|
||||||
find_library(HAVE_SSL ssl)
|
find_library(HAVE_SSL ssl)
|
||||||
@@ -169,6 +179,7 @@ endif(BUILD_TESTING)
|
|||||||
add_subdirectory(src/ebusd)
|
add_subdirectory(src/ebusd)
|
||||||
add_subdirectory(src/lib/utils)
|
add_subdirectory(src/lib/utils)
|
||||||
add_subdirectory(src/lib/ebus)
|
add_subdirectory(src/lib/ebus)
|
||||||
|
add_subdirectory(src/lib/knx)
|
||||||
add_subdirectory(src/tools)
|
add_subdirectory(src/tools)
|
||||||
|
|
||||||
if(EXISTS "${ROOT}/etc/debian_version")
|
if(EXISTS "${ROOT}/etc/debian_version")
|
||||||
|
|||||||
+7
-1
@@ -2,7 +2,13 @@ ACLOCAL_AMFLAGS = -I m4
|
|||||||
|
|
||||||
SUBDIRS = docs \
|
SUBDIRS = docs \
|
||||||
src/lib/utils \
|
src/lib/utils \
|
||||||
src/lib/ebus \
|
src/lib/ebus
|
||||||
|
|
||||||
|
if KNX
|
||||||
|
SUBDIRS += src/lib/knx
|
||||||
|
endif
|
||||||
|
|
||||||
|
SUBDIRS += \
|
||||||
src/ebusd \
|
src/ebusd \
|
||||||
src/tools
|
src/tools
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -7,9 +7,12 @@
|
|||||||
/* Defined if MQTT handling is enabled. */
|
/* Defined if MQTT handling is enabled. */
|
||||||
#cmakedefine HAVE_MQTT
|
#cmakedefine HAVE_MQTT
|
||||||
|
|
||||||
/* Defined if KNX is enabled. */
|
/* Defined if KNX handling is enabled. */
|
||||||
#cmakedefine HAVE_KNX
|
#cmakedefine HAVE_KNX
|
||||||
|
|
||||||
|
/* Defined if KNX handling via knxd is enabled. */
|
||||||
|
#cmakedefine HAVE_KNXD
|
||||||
|
|
||||||
/* Defined if SSL is enabled. */
|
/* Defined if SSL is enabled. */
|
||||||
#cmakedefine HAVE_SSL
|
#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])
|
AC_ARG_WITH(knx, AS_HELP_STRING([--without-knx], [disable support for KNX handling]), [], [with_knx=yes])
|
||||||
if test "x$with_knx" != "xno"; then
|
if test "x$with_knx" != "xno"; then
|
||||||
AC_CHECK_LIB([eibclient], [EIBSocketURL],
|
AC_DEFINE_UNQUOTED(HAVE_KNX, [1], [Defined if KNX handling is enabled.])
|
||||||
[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]), [
|
||||||
EXTRA_LIBS+=" -leibclient"],
|
AS_IF([test "x$with_knxd" == "xyes"],
|
||||||
[AC_MSG_RESULT([Could not find EIBSocketURL in libeibclient.])
|
[AC_CHECK_LIB([eibclient], [EIBSocketURL],
|
||||||
with_knx="no"])
|
[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
|
fi
|
||||||
AM_CONDITIONAL([KNX], [test "x$with_knx" != "xno"])
|
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])
|
AC_ARG_WITH(ssl, AS_HELP_STRING([--without-ssl], [disable support for SSL]), [], [with_ssl=yes])
|
||||||
if test "x$with_ssl" != "xno"; then
|
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/Makefile
|
||||||
src/lib/ebus/contrib/test/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_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.])
|
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)
|
if(HAVE_KNX)
|
||||||
set(ebusd_SOURCES ${ebusd_SOURCES} knxhandler.cpp knxhandler.h)
|
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)
|
endif(HAVE_KNX)
|
||||||
|
|
||||||
if(HAVE_SSL)
|
if(HAVE_SSL)
|
||||||
|
|||||||
@@ -16,15 +16,17 @@ ebusd_SOURCES = \
|
|||||||
if MQTT
|
if MQTT
|
||||||
ebusd_SOURCES += mqtthandler.cpp mqtthandler.h
|
ebusd_SOURCES += mqtthandler.cpp mqtthandler.h
|
||||||
endif
|
endif
|
||||||
if KNX
|
|
||||||
ebusd_SOURCES += knxhandler.cpp knxhandler.h
|
|
||||||
endif
|
|
||||||
|
|
||||||
ebusd_LDADD = ../lib/utils/libutils.a \
|
ebusd_LDADD = ../lib/utils/libutils.a \
|
||||||
../lib/ebus/libebus.a \
|
../lib/ebus/libebus.a \
|
||||||
-lpthread \
|
-lpthread \
|
||||||
@EXTRA_LIBS@
|
@EXTRA_LIBS@
|
||||||
|
|
||||||
|
if KNX
|
||||||
|
ebusd_SOURCES += knxhandler.cpp knxhandler.h
|
||||||
|
ebusd_LDADD += ../lib/knx/libknx.a
|
||||||
|
endif
|
||||||
|
|
||||||
if SSL
|
if SSL
|
||||||
ebusd_LDADD += -lssl -lcrypto
|
ebusd_LDADD += -lssl -lcrypto
|
||||||
endif
|
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());
|
logOtherError("knx", "invalid assignment %s to %s", key.c_str(), val.c_str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto dest = static_cast<eibaddr_t>(v << 11);
|
auto dest = static_cast<knx_addr_t>(v << 11);
|
||||||
if (pos2 == string::npos) {
|
if (pos2 == string::npos) {
|
||||||
// 2 level
|
// 2 level
|
||||||
v = parseInt(val.substr(pos+1).c_str(), 10, 0, 0x7ff, &res);
|
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());
|
logOtherError("knx", "invalid 2-level assignment %s to %s", key.c_str(), val.c_str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
dest |= static_cast<eibaddr_t>(v);
|
dest |= static_cast<knx_addr_t>(v);
|
||||||
} else {
|
} else {
|
||||||
// 3 level
|
// 3 level
|
||||||
v = parseInt(val.substr(pos+1, pos2).c_str(), 10, 0, 0x07, &res);
|
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());
|
logOtherError("knx", "invalid 3-level assignment %s to %s", key.c_str(), val.c_str());
|
||||||
continue;
|
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);
|
v = parseInt(val.substr(pos+1, pos2).c_str(), 10, 0, 0xff, &res);
|
||||||
if (res != RESULT_OK) {
|
if (res != RESULT_OK) {
|
||||||
logOtherError("knx", "invalid 3-level assignment %s to %s", key.c_str(), val.c_str());
|
logOtherError("knx", "invalid 3-level assignment %s to %s", key.c_str(), val.c_str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
dest |= static_cast<eibaddr_t>(v);
|
dest |= static_cast<knx_addr_t>(v);
|
||||||
}
|
}
|
||||||
if (key.substr(0, 7) != "global/") {
|
if (key.substr(0, 7) != "global/") {
|
||||||
messageCnt++;
|
messageCnt++;
|
||||||
@@ -248,7 +248,7 @@ KnxHandler::KnxHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap* m
|
|||||||
KnxHandler::~KnxHandler() {
|
KnxHandler::~KnxHandler() {
|
||||||
join();
|
join();
|
||||||
if (m_con) {
|
if (m_con) {
|
||||||
EIBClose(m_con);
|
delete m_con;
|
||||||
m_con = nullptr;
|
m_con = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,7 +348,10 @@ float int16ToFloat(uint16_t val) {
|
|||||||
return static_cast<float>(sig * exp2(exp) * (negative ? -0.01 : 0.01));
|
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};
|
uint8_t data[] = {0, 0, 0, 0, 0, 0};
|
||||||
data[0] = static_cast<uint8_t>(apci>>8);
|
data[0] = static_cast<uint8_t>(apci>>8);
|
||||||
data[1] = static_cast<uint8_t>(apci&0xff);
|
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;
|
return RESULT_ERR_INVALID_NUM;
|
||||||
}
|
}
|
||||||
len += lengthFlag.length;
|
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",
|
logOtherError("knx", "unable to send %s, dest %4.4x, len %d",
|
||||||
apci==APCI_GROUPVALUE_WRITE ? "write" : apci==APCI_GROUPVALUE_READ ? "read" : "response",
|
apci==APCI_GROUPVALUE_WRITE ? "write" : apci==APCI_GROUPVALUE_READ ? "read" : "response",
|
||||||
dest, len);
|
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) {
|
void KnxHandler::sendGlobalValue(global_t index, unsigned int value, bool response) {
|
||||||
if (!m_con) {
|
if (!m_con || !m_con->isConnected() || !m_con->getAddress()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto vit = m_subscribedGlobals.find(index);
|
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()) {
|
if (git == m_subscribedGroups.end()) {
|
||||||
return;
|
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,
|
response ? APCI_GROUPVALUE_RESPONSE : APCI_GROUPVALUE_WRITE,
|
||||||
git->second.lengthFlag, value);
|
git->second.lengthFlag, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
result_t KnxHandler::receiveTelegram(int maxlen, uint8_t *buf, int *recvlen,
|
result_t KnxHandler::receiveTelegram(int maxlen, knx_transfer_t* typ, uint8_t *buf, int *recvlen,
|
||||||
eibaddr_t *src, eibaddr_t *dest) {
|
knx_addr_t *src, knx_addr_t *dest) {
|
||||||
struct timespec tdiff = {
|
struct timespec tdiff = {
|
||||||
.tv_sec = 2,
|
.tv_sec = 2,
|
||||||
.tv_nsec = 0,
|
.tv_nsec = 0,
|
||||||
};
|
};
|
||||||
int fd = EIB_Poll_FD(m_con);
|
int fd = m_con->getPollFd();
|
||||||
#ifdef HAVE_PPOLL
|
#ifdef HAVE_PPOLL
|
||||||
nfds_t nfds = 1;
|
nfds_t nfds = 1;
|
||||||
struct pollfd fds[nfds];
|
struct pollfd fds[nfds];
|
||||||
@@ -482,28 +486,17 @@ result_t KnxHandler::receiveTelegram(int maxlen, uint8_t *buf, int *recvlen,
|
|||||||
newData = FD_ISSET(fd, &readfds);
|
newData = FD_ISSET(fd, &readfds);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
int len = EIB_Poll_Complete(m_con);
|
|
||||||
if (len == -1) {
|
|
||||||
// read failed
|
|
||||||
return RESULT_ERR_GENERIC_IO;
|
|
||||||
}
|
|
||||||
if (!newData) {
|
if (!newData) {
|
||||||
// timeout
|
// timeout
|
||||||
return RESULT_ERR_TIMEOUT;
|
return RESULT_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
len = EIBGetGroup_Src(m_con, maxlen, buf, src, dest);
|
*typ = m_con->getPollData(maxlen, buf, recvlen, src, dest);
|
||||||
if (len < 0) {
|
return *typ == KNX_TRANSFER_NONE ? RESULT_EMPTY : RESULT_OK;
|
||||||
return RESULT_ERR_GENERIC_IO;
|
|
||||||
}
|
|
||||||
if (len < 2) {
|
|
||||||
return RESULT_ERR_GENERIC_IO;
|
|
||||||
}
|
|
||||||
*recvlen = len;
|
|
||||||
return 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];
|
int apci = ((data[0]&0x03)<<8) | data[1];
|
||||||
if ((apci & APCI_GROUPVALUE_READ_MASK) == 0) {
|
if ((apci & APCI_GROUPVALUE_READ_MASK) == 0) {
|
||||||
apci &= ~APCI_GROUPVALUE_READ_MASK;
|
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) {
|
if (len>5) {
|
||||||
value = (value<<8) | data[5]; // up to 32 bits
|
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_WRITE ? "write" : apci==APCI_GROUPVALUE_READ ? "read"
|
||||||
: apci==APCI_GROUPVALUE_RESPONSE ? "response" : "other",
|
: 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];
|
int apci = ((data[0]&0x03)<<8) | data[1];
|
||||||
if ((apci & APCI_GROUPVALUE_READ_MASK) == 0) {
|
int groupReadWriteApci = apci & APCI_GROUPVALUE_READ_WRITE_MASK;
|
||||||
apci &= ~APCI_GROUPVALUE_READ_MASK;
|
if (groupReadWriteApci == APCI_GROUPVALUE_WRITE || groupReadWriteApci == APCI_GROUPVALUE_READ) {
|
||||||
|
apci = groupReadWriteApci;
|
||||||
}
|
}
|
||||||
bool isWrite = apci==APCI_GROUPVALUE_WRITE;
|
bool isWrite = apci==APCI_GROUPVALUE_WRITE;
|
||||||
if (apci!=APCI_GROUPVALUE_READ && !isWrite) {
|
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));
|
fval = int16ToFloat(static_cast<uint16_t>(value));
|
||||||
} else if (lengthFlag.length == 4) {
|
} else if (lengthFlag.length == 4) {
|
||||||
// convert from IEEE 754
|
// convert from IEEE 754
|
||||||
fval = uintToFloat(value);
|
bool negative = (value & (1u << 31)) != 0;
|
||||||
|
fval = uintToFloat(value, negative);
|
||||||
} else {
|
} else {
|
||||||
logOtherNotice("knx", "unable to decode write request from %4.4x to %4.4x for %s/%s/%s, value %d",
|
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);
|
src, dest, circuit.c_str(), name.c_str(), fieldName.c_str(), value);
|
||||||
@@ -703,24 +702,22 @@ void KnxHandler::run() {
|
|||||||
int len = 0;
|
int len = 0;
|
||||||
time_t definitionsSince = 0;
|
time_t definitionsSince = 0;
|
||||||
while (isRunning()) {
|
while (isRunning()) {
|
||||||
bool wasConnected = m_con != nullptr;
|
bool wasConnected = m_con != nullptr && m_con->isConnected();
|
||||||
bool needsWait = true;
|
bool needsWait = true;
|
||||||
if (!m_con) {
|
if (!m_con) {
|
||||||
m_con = EIBSocketURL(g_url);
|
m_con = KnxConnection::create();
|
||||||
const char* err = nullptr;
|
const char* err = m_con->open(g_url);
|
||||||
if (!m_con) {
|
if (!err) {
|
||||||
err = "open error";
|
|
||||||
} else if (EIBOpen_GroupSocket(m_con, 0) < 0) {
|
|
||||||
err = "open group error";
|
|
||||||
EIBClose_sync(m_con);
|
|
||||||
m_con = nullptr;
|
|
||||||
} else {
|
|
||||||
m_lastErrorLogTime = 0;
|
m_lastErrorLogTime = 0;
|
||||||
logOtherNotice("knx", "connected");
|
logOtherNotice("knx", "connected");
|
||||||
sendGlobalValue(GLOBAL_VERSION, VERSION_INT);
|
sendGlobalValue(GLOBAL_VERSION, VERSION_INT);
|
||||||
sendGlobalValue(GLOBAL_RUNNING, 1);
|
sendGlobalValue(GLOBAL_RUNNING, 1);
|
||||||
}
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
|
if (m_con) {
|
||||||
|
delete m_con;
|
||||||
|
m_con = nullptr;
|
||||||
|
}
|
||||||
time(&now);
|
time(&now);
|
||||||
if (now > m_lastErrorLogTime + 10) { // log at most every 10 seconds
|
if (now > m_lastErrorLogTime + 10) { // log at most every 10 seconds
|
||||||
m_lastErrorLogTime = now;
|
m_lastErrorLogTime = now;
|
||||||
@@ -792,7 +789,7 @@ void KnxHandler::run() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// store association
|
// 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 subKey = static_cast<uint32_t>(dest | (isWrite ? FLAG_WRITE : FLAG_READ));
|
||||||
auto sit = m_subscribedGroups.find(subKey);
|
auto sit = m_subscribedGroups.find(subKey);
|
||||||
if (sit != m_subscribedGroups.cend()) {
|
if (sit != m_subscribedGroups.cend()) {
|
||||||
@@ -866,19 +863,20 @@ void KnxHandler::run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_con) {
|
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
|
// APDU data starting with octet 6 according to spec, contains 2 bits of application layer
|
||||||
result_t res = RESULT_OK;
|
result_t res = RESULT_OK;
|
||||||
do {
|
do {
|
||||||
res = receiveTelegram(8, data, &len, &src, &dest);
|
res = receiveTelegram(sizeof(data), &typ, data, &len, &src, &dest);
|
||||||
if (res != RESULT_OK) {
|
if (res != RESULT_OK) {
|
||||||
if (res == RESULT_ERR_GENERIC_IO) {
|
if (res == RESULT_ERR_GENERIC_IO) {
|
||||||
EIBClose_sync(m_con);
|
delete m_con;
|
||||||
m_con = nullptr;
|
m_con = nullptr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
needsWait = false;
|
needsWait = false;
|
||||||
handleReceivedTelegram(src, dest, len, data);
|
handleReceivedTelegram(typ, src, dest, len, data);
|
||||||
}
|
}
|
||||||
} while (res == RESULT_OK);
|
} while (res == RESULT_OK);
|
||||||
}
|
}
|
||||||
@@ -913,7 +911,7 @@ void KnxHandler::run() {
|
|||||||
if (!field || field->isIgnored()) {
|
if (!field || field->isIgnored()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
eibaddr_t dest = destFlags&0xffff;
|
knx_addr_t dest = destFlags&0xffff;
|
||||||
unsigned int value = 0;
|
unsigned int value = 0;
|
||||||
result = message->decodeLastDataNumField(nullptr, index, &value);
|
result = message->decodeLastDataNumField(nullptr, index, &value);
|
||||||
sendGroupValue(dest, APCI_GROUPVALUE_WRITE, sit->second.lengthFlag, value, field);
|
sendGroupValue(dest, APCI_GROUPVALUE_WRITE, sit->second.lengthFlag, value, field);
|
||||||
|
|||||||
+10
-9
@@ -19,7 +19,6 @@
|
|||||||
#ifndef EBUSD_KNXHANDLER_H_
|
#ifndef EBUSD_KNXHANDLER_H_
|
||||||
#define EBUSD_KNXHANDLER_H_
|
#define EBUSD_KNXHANDLER_H_
|
||||||
|
|
||||||
#include <eibclient.h>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
@@ -29,11 +28,12 @@
|
|||||||
#include "ebusd/bushandler.h"
|
#include "ebusd/bushandler.h"
|
||||||
#include "lib/ebus/message.h"
|
#include "lib/ebus/message.h"
|
||||||
#include "lib/ebus/stringhelper.h"
|
#include "lib/ebus/stringhelper.h"
|
||||||
|
#include "lib/knx/knx.h"
|
||||||
|
|
||||||
namespace ebusd {
|
namespace ebusd {
|
||||||
|
|
||||||
/** @file ebusd/knxhandler.h
|
/** @file ebusd/knxhandler.h
|
||||||
* A data handler enabling KNX support via knx.
|
* A data handler enabling KNX support.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using std::map;
|
using std::map;
|
||||||
@@ -65,7 +65,7 @@ enum apci_t {
|
|||||||
APCI_GROUPVALUE_WRITE = 0x080, //!< A_GroupValue_Write-PDU
|
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_READ 0x400000
|
||||||
#define FLAG_WRITE 0x800000
|
#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.
|
* @param field the message field or nullptr for non field related.
|
||||||
* @return the result code.
|
* @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.
|
* 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),
|
* @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.
|
* 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.
|
* Handle a received KNX telegram.
|
||||||
|
* @param typ the poll data type.
|
||||||
* @param src the source address.
|
* @param src the source address.
|
||||||
* @param dest the destination group address.
|
* @param dest the destination group address.
|
||||||
* @param len the telegram length (starting with ovctet 6).
|
* @param len the telegram length (starting with ovctet 6).
|
||||||
* @param data the telegram data buffer.
|
* @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:
|
protected:
|
||||||
// @copydoc
|
// @copydoc
|
||||||
@@ -188,7 +189,7 @@ class KnxHandler : public DataSink, public DataSource, public WaitThread {
|
|||||||
StringReplacers m_replacers;
|
StringReplacers m_replacers;
|
||||||
|
|
||||||
/** the group address for relevant message fields before being subscribed to by "circuit/message/field" name. */
|
/** 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.
|
* 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. */
|
/** the time the run thread was entered. */
|
||||||
time_t m_start;
|
time_t m_start;
|
||||||
|
|
||||||
/** the knx structure if initialized, or nullptr. */
|
/** the knx connection if initialized, or nullptr. */
|
||||||
EIBConnection* m_con;
|
KnxConnection* m_con;
|
||||||
|
|
||||||
/** the last update check result. */
|
/** the last update check result. */
|
||||||
string m_lastUpdateCheckResult;
|
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 {
|
result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output) const {
|
||||||
int signedValue;
|
|
||||||
if (!hasFlag(REQ) && value == m_replacement) {
|
if (!hasFlag(REQ) && value == m_replacement) {
|
||||||
return RESULT_EMPTY;
|
return RESULT_EMPTY;
|
||||||
}
|
}
|
||||||
@@ -814,9 +813,10 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
|
|||||||
} else {
|
} else {
|
||||||
negative = false;
|
negative = false;
|
||||||
}
|
}
|
||||||
|
int signedValue;
|
||||||
if (m_bitCount == 32) {
|
if (m_bitCount == 32) {
|
||||||
if (hasFlag(EXP)) { // IEEE 754 binary32
|
if (hasFlag(EXP)) { // IEEE 754 binary32
|
||||||
float val = uintToFloat(value);
|
float val = uintToFloat(value, negative);
|
||||||
if (val != val) { // !isnan(val)
|
if (val != val) { // !isnan(val)
|
||||||
return RESULT_EMPTY;
|
return RESULT_EMPTY;
|
||||||
}
|
}
|
||||||
@@ -830,7 +830,6 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
|
|||||||
*output = static_cast<float>(val);
|
*output = static_cast<float>(val);
|
||||||
return RESULT_OK;
|
return RESULT_OK;
|
||||||
}
|
}
|
||||||
// less than 32 bit
|
|
||||||
if (!negative) {
|
if (!negative) {
|
||||||
if (m_divisor < 0) {
|
if (m_divisor < 0) {
|
||||||
*output = static_cast<float>(value) * static_cast<float>(-m_divisor);
|
*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,
|
result_t NumberDataType::readFromRawValue(unsigned int value,
|
||||||
OutputFormat outputFormat, ostream* output) const {
|
OutputFormat outputFormat, ostream* output) const {
|
||||||
size_t length = (m_bitCount < 8) ? 1 : (m_bitCount/8);
|
size_t length = (m_bitCount < 8) ? 1 : (m_bitCount/8);
|
||||||
int signedValue;
|
|
||||||
// initialize output
|
// initialize output
|
||||||
*output << setw(0) << std::resetiosflags(output->flags()) << dec << std::skipws << setprecision(6);
|
*output << setw(0) << std::resetiosflags(output->flags()) << dec << std::skipws << setprecision(6);
|
||||||
|
|
||||||
@@ -888,6 +886,7 @@ result_t NumberDataType::readFromRawValue(unsigned int value,
|
|||||||
} else {
|
} else {
|
||||||
negative = false;
|
negative = false;
|
||||||
}
|
}
|
||||||
|
int signedValue;
|
||||||
if (m_bitCount == 32) {
|
if (m_bitCount == 32) {
|
||||||
if (hasFlag(EXP)) { // IEEE 754 binary32
|
if (hasFlag(EXP)) { // IEEE 754 binary32
|
||||||
float val = uintToFloat(value, negative);
|
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