BAOS SDK v2  1.2.1
An SDK providing access to IP-BAOS devices through BAOS binary protocol version 2.x
Loading...
Searching...
No Matches
09_BaosView.cpp

This sample is a console application with a mini visualisation for the current data point values and configuration. Every time a datapoint value indication is received the view is updated and shows the new value. For it to work properly the complete view must be visible inside the console windows without scrolling. Scrolling or resizing the console window will mess up the writing of the updated datapoint values on the correct position. This sample heavilly relies on the ANSI Escape sequences to move the cursor in the console, if those are not available in your console, this sample will not work as expected.

Usage:

09_BaosView <ip_address>
// e.g.:
09_BaosView 10.0.0.102
//
// Copyright (c) 2002-2026 WEINZIERL ENGINEERING GmbH
// All rights reserved.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,
// WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
//
#include "Helper.h"
#include <baos/Sdk.h>
#include <wzcpp/features/utils/Formatter.h>
#include <iostream>
#include <memory>
#include <thread>
using namespace wz::baos;
using namespace wz::baos::ip;
using namespace wz::baos::protocol;
/******************************************
** Anonymous namespace
*******************************************/
namespace
{
{
std::string result;
result += flags.communication ? "C " : "- ";
result += flags.readFromBus ? "R " : "- ";
result += flags.writeFromBus ? "W " : "- ";
result += flags.transmitToBus ? "T " : "- ";
result += flags.updateResponse ? "U " : "- ";
result += flags.readOnInit ? "I " : "- ";
return result;
}
enum ColumnWidths
{
Id = 6,
DPT = 38,
Flags = 13,
Data = 25
};
class BaosView
{
public:
BaosView(const std::string& ip4Address, std::uint16_t port = 12004)
: device_(ip4Address, port)
{
}
public:
void print()
{
// read all valid datapoint values
const DatapointValues values = device_.getAllDpValuesRaw(true);
// header
// like:
// |------|---------------|------------------------|-------------|------------------------|
// | Id | DPT | Description | Flags | Data |
// | | | | C R W T U I | (in hex) |
// |------|---------------|------------------------|-------------|------------------------|
std::cout << "|" << std::string(ColumnWidths::Id, '-') << "|" << std::string(ColumnWidths::DPT, '-') << "|"
<< std::string(ColumnWidths::DescriptionString, '-') << "|" << std::string(ColumnWidths::Flags, '-')
<< "|" << std::string(ColumnWidths::Data, '-') << "|" << std::endl;
std::cout << "|" << std::setfill(' ') << std::setw(ColumnWidths::Id) << "Id "
<< "|" << std::setfill(' ') << std::setw(ColumnWidths::DPT) << "DPT "
<< "|" << std::setfill(' ') << std::setw(ColumnWidths::DescriptionString) << "Description "
<< "|" << std::setfill(' ') << std::setw(ColumnWidths::Flags) << "Flags "
<< "|" << std::setfill(' ') << std::setw(ColumnWidths::Data) << "Data "
<< "|" << std::endl;
std::cout << "|" << std::setfill(' ') << std::setw(ColumnWidths::Id) << ""
<< "|" << std::setfill(' ') << std::setw(ColumnWidths::DPT) << ""
<< "|" << std::setfill(' ') << std::setw(ColumnWidths::DescriptionString) << ""
<< "|" << std::setfill(' ') << std::setw(ColumnWidths::Flags) << "C R W T U I "
<< "|" << std::setfill(' ') << std::setw(ColumnWidths::Data) << "(in hex) "
<< "|" << std::endl;
std::cout << "|" << std::string(ColumnWidths::Id, '-') << "|" << std::string(ColumnWidths::DPT, '-') << "|"
<< std::string(ColumnWidths::DescriptionString, '-') << "|" << std::string(ColumnWidths::Flags, '-')
<< "|" << std::string(ColumnWidths::Data, '-') << "|" << std::endl;
// body
// like:
// | 1 |DPT 01 - 1 bit | Actuator A - Switch | C R W T U I | 00 |
// |------|---------------|------------------------|-------------|------------------------|
if(dp_configs_.empty())
{
std::cout << "No datapoints configured" << std::endl;
return;
}
for (const auto& item : limitedDps)
{
const std::uint16_t dpId = item.first;
const DatapointConfig& desc = item.second;
lastDpId_ = dpId;
// Get datapoint value when valid
std::string formatedValue = "-- ";
auto iter = values.find(dpId);
if (iter != values.end())
{
formatedValue = wzcpp::rangeToHex(iter->second);
}
// fields
std::cout << "|" << std::setfill(' ') << std::setw(ColumnWidths::Id) << dpId << "|" << std::setfill(' ')
<< std::setw(ColumnWidths::DPT) << dptToString(desc.dpt) << "|" << std::setfill(' ')
<< std::setw(ColumnWidths::DescriptionString) << desc.desc << "|" << std::setfill(' ')
<< std::setw(ColumnWidths::Flags) << formatFlags(desc.flags) << "|" << std::setfill(' ')
<< std::setw(ColumnWidths::Data-1) << formatedValue << " |" << std::endl;
// seperator line
std::cout << "|" << std::string(ColumnWidths::Id, '-') << "|" << std::string(ColumnWidths::DPT, '-') << "|"
<< std::string(ColumnWidths::DescriptionString, '-') << "|" << std::string(ColumnWidths::Flags, '-')
<< "|" << std::string(ColumnWidths::Data, '-') << "|" << std::endl;
}
// Saves the current cursor position
// It is the end of our table view
std::cout << "\u001b[s";
auto omitted = dp_configs_.size() - limitedDps.size();
if(omitted > 0)
{
std::cout << omitted << " Datapoints omitted" << std::endl;
}
}
{
device_.registerDPValueCallback(
[this](const DatapointValues& values)
{
try
{
for (const auto& item : values)
{
std::uint16_t id = item.first;
const DatapointValue& value = item.second;
this->updateView(id, value);
}
}
catch (const std::exception&)
{
}
});
}
private:
{
auto endDpIter = std::begin(dp_configs_);
if(dp_limit < dp_configs_.size())
{
std::advance(endDpIter, dp_limit);
}
else
{
endDpIter = std::end(dp_configs_);
}
return DatapointConfigurations {std::begin(dp_configs_), endDpIter};
}
{
device_.getStaticInfo();
dp_configs_ = device_.getAllDpConfigurations();
}
std::uint32_t getReverseRowIndexForDpId(std::uint16_t dpId)
{
auto endDpIter = std::begin(dp_configs_);
auto iter = cutConfigs.find(dpId);
return std::distance(iter, cutConfigs.end());
}
void updateView(std::uint16_t dpId, const DatapointValue& value)
{
std::string formatedValue = wzcpp::rangeToHex(value);
std::uint32_t cursorUp = (rowIndex * 2); // cell
std::uint32_t cursorRight = 1 + ColumnWidths::Id + 1 + ColumnWidths::DPT + 1 + ColumnWidths::DescriptionString + 1 +
ColumnWidths::Flags + 1 + 1; // begin of cell data
std::cout << "\u001b[u"; // Move to table end (it's our store point)
std::cout << "\u001b[3B"; // Move cursor 3 lines down for status message
if(dpId > lastDpId_)
{
std::cout << "+ Skipped updating: datapoint id(" << dpId <<"): " << wzcpp::rangeToHex(value) << " ";
std::cout << "\u001b[u"; // Move to table's end (it's our store point)
}
else
{
std::cout << "+ Updating the view: datapoint id(" << dpId <<"): " << wzcpp::rangeToHex(value) << " ";
std::cout << "\u001b[u"; // Move to table's end (it's our store point)
// Move to the cell for the datapoint value
std::cout << "\u001b["<< cursorUp << "A";
std::cout << "\u001b[" << cursorRight << "G";
// Clear the data cell
std::cout << "\u001b[0K";
// Write the new value
std::cout << "\u001b[36m" << std::setfill(' ') << std::setw(ColumnWidths::Data-1) << formatedValue << "\u001b[39m" << " |";
// Move to table end (it's our store point)
std::cout << "\u001b[u";
}
}
private:
BaosIp4Device device_;
std::uint16_t lastDpId_{0};
const std::uint32_t dp_limit{5};
};
} // end anonymous namespace
/******************************************
** Main
*******************************************/
int main(int argc, char* argv[])
{
try
{
std::cout << "\u001b[2J"; // erase screen
std::cout << "\u001b[H"; // move cursor to home
std::cout << "******************************************" << std::endl;
std::cout << "09_BaosView sample" << std::endl;
std::cout << "******************************************" << std::endl;
std::cout << std::endl;
// Reduce log messages
setBaosLogLevel(wz::baos::LogLevel::warn);
// The CommandLineOptions::parse function
// validates the arguments and handles the help command
CommandLineOptions options;
options.setDurationOptionSupported(true);
options.parse(argc, argv);
if (options.wasHelpdisplayed())
{
return 0;
}
// Get the ip address from the parsed command line options
const std::string ipAddress = options.getIpAddress();
std::cout << " Connection requested for " << ipAddress << std::endl;
BaosView baosView{ipAddress};
// create a TPC/IP connection to the remote BAOS device
baosView.print();
baosView.watchForIndications();
// Default behaviour is interactive: wait for user input.
// For automated runs the sample can terminate automatically after N seconds.
if (options.isInteractive())
{
// Wait for Enter, all indications will be shown in the callback event handlers.
std::cout << "Press [Enter] to exit the application ..." << std::endl;
std::getchar();
}
else
{
// Wait for End, all indications will be shown in the callback event handlers.
const std::int32_t durationSeconds = options.getDurationSeconds();
std::cout << "Listening for indications for " << durationSeconds << " seconds ..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(durationSeconds));
}
std::cout << "\u001b[3B";
std::cout << "Bye ..." << std::endl;
}
catch (const std::exception& e)
{
std::cerr << "Failed: " << e.what() << std::endl;
return -1;
}
return 0;
}
Specialization for a IP v4 BAOSDevice.
Specialization for a TCP IP v4 BAOSConnection.
Global BAOS protocol defines and types.
Global BAOS SDK function and options.
Definition Helper.h:23
A specialization for (connection oriented) connection to the BAOS device via a TCP connection.
Definition BaosTcpConnection.h:182
Represents a BAOS IP4 device with an underlying TCP connection (with BAOS unsecure connection-less)
Definition BaosIpv4Device.h:55
Groups BAOS binary protocol specific types , defines and classes for Indications, Responses etc.
Definition Defines.h:33
std::map< std::uint16_t, DatapointValue > DatapointValues
A map with datapoint ids as keys and DatapointValue as values.
Definition Defines.h:36
BAOSLIB_EXPORT std::string dptToString(DPT dpt)
Convert the enum value to a human readable string.
DPT
Enumeration value for the supported datapoint types( DPTs )
Definition Defines.h:173
wz::baos::Buffer DatapointValue
An type for the DatapointValues.
Definition Defines.h:34
Global BAOS sdk namespace.
Definition config.h:69
BAOSLIB_EXPORT void setBaosLogLevel(wz::baos::LogLevel level)
std::map< std::uint16_t, DatapointConfig > DatapointConfigurations
Definition BaosDeviceDataTypes.h:212
Information about a datapoint object.
Definition BaosDeviceDataTypes.h:201
std::string desc
Definition BaosDeviceDataTypes.h:205
protocol::DatapointConfigFlags flags
Definition BaosDeviceDataTypes.h:203
protocol::DPT dpt
Definition BaosDeviceDataTypes.h:204
Struct for the communication flags of a datapoint. See KNX spec for more details.
Definition Defines.h:444
std::uint8_t writeFromBus
The writable from bus flag.
Definition Defines.h:511
std::uint8_t readOnInit
The perform read request in onit flag.
Definition Defines.h:512
std::uint8_t updateResponse
Define the bitfield for the flags and transmitPriority.
Definition Defines.h:514
std::uint8_t communication
Definition Defines.h:509
std::uint8_t transmitToBus
The devices send changes on the group object to the KNX bus.
Definition Defines.h:513
std::uint8_t readFromBus
The readable from bus flag.
Definition Defines.h:510