BAOS SDK v2  1.0.1
An SDK providing access to IP-BAOS devices through BAOS binary protocol version 2.x
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-2023 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 <iostream>
#include <memory>
using namespace wz::baos;
using namespace wz::baos::ip;
using namespace wz::baos::protocol;
/******************************************
** Anonymous namespace
*******************************************/
namespace
{
std::string formatFlags(const protocol::DatapointConfigFlags& flags)
{
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,
DescriptionString = 30,
Flags = 13,
Data = 25
};
class BaosView
{
public:
BaosView(const std::string& ip4Address, std::uint16_t port = 12004)
: device_(ip4Address, port)
{
loadInitialDeviceInfo();
}
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;
}
const DatapointConfigurations limitedDps = getLimitedDpConfigs();
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;
}
}
void watchForIndications()
{
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:
DatapointConfigurations getLimitedDpConfigs()
{
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};
}
void loadInitialDeviceInfo()
{
device_.getStaticInfo();
dp_configs_ = device_.getAllDpConfigurations();
}
std::uint32_t getReverseRowIndexForDpId(std::uint16_t dpId)
{
auto endDpIter = std::begin(dp_configs_);
const DatapointConfigurations cutConfigs = getLimitedDpConfigs();
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 rowIndex = getReverseRowIndexForDpId(dpId);
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(wzcpp::LogLevel::warn);
// The CommandLineOptions::parse function
// validates the arguments and handles the help command
CommandLineOptions options;
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
BaosIp4Device baosDevice(ipAddress);
baosView.print();
baosView.watchForIndications();
// wait for Enter, all indications will be shown
// in the callback handler
std::cout << "Press [Enter] to exit the application ..." << std::endl;
std::getchar();
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
Groups BAOS binary protocol specific types , defines and classes for Indications, Responses etc.
Definition: Defines.h:32
std::map< std::uint16_t, DatapointValue > DatapointValues
A map with datapoint ids as keys and DatapointValue as values.
Definition: Defines.h:35
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:172
wz::baos::Buffer DatapointValue
An type for the DatapointValues.
Definition: Defines.h:33
Global BAOS sdk namespace.
Definition: config.h:62
std::map< std::uint16_t, DatapointConfig > DatapointConfigurations
Definition: BaosDeviceDataTypes.h:212
void setBaosLogLevel(wzcpp::LogLevel level)