A CLI client using a QKnxNetIpRouter .
This example shows a CLI client using a QKnxNetIpRouter to monitor KNX frames sent by neighboring KNXnet/IP routers. It is a CLI interactive client that allows the user to send a predifined KNX frame on the default 224.0.23.12 multicast address that is the most commonly used in KNX installations.
Here are the parameters that the client allows. For example, the network interface used by the router and the multicast address used can be changed to the user's needs.
Options: -h, --help Displays this help. -n, --interface <InterfaceName> Sets the network interface name that the KNXnet/Ip routing interface will use. -m, --multicastAddress <multicastAddress> Sets the multicast address that the KNXnet/Ip routing interface will use for sending routing messages. -i, --indication Sends routing indication messages. -b, --busy Sends routing busy messages. --busyControlField <busyControlField> Sets the busy control field of busy messages. --busyWaitTime <busyWaitTime> Sets the wait time for busy messages. -l, --lost Sends routing lost messages. -r, --receiver Determines that this router will only work as a KNXnet/IP routing message receiver.
There are two main modes of using the example. One of the modes is using it as a receiver of KNX frames. In this mode no other messages can be sent. This mode is used to monitor KNXnet/IP frames and it can be achieved by running the example like this:
router -n eth0 --receiver
In the other mode, in addition to receiving KNX frames the router can send a unique type of KNX frames that has been predefined. The type of frame to use can be specified as a parameter in the command line.
For sending indication frames and receiving any other KNX frame the example can be run like this:
router -n eth0 --indication
In this last command the router will send an indication KNX frame every time the user hits the Enter . The router will also display information about KNX frames received on that network interface.
For sending busy frames and routing lost messages, the example has to be run in one of the following ways:
router -n eth0 --busy --busyWaitTime 30 router -n eth0 --lost
As explained above, it will send the predifined messages every time the user hits the Enter . However, the message sent can be customized by pasting the frame representation as a hexadecimal stream of bytes and hitting Enter .
Here is an example of how the example looks like when running it:
router -n enp0s31f6 -i 11:40:26 : Router is in Routing state. Network interface used: enp0s31f6 ( QHostAddress("10.9.78.59") ) Multicast address: QHostAddress("224.0.23.12") Type 'quit' to stop the application. Type the hexadecimal content of the indication and hit 'enter'. Setting no content by default uses 1100b4e000000002010000.
类 QKnxNetIpRouter used in this example allows sending and receiving routing KNXnet/IP packets to and from other KNXnet/IP routers. There are some helper functions that will be explained in the following lines.
The main function starts by instantiating the
QKnxNetIpRouter
class. After that, in order to have a functional router, certain properties of the
QKnxNetIpRouter
instance must be set up. This is done by the method
setupRouterSignalHandlers()
. The following code snippet shows where this happens:
int main(int argc, char *argv[]) { ... QKnxNetIpRouter router; setupRouterSignalHandlers(router, iface, multicastAddress);
The most important step to get a functional router is to assign it a network interface. That way, the router is ready for monitoring and sending KNX frames from/to other KNX routers and the KNX system connected to that same network.
void setupRouterSignalHandlers(QKnxNetIpRouter &router, const QNetworkInterface &iface, const QHostAddress &multicastAddress) { router.setInterfaceAffinity(iface); Q_ASSERT(router.interfaceAffinity().index() == iface.index()); router.setMulticastAddress(multicastAddress);
The next step consists of setting the handlers that allow monitoring KNXnet/IP frames received from neighboring KNX routers as well as the frames sent by this router.
void setupRouterSignalHandlers(QKnxNetIpRouter &router, const QNetworkInterface &iface, const QHostAddress &multicastAddress) { ... QObject::connect(&router, &QKnxNetIpRouter::routingIndicationReceived, [](QKnxNetIpFrame frame) { QKnxNetIpRoutingIndicationProxy indication(frame); qInfo().noquote() << "Received routing indication" << indication.isValid(); }); QObject::connect(&router, &QKnxNetIpRouter::routingBusyReceived, [](QKnxNetIpFrame frame) { QKnxNetIpRoutingBusyProxy busy(frame); qInfo().noquote() << "Received routing busy, wait time: " << busy.routingBusyWaitTime() << " busy control field: " << busy.routingBusyControl(); }); QObject::connect(&router, &QKnxNetIpRouter::routingLostCountReceived, [](QKnxNetIpFrame frame) { QKnxNetIpRoutingLostMessageProxy lost(frame); qInfo().noquote() << "Received routing lost count" << lost.deviceState(); }); QObject::connect(&router, &QKnxNetIpRouter::routingIndicationSent, [](QKnxNetIpFrame frame) { qInfo().noquote() << "Sent routing indication"; Q_UNUSED(frame); }); QObject::connect(&router, &QKnxNetIpRouter::routingBusySent, [](QKnxNetIpFrame frame) { qInfo().noquote() << "Sent routing busy"; Q_UNUSED(frame); }); QObject::connect(&router, &QKnxNetIpRouter::routingLostCountSent, [](QKnxNetIpFrame frame) { qInfo().noquote() << "Sent routing lost count"; Q_UNUSED(frame); }); }
The client can respond to the Enter press events and send predefined KNX messages. For this purpose a QTextStream instance is used and a handler installed for capturing the signal activated() emitted by the socket. The code below demonstrates this:
void setupRouterCLI(QKnxNetIpRouter &router, const QCommandLineParser &cliParser, QTextStream & input, #ifdef Q_OS_WIN QWinEventNotifier ¬ifier) { QObject::connect(¬ifier, &QWinEventNotifier::activated, [&](HANDLE) { #else QSocketNotifier ¬ifier) { QObject::connect(¬ifier, &QSocketNotifier::activated, [&](int) { #endif ... static const auto bytes = QKnxByteArray::fromHex("1100b4e000000002010000"); auto frame = QKnxLinkLayerFrame::builder() .setData(tmp.isEmpty() ? bytes : QKnxByteArray::fromHex(tmp)) .setMedium(QKnx::MediumType::NetIP) .createFrame(); auto indication = QKnxNetIpRoutingIndicationProxy::builder() .setCemi(frame) .create(); router.sendRoutingIndication(indication); ... }
The last thing before calling QCoreApplication::exec () is the QKnxNetIpRouter::start () call. The call notifies the router to initialize its internal data and enables it to begin receiving and sending KNX frames, as seen here:
void startRouter(QKnxNetIpRouter &router, const QCommandLineParser &cliParser) { router.start(); if (router.error() != QKnxNetIpRouter::Error::None) return; ... }
The
startRouter()
is a helper function that gets called at the end of main.
文件: