blob: 6f74321e59ba1fb281cfc3a55d08bb59dcaee778 [file] [log] [blame]
/*
* BaSyxNativeProvider.h
*
* Created on: 14.08.2018
* Author: schnicke
*/
#ifndef VAB_VAB_PROVIDER_NATIVE_BASYXNATIVEPROVIDER_H
#define VAB_VAB_PROVIDER_NATIVE_BASYXNATIVEPROVIDER_H
#include <BaSyx/shared/types.h>
#include <BaSyx/util/tools/CoderTools.h>
#include <BaSyx/vab/backend/connector/native/frame/Frame.h>
#include <BaSyx/vab/provider/native/frame/BaSyxNativeFrameProcessor.h>
#include <BaSyx/log/log.h>
#include <BaSyx/abstraction/net/Buffer.h>
#include <asio.hpp>
/**
* Provies access based on the basyx native protocol
*/
namespace basyx {
namespace vab {
namespace provider {
namespace native {
class NativeProvider {
private:
// Connection socket
asio::ip::tcp::socket & clientSocket;
// Frame processor
frame::BaSyxNativeFrameProcessor * frameProcessor;
// Buffers
static constexpr std::size_t default_buffer_size = 4096;
std::array<char, default_buffer_size> recv_buffer;
std::array<char, default_buffer_size> send_buffer;
bool closed;
basyx::log log;
public:
NativeProvider(asio::ip::tcp::socket & clientSocket,
frame::BaSyxNativeFrameProcessor* frameProcessor)
: clientSocket(clientSocket)
, frameProcessor(frameProcessor)
, closed(false)
, log{ "NativeProvider" }
{
}
~NativeProvider()
{
// Connection no longer needed, close it
try
{
if (this->clientSocket.is_open())
this->clientSocket.close();
}
catch (std::exception & e)
{
log.warn("Exception in closing socket");
};
}
// Has to be called repeatedly
void update()
{
log.trace("Updating...");
if (!closed)
{
asio::error_code ec;
log.trace("Waiting for incoming message");
auto input_frame = recvFrame(ec);
if(ec) {
log.info("Connection closed");
closed = true;
}
else {
log.trace("Received frame.");
log.info("Received: {}", input_frame.getFirstValue());
auto output_frame = frameProcessor->processInputFrame(input_frame);
log.info("Sending reply.");
auto bytes_sent = sendFrame(output_frame);
if (bytes_sent < 0) {
log.error("Sending failed: {}", "ERROR");
closed = true;
}
}
}
}
bool isClosed()
{
return closed;
}
std::size_t sendData(char* data, std::size_t size)
{
log.debug("Sending {} bytes.", size);
std::size_t bytes_sent = this->clientSocket.send(asio::buffer(data, size));
log.debug("Sent {} bytes.", bytes_sent);
return bytes_sent;
};
std::size_t receiveData(char* data, asio::error_code & ec)
{
std::size_t bytes_read = this->clientSocket.receive(asio::buffer(recv_buffer.data(), recv_buffer.size()), 0, ec);
log.debug("Received {} bytes.", bytes_read);
return bytes_read;
};
std::size_t sendFrame(const connector::native::Frame & frame)
{
connector::native::Frame::write_to_buffer(
basyx::net::make_buffer(
send_buffer.data() + BASYX_FRAMESIZE_SIZE, default_buffer_size - BASYX_FRAMESIZE_SIZE),
frame);
auto size_field = reinterpret_cast<uint32_t*>(&send_buffer[0]);
*size_field = frame.size();
return sendData(send_buffer.data(), frame.size() + BASYX_FRAMESIZE_SIZE);
};
connector::native::Frame recvFrame(asio::error_code & ec)
{
this->receiveData(recv_buffer.data(), ec);
auto size = *reinterpret_cast<uint32_t*>(recv_buffer.data());
auto frame = connector::native::Frame::read_from_buffer(
basyx::net::make_buffer(this->recv_buffer.data() + BASYX_FRAMESIZE_SIZE, size - BASYX_FRAMESIZE_SIZE)
);
return frame;
};
};
};
};
};
};
#endif /* VAB_VAB_PROVIDER_NATIVE_BASYXNATIVEPROVIDER_H */