PdCom  5.0
Process data communication client
advanced_example.cpp

Base class for recieving notificationsThis class is in charge of passing notifications from the library to client code. Make sure that the subscriber outlives all assigned subscriptions.

/*****************************************************************************
*
* Copyright (C) 2021 Bjarne von Horn (vh at igh dot de).
*
* This file is part of the PdCom library.
*
* The PdCom library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* The PdCom library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the PdCom library. If not, see <http://www.gnu.org/licenses/>.
*
*****************************************************************************/
#include <cassert>
#include <cstdio>
#include <iostream>
#include <pdcom5/Process.h>
#include <termios.h>
#include <unistd.h>
// RAII helper to configure the shell
class TerminalGuard
{
termios old_;
public:
TerminalGuard()
{
tcgetattr(STDIN_FILENO, &old_);
termios newt = old_;
newt.c_lflag &= ~(ECHO | ICANON);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
}
~TerminalGuard() { tcsetattr(STDIN_FILENO, TCSANOW, &old_); }
};
class MyProcess :
{
size_t read(char *buf, size_t count) override
{
const size_t ans = posixRead(buf, count);
if (ans == 0)
running_ = false;
return ans;
}
void write(const char *buf, size_t count) override
{
posixWrite(buf, count);
}
void flush() override {}
public:
MyProcess(const char *host = "127.0.0.1", unsigned short port = 2345) :
PdCom::Process(),
PdCom::PosixProcess(host, port),
PdCom::Subscriber(
PdCom::event_mode) //{std::chrono::milliseconds(100)})
{}
void execute();
void connected();
void findReply(const PdCom::Variable &var) override
{
p1_ = var;
assert(!p1_.empty());
std::cout << "Found parameter!" << std::endl;
}
void stateChanged(PdCom::Subscription const &s) override
{
using State = PdCom::Subscription::State;
if (s.getState() == State::Active) {
if (&s == &s1_)
s1_active_ = true;
if (&s == &s2_)
s2_active_ = true;
}
else if (s.getState() == State::Invalid) {
std::cout << "Invalid subscription!" << std::endl;
running_ = false;
}
}
void newValues(std::chrono::nanoseconds /* time_ns */) override
{
std::cout << "New Data: ";
s1_.print(std::cout, ',');
std::cout << " and ";
s2_.print(std::cout, ',');
std::cout << "\n";
}
bool s1_active_ = false, s2_active_ = false;
bool running_ = true;
bool connected_ = false;
};
void MyProcess::connected()
{
std::cout << "Connected!" << std::endl;
s1_ = PdCom::Subscription(*this, *this, "/input/klemme1");
s2_ = PdCom::Subscription(*this, *this, "/input/klemme2");
find("/parameter01");
connected_ = true;
}
void MyProcess::execute()
{
fd_set fds;
const int max_fd = std::max<int>(fd_, STDIN_FILENO);
TerminalGuard tg;
while (running_ and !(s1_active_ and s2_active_ and !p1_.empty()))
asyncData();
std::cout << "Ready to rumble!" << std::endl;
while (running_) {
FD_ZERO(&fds);
FD_SET(fd_, &fds);
FD_SET(STDIN_FILENO, &fds);
select(max_fd + 1, &fds, NULL, NULL, NULL);
if (FD_ISSET(STDIN_FILENO, &fds) and !p1_.empty()) {
char buf;
std::cin.read(&buf, 1);
if (buf == 'q') {
break;
}
assert(p1_.setValue(static_cast<unsigned char>(buf)));
std::cout << "Changed Parameter to " << buf << std::endl;
}
if (FD_ISSET(fd_, &fds)) {
asyncData();
}
}
}
int main(int argc, char **argv)
{
// usage: example2 <host> <port>
MyProcess p(
argc >= 2 ? argv[1] : "127.0.0.1",
argc >= 3 ? strtoul(argv[2], nullptr, 10) : 2345);
p.execute();
}