BPNGClientLib
Library for accessing the Telemotive data logger devices
User's manual - BLUEPIRAT Client Library 5.1.0.8

General

This is the documentation for the C++ BLUEPIRAT Client library which is compatible with all Microsoft compilers. The library's interface class IBPNGClient uses only base data type parameters like int, long and char, pointers to those types and pointers to complex proprietary data objects that are entirely defined within the library. To access the data of such objects the library comes with own interface definitions for all of those complex data types (like e.g. IConversionSet, see BPNGDefines.h). All library functions are blocking functions. Status and progress information is processed via listener callbacks (see IBPNGClientListener). Errors are processed by the functions' return values (see section Error handling for more details).

Functionality

The BLUEPIRAT Client Library provides methods for base functionality like:

Besides that there are several more functions for deleting data, setting the logger's/TSL time and marker, scanning the network for available loggers/TSL, etc.

Error handling and listener mechanism

All errors are processed by the functions' return values. If the return value states an error a call to getLastError() provides details about the error(s) occurred. Warnings are not intended to abort a process. That's why they are reported via the function IBPNGClientListener::onWarning(). It's up to the user to handle them or not.

Progress and status information is also processed via listener callbacks. You have to derive your own class from IBPNGClientListener and implement all functions you need. Register an object of your listener class at the executing IBPNGClient with IBPNGClient::addListener().

Thread safety

The library is thread safe when using different objects of IBPNGClient resp. the objects' pointers in different threads. It is NOT thread safe for one IBPNGClient instance in several threads!

Demo project

The "sample" directory contains a demo project for the BLUEPIRAT Client Library.

Exampe for lib unsage:

//************************************************************
//
// BPNGClientLibTest.cc
//
//************************************************************
// sys
#include <algorithm>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <dirent.h>
#include <getopt.h>
#include <iostream>
#include <iomanip>
#include <set>
#include <sstream>
#include <string>
#include <unistd.h>
#include <utility>
#include <vector>
// tmlib
// following two includes will be removed for clientlib release
#include <utility.hh>
#include <fileutils.hh>
// atom
#include <RdbDefines.h>
// client
#include <BPNGDefines.h>
#include <IBPNGClient.h>
// test
#include "RdbEventList.hh"
#include "clientUtil.hh"
using namespace std;
using namespace std::chrono;
const char DEFAULT_TARGET_IP[] = "192.168.0.233";
const char DEFAULT_IP[] = "0.0.0.0";
enum ConfigMode
{
CONFIG_NONE = 0,
CONFIG_GET = 0x01,
CONFIG_SET = 0x02,
CONFIG_DEFAULT = 0x04,
CONFIG_ALL = CONFIG_GET | CONFIG_SET | CONFIG_DEFAULT
};
static ConfigMode toConfig(const char *arg)
{
if (!strcmp(arg, "get"))
return CONFIG_GET;
else if (!strcmp(arg, "set"))
return CONFIG_SET;
else if (!strcmp(arg, "default"))
return CONFIG_DEFAULT;
else if (!strcmp(arg, "all"))
return CONFIG_ALL;
else
return CONFIG_NONE;
}
static BPNGBugreportMode toBugreport(const char *arg)
{
if (!strcmp(arg, "full"))
else if (!strcmp(arg, "logs"))
return BR_ONLY_LOGS;
else if (!strcmp(arg, "client"))
else if (!strcmp(arg, "db"))
return BR_FDB_RDB;
else if (!strcmp(arg, "all"))
else if (!strcmp(arg, "traces"))
else
}
static vector<string> readZipsFromDirectory(string dir)
{
vector<string> output;
DIR* directory = opendir(dir.c_str());
struct dirent* entry = readdir(directory);
string file;
while (entry != nullptr)
{
file = entry->d_name;
if (file.find(".zip") != string::npos)
{
output.push_back(file);
}
entry = readdir(directory);
}
closedir(directory);
return output;
}
static string getLocalDateString()
{
time_t t;
tm tt;
ostringstream buffer;
time(&t);
localtime_r(&t, &tt);
buffer << std::put_time(&tt, "%F_%H-%M-%S");
return buffer.str();
}
static string unixtimeToLocaltime(uint64_t unixtime)
{
time_t t;
tm tt;
ostringstream buffer;
t = time_t(unixtime / 1000000UL);
localtime_r(&t, &tt);
buffer << std::put_time(&tt, "%F_%H-%M-%S");
return buffer.str();
}
/************************************************
* Client function *
************************************************/
static void checkForTslNeighbor(const string &ip, const string &ipNeigbor,
const BPNGLoggerDetector &listener,
{
OnlineLoggerInfo oli = listener.getLoggerInfoForIP(ipNeigbor.c_str());
// cout << "OnlineLoggerInfo: " << oli << endl;
string eth0 = oli.tslEth0IP;
string eth1 = oli.tslEth1IP;
if (ip != DEFAULT_IP && (eth0 == ip || eth1 == ip))
tsl.addDevice(oli);
if (eth0 != ip && eth0 != DEFAULT_IP && !eth0.empty())
checkForTslNeighbor(ipNeigbor, oli.tslEth0IP, listener, tsl);
if (eth1 != ip && eth1 != DEFAULT_IP && !eth1.empty())
checkForTslNeighbor(ipNeigbor, oli.tslEth1IP, listener, tsl);
}
static TSLClusterImpl getTslNetwork(const char *ip, const BPNGLoggerDetector &listener)
{
cout << __func__ << ": ip=" << ip << endl;
OnlineLoggerInfo oli = listener.getLoggerInfoForIP(ip);
TSLClusterImpl cluster(oli);
cout << "OnlineLoggerInfo: " << oli << endl;
string eth0 = oli.tslEth0IP;
string eth1 = oli.tslEth1IP;
if (eth0 != DEFAULT_IP && !eth0.empty())
checkForTslNeighbor(ip, eth0, listener, cluster);
if (eth1 != DEFAULT_IP && !eth1.empty())
checkForTslNeighbor(ip, eth1, listener, cluster);
return cluster;
}
static bool connectInitLogger(const char *module, IBPNGClient *bpngClient,
TSLClusterImpl tsl, bool initialize = true)
{
cout << module << ": connect Logger... ";
bool ret = false;
if (tsl.getTSLSize() > 1)
{
bpngClient->setTSLCluster(tsl.getTSLCluster());
ret = bpngClient->connect();
}
else
{
ret = bpngClient->connectLogger(1, &tsl.getTSLCluster().loggerArray[0]);
}
if (ret)
{
cout << "OK" << endl;
}
else
{
BPNGError err = bpngClient->getLastError();
cout << "Failed to connect tsl. " << endl;
cout << "BPNGErrCode: " << err.code << ", " << err.msg << endl;
bpngClient->release();
return false;
}
if (!initialize)
return true;
cout << "init online... ";
if (bpngClient->initialize())
{
cout << "OK" << endl;
}
else
{
BPNGError err = bpngClient->getLastError();
cerr << "init online failed: " << err.msg << endl;
bpngClient->disconnectLogger();
return false;
}
return true;
}
static void setTimeTest(TSLClusterImpl tsl)
{
if (!connectInitLogger(__func__, bpng, tsl))
{
cerr << "Failed to initialize logger connection to " << tsl.getTSLName() << ", abort." << endl;
return;
}
for (int i = 0; i < 5; i++)
{
auto tnow = system_clock::now() + system_clock::duration(seconds(i * 100));
if (bpng->setTime(system_clock::to_time_t(tnow)))
cout << "loop " << i << ": settime ok test time " << tnow << " ok" << endl;
else
cerr << "loop " << i << ": settime to test time " << tnow << " failed" << endl;
auto tget = system_clock::from_time_t(bpng->getCurrentLoggerTime());
cout << "loop " << i << ": returned " << tget << endl;
sleep(5);
}
auto tnow = system_clock::now();
if (bpng->setTime(system_clock::to_time_t(tnow)))
cout << "settime to correct time ok" << endl;
else
cerr << "settime to correct time failed" << endl;
cout << "Test finished" << endl;
}
static void getTimeTest(TSLClusterImpl tsl)
{
cout << "bpng=" << bpng << endl;
if (!connectInitLogger(__func__, bpng, tsl))
{
cerr << "Failed to initialize logger connection to " << tsl.getTSLName() << ", abort." << endl;
return;
}
for (int i = 0; i < 4; i++)
{
auto tget = system_clock::from_time_t(bpng->getCurrentLoggerTime());
cout << "loop " << i << ": get " << tget << endl;
sleep(5);
}
}
static void configTest(TSLClusterImpl tsl, const char *path, const vector<ConfigMode> &config)
{
if (!connectInitLogger(__func__, bpng, tsl))
{
cerr << "Failed to initialize logger connection to " << tsl.getTSLName() << ", abort." << endl;
return;
}
for (auto c : config)
{
if (c & CONFIG_GET)
{
ostringstream targetPath;
targetPath << path << "/Config_";
if (tsl.getTSLSize() == 1)
{
targetPath << tsl.getTSLCluster().loggerArray[0].name << '_';
targetPath << tsl.getTSLCluster().loggerArray[0].mbnr;
}
else
{
targetPath << "bPTSL_" << tsl.getTSLName();
}
targetPath << '_' << getLocalDateString();
// get and save current config
cout << "configTest: get and save config...";
if (!bpng->getConfig(targetPath.str().c_str()))
{
BPNGError err = bpng->getLastError();
cerr << "download configuration failed: " << err.msg << endl;
return;
}
}
if (c & CONFIG_DEFAULT)
{
// setting the default config
cout << "configTest: set default config...";
if (!bpng->setDefaultConfig())
{
BPNGError err = bpng->getLastError();
cerr << "default config failed: " << err.msg << endl;
return;
}
}
if (c & CONFIG_SET)
{
// FIXME:
// Logger does not load the new config.
// Logger will only accept config zip files with format:
// bpng_*_date_time.zip
// here you could change the downloaded configuration
// by extracting it and modifying the xml files
// see documentation of IBPNGClient::getConfig()
// or IBPNGClient::reconfigLogger().
// the new config archive needs a date in its filename in this form: YYYY-MM-DD_HH-MM-SS
vector<string> configZips = readZipsFromDirectory(path);
vector<OnlineLoggerInfoStringPair> pairs;
vector<string> paths;
for (const auto &iter : tsl)
{
for (size_t i = 0; i != configZips.size(); ++i)
{
string configZip = configZips[i];
if (configZip.find(iter.mbnr) != string::npos)
{
cout << configZips[i] << endl;
pair.key = iter;
ostringstream zipPath;
zipPath << path << '/' << configZip;
paths.push_back(zipPath.str());
pair.value = paths.back().c_str();
cout << "pair.value: " << pair.value << endl;
pairs.push_back(pair);
break;
}
}
}
// We use the same config that we downloaded
cout << "configTest: restore original config...";
if (!bpng->reconfigLogger(pairs.size(), &pairs[0]))
{
BPNGError err = bpng->getLastError();
cerr << "reconfigurating logger failed: " << err.msg << endl;
cout << "BPNGErrCode: " << err.code << ", " << err.msg << endl;
return;
}
}
}
// disconnect
}
static void bugreportTest(TSLClusterImpl tsl, const char *path, BPNGBugreportMode mode)
{
if (!connectInitLogger(__func__, bpng, tsl))
{
cerr << "Failed to initialize logger connection to " << tsl.getTSLName() << ", abort." << endl;
return;
}
uint64_t startTime = 0;
uint64_t endTime = 0;
if (mode == BR_FULL_ALL_TRACES)
{
// get start and end time of all traces
cout << "get trace block table..." << endl;
IRdbTraceBlockList *traceBlocklist = bpng->getTraceBlockList();
RdbTraceBlockList blocks(traceBlocklist);
blocks.sortTraceBlocksById();
startTime = blocks.begin()->m_DataStartTimeUTC;
endTime = blocks.end()->m_DataEndTimeUTC;
}
string destination = "/tmp";
char fullPath[PATH_MAX];
char * resultPath = realpath(path, fullPath);
if (resultPath)
destination = fullPath;
// name of Bureport file
string zipName = "Bugreport_";
if (tsl.getTSLSize() > 1)
zipName += tsl.getTSLName();
else
zipName += tsl.begin()->name;
destination += "/";
destination += zipName;
int result = bpng->downloadBugReport(destination.c_str(), mode, startTime, endTime);
if (result == 0)
{
BPNGError err = bpng->getLastError();
cerr << "download Bugreport failed: " << err.msg << endl;
}
else if (result < 0)
{
cerr << "download Bugreport failed: user aborted erase!" << endl;
}
else
{
cout << "download Bugreport successfull finished. Location: " << destination << endl;
}
// disconnect
}
static void downloadTest(TSLClusterImpl tsl, const char *path, bool all = false)
{
IBPNGClient *bpngClient = getBPNGClient();
string loggername = (tsl.getTSLSize() == 1) ? tsl.begin()->name : tsl.getTSLName();
if (!connectInitLogger(__func__, bpngClient, tsl))
{
cerr << "Failed to initialize logger connection to " << loggername << ", abort." << endl;
return;
}
uint64_t startId = 0;
cout << "get events..." << endl;
IRdbEventList *list = bpngClient->getEventList();
RdbEventList eventList(list);
if (eventList.size() == 0)
{
cout << "Empty event list" << endl;
bpngClient->disconnectLogger();
return;
}
// search last startup
for (int i = eventList.size() - 1; i >= 0; --i)
{
if (eventList[i].type == STARTUP)
{
startId = eventList[i].uniqueID;
break;
}
}
cout << "get trace block table..." << endl;
IRdbTraceBlockList *traceBlocklist = bpngClient->getTraceBlockList();
RdbTraceBlockList blocks(traceBlocklist);
blocks.sortTraceBlocksById();
// if you want to download several spans, put them in a vector
vector<DataSpan> spanVec;
// target path as output string
ostringstream starget;
if (all)
{
uint64_t max = 0;
if (!blocks.empty())
max = blocks.back().m_DataBaseEntryId;
DataSpan span;
cout << "create data span, startID = " << startId << ", endID = " << max << endl;
span.type = 0;
span.start = startId;
span.end = max;
spanVec.push_back(span);
starget << path << '/' << loggername << '_'
<< unixtimeToLocaltime(blocks.front().m_DataStartTimeUTC) << '_'
<< unixtimeToLocaltime(blocks.back().m_DataEndTimeUTC) << ".zip";
}
else
{
// download selected time span
// always from startup to shutdown event
const uint64_t us = 1000000U;
time_t startTime, endTime;
tm starttm;
tm endtm;
// start time
starttm.tm_sec = 0;
starttm.tm_min = 0;
starttm.tm_hour = 0;
starttm.tm_mday = 6;
starttm.tm_mon = 4 - 1;
starttm.tm_year = 2020 - 1900;
starttm.tm_wday = 0;
starttm.tm_yday = 0;
starttm.tm_isdst = 0;
// end time
endtm.tm_sec = 59;
endtm.tm_min = 59;
endtm.tm_hour = 23;
endtm.tm_mday = 6;
endtm.tm_mon = 4 - 1;
endtm.tm_year = 2020 - 1900;
endtm.tm_wday = 0;
endtm.tm_yday = 0;
endtm.tm_isdst = 0;
startTime = timegm(&starttm) * us;
endTime = timegm(&endtm) * us;
cout << "select time span: " << std::put_time(&starttm, "%F %T") << ".." << std::put_time(&endtm, "%F %T %Z") << endl;
DataSpan span;
span.type = 0;
span.start = 0;
span.end = 0;
size_t startblock = 0, endblock = 0;
cout << "block size: " << blocks.size() << endl;
for (size_t i = 0; i < blocks.size(); i++)
{
//cout << "entry id: " << blocks[i].m_DataBaseEntryId << " | timespan: " << unixtimeToLocaltime(blocks[i].m_DataStartTimeUTC) << ".." << unixtimeToLocaltime(blocks[i].m_DataEndTimeUTC) << endl;
if ((blocks[i].m_DataStartTimeUTC <= startTime && blocks[i].m_DataEndTimeUTC >= startTime)
|| (i > 0 && blocks[i].m_DataStartTimeUTC >= startTime && blocks[i-1].m_DataEndTimeUTC <= startTime)
|| (i == 0 && blocks[i].m_DataStartTimeUTC >= startTime))
{
span.start = blocks[i].m_DataBaseEntryId;
startblock = i;
}
if ((blocks[i].m_DataStartTimeUTC <= endTime && blocks[i].m_DataEndTimeUTC >= endTime)
|| (i+1 < blocks.size() && blocks[i+1].m_DataStartTimeUTC >= endTime && blocks[i].m_DataEndTimeUTC <= endTime)
|| (i == blocks.size() - 1 && blocks[i].m_DataEndTimeUTC <= endTime))
{
span.end = blocks[i].m_DataBaseEntryId;
endblock = i;
}
}
spanVec.push_back(span);
cout << "selected id span: " << span.start << ".." << span.end << endl;
starget << path << '/' << loggername << '_'
<< unixtimeToLocaltime(blocks[startblock].m_DataStartTimeUTC) << '_'
<< unixtimeToLocaltime(blocks[endblock].m_DataEndTimeUTC) << ".zip";
}
const string &target = starget.str();
cout << "download data to " << target << endl;
if (!bpngClient->downloadDataSpans(spanVec.size(), &spanVec[0], target.c_str(), 0))
{
BPNGError err = bpngClient->getLastError();
cerr << "download failed: " << err.msg << endl;
}
bpngClient->disconnectLogger();
}
static void onlineConversionTest(TSLClusterImpl tsl, const char *path, bool all)
{
if (!connectInitLogger(__func__, bpng, tsl, true))
{
cerr << "Failed to initialize logger connection to " << tsl.getTSLName() << ", abort." << endl;
return;
}
const uint64_t us = 1000000U;
time_t startTime, endTime;
tm starttm;
tm endtm;
if (all)
{
// convert all
startTime = 0;
endTime = time(nullptr);
gmtime_r(&startTime, &starttm);
gmtime_r(&endTime, &endtm);
}
else
{
// convert specific time span (adapt this to your needs)
starttm.tm_sec = 0;
starttm.tm_min = 0;
starttm.tm_hour = 0;
starttm.tm_mday = 8;
starttm.tm_mon = 1 - 1;
starttm.tm_year = 2020 - 1900;
starttm.tm_wday = 0;
starttm.tm_yday = 0;
starttm.tm_isdst = 0;
endtm.tm_sec = 59;
endtm.tm_min = 59;
endtm.tm_hour = 23;
endtm.tm_mday = 9;
endtm.tm_mon = 12 - 1;
endtm.tm_year = 2020 - 1900;
endtm.tm_wday = 0;
endtm.tm_yday = 0;
endtm.tm_isdst = 1;
startTime = mktime(&starttm);
endTime = mktime(&endtm);
}
cout << "select time span: " << std::put_time(&starttm, "%F %T") << ".." << std::put_time(&endtm, "%F %T %Z") << endl;
cs->addTimeSpan(startTime * us, endTime * us);
const IChannelList *channels = bpng->getLoggerChannels();
cout << "channels = " << channels << endl;
if (!channels)
{
cerr << "no logger channels found" << endl;
return;
}
const auto nchannels = channels->getSize();
cout << "#channels = " << nchannels << endl;
set<ChannelType> ignoredChannels;
// With IConversionSet::addChannel() we have to add those channels to the conversion set that we want to convert.
// The required format is passed as third argument. Channels that should be written to the same output file
// must be added to IConversionSet with the same 'fileId' argument (and of course same formatId).
// In this sample we only want to convert CAN channels according to this:
// CAN #1 and CAN #2 are supposed to be written to one CANOE asc output file each.
// CAN #3 and CAN #4 are supposed to be written together to another CANOE asc file.
// All other CAN channels are supposed to be written together to one BLF file.
for (int i = 0; i < nchannels; ++i)
{
const IChannel &channel = *channels->getChannel(i);
const ChannelType type = channel.getType();
const int index = channel.getIndex();
// cout << "ch = " << type << endl;
if (type == CH_CAN)
{
// Note: channel indices are zero based
if (index == 0 || index == 1)
{
// CAN #1 and #2 in separate files
// -1 as fileId parameter creates a separate file for this channel
cs->addChannel(type,
index,
-1,
channel.getOffset(),
channel.getMainboardNumber(),
channel.isMappingActive(),
}
else if (index == 2 || index == 3)
{
// CAN #3 and #4 in the same file.
// fileId != -1 will write all channels with the same format and same
// file Id to the same output file (if procurable in accordance with
// the format specification.
cs->addChannel(type,
index,
10,
channel.getOffset(),
channel.getMainboardNumber(),
channel.isMappingActive(),
}
else
{
// All other CAN channels to one BLF file.
cs->addChannel(type,
index,
BLF,
20,
channel.getOffset(),
channel.getMainboardNumber(),
channel.isMappingActive(),
}
}
else
{
ignoredChannels.insert(type);
break;
}
}
for (auto c : ignoredChannels)
cerr << "Ignored channel typ " << c << endl;
ignoredChannels.clear();
cout << "Converting data to \"" << path << '"' << endl;
if (!bpng->convertData(cs, path))
{
BPNGError err = bpng->getLastError();
cerr << "online conversion failed: " << err.msg << endl;
bpng->release();
return;
}
}
static void offlineConversionTest(const char *offlinefile, const char *path, bool all)
{
// register all messages and conversion formats
bpng->registerAll();
// set offline data
bpng->setOfflineData(offlinefile);
BOOL ret = bpng->initialize();
if (ret == 0)
{
BPNGError err = bpng->getLastError();
cout << "Failed to init offline." << endl;
cout << "BPNGErrCode: " << err.code << ", " << err.msg << endl;
bpng->release();
return;
}
// Ensure the output directory exists
ret = mkdirPath(path);
if (ret != 0 && errno != EEXIST)
{
cout << "Failed to create output directory" << endl;
bpng->release();
return;
}
const uint64_t us = 1000000U;
time_t startTime, endTime;
tm starttm;
tm endtm;
if (all)
{
// convert all
startTime = 0;
endTime = time(nullptr);
gmtime_r(&startTime, &starttm);
gmtime_r(&endTime, &endtm);
}
else
{
// convert specific time span (adapt this to your needs)
starttm.tm_sec = 0;
starttm.tm_min = 0;
starttm.tm_hour = 0;
starttm.tm_mday = 8;
starttm.tm_mon = 1 - 1;
starttm.tm_year = 2020 - 1900;
starttm.tm_wday = 0;
starttm.tm_yday = 0;
starttm.tm_isdst = 0;
endtm.tm_sec = 59;
endtm.tm_min = 59;
endtm.tm_hour = 23;
endtm.tm_mday = 9;
endtm.tm_mon = 12 - 1;
endtm.tm_year = 2020 - 1900;
endtm.tm_wday = 0;
endtm.tm_yday = 0;
endtm.tm_isdst = 1;
startTime = mktime(&starttm);
endTime = mktime(&endtm);
}
cout << "select time span: " << std::put_time(&starttm, "%F %T") << ".." << std::put_time(&endtm, "%F %T %Z") << endl;
cs->addTimeSpan(startTime * us, endTime * us);
const IChannelList *channels = bpng->getLoggerChannels();
cout << "channels = " << channels << endl;
if (!channels)
{
cerr << "no logger channels found" << endl;
return;
}
const auto nchannels = channels->getSize();
cout << "#channels = " << nchannels << endl;
set<ChannelType> ignoredChannels;
// With IConversionSet::addChannel() we have to add those channels to the conversion set that we want to convert.
// The required format is passed as third argument. Channels that should be written to the same output file
// must be added to IConversionSet with the same 'fileId' argument (and of course same formatId).
// In this sample we only want to convert CAN channels according to this:
// CAN #1 and CAN #2 are supposed to be written to one CANOE asc output file each.
// CAN #3 and CAN #4 are supposed to be written together to another CANOE asc file.
// All other CAN channels are supposed to be written together to one BLF file.
for (int i = 0; i < nchannels; ++i)
{
const IChannel &channel = *channels->getChannel(i);
const ChannelType type = channel.getType();
const int index = channel.getIndex();
// cout << "ch = " << type << endl;
if (type == CH_CAN)
{
// Note: channel indices are zero based
if (index == 0 || index == 1)
{
// CAN #1 and #2 in separate files
// -1 as fileId parameter creates a separate file for this channel
cs->addChannel(type,
index,
-1,
channel.getOffset(),
channel.getMainboardNumber(),
channel.isMappingActive(),
}
else if (index == 2 || index == 3)
{
// CAN #3 and #4 in the same file.
// fileId != -1 will write all channels with the same format and same
// file Id to the same output file (if procurable in accordance with
// the format specification.
cs->addChannel(type,
index,
10,
channel.getOffset(),
channel.getMainboardNumber(),
channel.isMappingActive(),
}
else
{
// All other CAN channels to one BLF file.
cs->addChannel(type,
index,
BLF,
20,
channel.getOffset(),
channel.getMainboardNumber(),
channel.isMappingActive(),
}
}
else
{
ignoredChannels.insert(type);
break;
}
}
for (auto c : ignoredChannels)
cerr << "Ignored channel typ " << c << endl;
ignoredChannels.clear();
cout << "Converting data to \"" << path << '"' << endl;
if (!bpng->convertData(cs, path))
{
BPNGError err = bpng->getLastError();
cerr << "offline conversion failed: " << err.msg << endl;
bpng->release();
return;
}
}
static void eraseTest(TSLClusterImpl tsl, bool all = true)
{
if (!connectInitLogger(__func__, bpng, tsl))
{
cerr << "Failed to initialize logger connection to " << tsl.getTSLName() << ", abort." << endl;
return;
}
if (all)
{
cout << "delete all data... ";
if (bpng->deleteAllData())
{
cout << "OK" << endl;
}
else
{
BPNGError err = bpng->getLastError();
cerr << "deletion failed: " << err.msg << endl;
return;
}
}
else
{
cout << "get events..." << endl;
IRdbEventList *list = bpng->getEventList();
RdbEventList eventList(list);
if (eventList.size() == 0)
{
cout << "Empty event list" << endl;
return;
}
// download selected time span
// always from startup to shutdown event
const uint64_t us = 1000000U;
time_t startTime, endTime;
tm starttm;
tm endtm;
// start time
starttm.tm_sec = 0;
starttm.tm_min = 0;
starttm.tm_hour = 0;
starttm.tm_mday = 20;
starttm.tm_mon = 3 - 1;
starttm.tm_year = 2020 - 1900;
starttm.tm_wday = 0;
starttm.tm_yday = 0;
starttm.tm_isdst = 0;
// end time
endtm.tm_sec = 59;
endtm.tm_min = 59;
endtm.tm_hour = 23;
endtm.tm_mday = 22;
endtm.tm_mon = 3 - 1;
endtm.tm_year = 2020 - 1900;
endtm.tm_wday = 0;
endtm.tm_yday = 0;
endtm.tm_isdst = 0;
startTime = timegm(&starttm) * us;
endTime = timegm(&endtm) * us;
cout << "select time span: " << std::put_time(&starttm, "%F %T") << ".." << std::put_time(&endtm, "%F %T %Z") << endl;
vector<size_t> startUpIds;
// search for startup at starttime and endtime
for (size_t i = 0; i < eventList.size(); i++)
{
if (eventList[i].type == STARTUP)
{
//cout << "event ID: " << eventList[i].uniqueID << " timestamp: " unixtimeToLocaltime(eventList[i].timeStamp) << endl;
if ((eventList[i].timeStamp >= startTime && eventList[i].timeStamp <= endTime)
|| (i > 0 && eventList[i-1].timeStamp <= startTime && eventList[i].timeStamp >= startTime)
|| (i + 1 < eventList.size() && eventList[i+1].timeStamp >= endTime && eventList[i].timeStamp <= endTime))
{
startUpIds.push_back(eventList[i].uniqueID);
cout << "event ID: " << eventList[i].uniqueID << " timestamp: "
<< unixtimeToLocaltime(eventList[i].timeStamp) << endl;
}
}
}
cout << "number of StartUpIds: " << startUpIds.size() << endl;
int eraseResult = bpng->deleteSectionsByStartUpIds(startUpIds.size(), &startUpIds[0]);
if (eraseResult == 0)
{
BPNGError err = bpng->getLastError();
cerr << "erase failed: " << err.msg << endl;
}
else if (eraseResult < 0)
{
cerr << "erase failed: user aborted erase!" << endl;
}
else
{
cout << "erase successfull finished" << endl;
}
}
}
static void restartDeviceTest(TSLClusterImpl tsl, bool waitForRestart)
{
if (!connectInitLogger(__func__, bpng, tsl))
{
cerr << "Failed to initialize logger connection to " << tsl.getTSLName() << ", abort." << endl;
return;
}
cout << "restart device(s)... ";
if (bpng->restartDevice(waitForRestart))
{
cout << "OK" << endl;
}
else
{
BPNGError err = bpng->getLastError();
cerr << "restart failed: " << err.msg << endl;
return;
}
}
static void help(const char *prog)
{
cout << "Usage: " << prog << " <options>\n\n"
<< "Test client lib, where <options> are\n\n";
cout << " " << "--all, -a" << " " << "Download, erase or convert all data, not just a limited set" << endl;
cout << " " << "--config=<TYPE>, -c<TYPE>" << " " << "Get config, set config, set to default and restore it.\n" <<
" TYPE={get, default}" << endl << endl;
cout << " " << "--download, -d" << " " << "Download data from loggers" << endl;
cout << " " << "--erase, -e" << " " << "Erase data on loggers" << endl;
cout << " " << "--ipAddress[=<IP>], -i[<IP>]" << " " << "IP address of target (default=" << DEFAULT_TARGET_IP << ")" << endl;
cout << " " << "--tsl=<NAME>, -t<NAME>" << " " << "TSL name of target." << endl;
cout << " " << "--path[=<PATH>], -p[<PATH>]" << " " << "Path where to to store e.g. download data, \n" <<
" default is the current directory, for configs this is a file path" << endl << endl;
cout << " " << "--gettime, -g" << " " << "Get time on loggers" << endl;
cout << " " << "--settime, -s" << " " << "Set time on loggers" << endl << endl;
cout << " " << "--offline-conversion=<FILE>, -o<FILE>" << " " << "Convert offline data" << endl << endl;
cout << " " << "--online-conversion=<FILE>, -O" << " " << "Convert online data" << endl << endl;
cout << " " << "--restart[=<waitForRestart>], -r<waitForRestart>" << " " << "Restarts the loggers (default='0'(false))" << endl;
cout << " " << "--bugreport[=<mode>], -b<mode>" << " " << "Download Bugreport (default='full')" << endl;
cout << " " << "--help, -h" << " " << "This screen." << endl;
cout << " " << "--verbose, -v" << " " << "Increase verbosity. Can be specified more than once." << endl;
}
int main(int argc, char *argv[])
{
int c, option_index = 0;
unsigned int verbose = 0;
const char * const prog = progname(argv[0]);
string ip = DEFAULT_TARGET_IP;
const char *path = ".";
const char *offlinePath = nullptr;
string tslName;
bool all = false;
bool settime = false;
bool gettime = false;
vector<ConfigMode> config;
bool download = false;
bool erase = false;
bool tsl = false;
bool onlineConversion = false;
bool doNothing = false;
bool restart = false;
bool waitForRestart = false;
bool bugreport = false;
static const struct option long_options[] =
{
{"help", no_argument, nullptr, 'h'},
{"verbose", no_argument, nullptr, 'v'},
{"all", no_argument, nullptr, 'a'},
{"config", required_argument, nullptr, 'c'},
{"download", no_argument, nullptr, 'd'},
{"erase", no_argument, nullptr, 'e'},
{"ipAddress", optional_argument, nullptr, 'i'},
{"tsl", required_argument, nullptr, 't'},
{"path", optional_argument, nullptr, 'p'},
{"settime", no_argument, nullptr, 's'},
{"gettime", no_argument, nullptr, 'g'},
{"offline-conversion", required_argument, nullptr, 'o'},
{"online-conversion", no_argument, nullptr, 'O'},
{"restart", optional_argument, nullptr, 'r'},
{"bugreport", optional_argument, nullptr, 'b'},
{ nullptr } // Always last entry. Needed to finish parameter list.
};
while ((c = getopt_long(argc, argv, "ac:deghi:o:Op:svt:r:b:", long_options, &option_index)) != -1)
{
switch (c)
{
case 'a':
all = true;
break;
case 'c':
if (optarg)
config.push_back(toConfig(optarg));
break;
case 'd':
download = true;
break;
case 'e':
erase = true;
break;
case 'i':
if (optarg)
ip = optarg;
break;
case 't':
tsl = true;
if (optarg)
tslName = optarg;
break;
case 'p':
if (optarg)
path = optarg;
break;
case 's':
settime = true;
break;
case 'g':
gettime = true;
break;
case 'o':
offlinePath = optarg;
break;
case 'O':
onlineConversion = true;
break;
case 'r':
restart = true;
if (optarg)
waitForRestart = atoi(optarg);
break;
case 'b':
bugreport = true;
if (optarg)
brMode = toBugreport(optarg);
break;
case 'v':
verbose++;
break;
case 'h':
help(prog);
doNothing = true;
break;
default:
// already handled by lib
doNothing = true;
break;
}
}
if (offlinePath)
{
if (verbose)
offlineConversionTest(offlinePath, path, all);
doNothing = true;
}
if (!doNothing)
{
// Get list of all currently available blue PiraT 2 devices
BPNGLoggerDetector detector(ip, verbose);
vector<OnlineLoggerInfoWrapper> listOfDevices = detector.getLoggerList(0);
vector<TSLClusterImpl> listOfTslCluster = detector.getTSLs(listOfDevices);
// select the device you want to work with
// OnlineLoggerInfo device;
// for (size_t i = 0; i < listOfDevices.size(); ++i)
// {
// cout << "[" << i << "]: " << listOfDevices[i] << endl;
// if (strcmp(listOfDevices[i].ip, "192.168.0.233") == 0)
// {
// device = listOfDevices[i];
// break;
// }
// }
// map for tsl's
TSLClusterImpl targetTsl;
for (size_t i = 0; i < listOfTslCluster.size(); ++i)
{
TSLClusterImpl tslCluster = listOfTslCluster[i];
cout << "Found TSL [" << tslCluster.getTSLName() << "] with devices\n";
tslCluster.print();
cout << "\n";
/* insert target tsl name here*/
if (tsl && tslCluster.getTSLName() == tslName)
{
targetTsl = tslCluster;
}
}
if (!tsl)
{
targetTsl = getTslNetwork(ip.c_str(), detector);
}
if (targetTsl.begin() != targetTsl.end())
{
cout << "targetTsl [" << targetTsl.getTSLName() << "] with devices\n";
targetTsl.print();
cout << "---------------------------------------------------------\n";
if (settime)
setTimeTest(targetTsl);
if (gettime)
getTimeTest(targetTsl);
if (!config.empty())
configTest(targetTsl, path, config);
if (download)
downloadTest(targetTsl, path, all);
if (onlineConversion)
onlineConversionTest(targetTsl, path, all);
if (bugreport)
bugreportTest(targetTsl, path, brMode);
if (erase)
{
detector.excludeRCTFromTSL(targetTsl);
eraseTest(targetTsl, all);
}
if (restart)
restartDeviceTest(targetTsl, waitForRestart);
}
else
{
cout << "No target set!" << endl;
}
}
return EXIT_SUCCESS;
}