ChimeraTK-DeviceAccess  03.18.00
RebotDummyServer.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2 // SPDX-License-Identifier: LGPL-3.0-or-later
3 
4 #include "RebotDummyServer.h"
5 
6 #include "DummyProtocol1.h" // the latest version includes all predecessors in the include
7 
8 #include <boost/asio.hpp>
9 #include <boost/bind/bind.hpp>
10 
11 #include <iostream>
12 #include <stdexcept>
13 
14 namespace ChimeraTK {
15 
16  std::atomic<bool> stop_rebot_server(false);
17 
19  unsigned int protocolVersion, ip::tcp::socket socket, std::shared_ptr<DummyBackend> registerSpace)
20  : _state(ACCEPT_NEW_COMMAND), _heartbeatCount(0), _helloCount(0), _dont_answer(false), _registerSpace(registerSpace),
21  _protocolVersion(protocolVersion), _currentClientConnection(std::move(socket)) {
22  if(protocolVersion == 0) {
23  _protocolImplementor.reset(new DummyProtocol0(*this));
24  }
25  else if(protocolVersion == 1) {
26  _protocolImplementor.reset(new DummyProtocol1(*this));
27  }
28  else {
29  throw std::invalid_argument("RebotDummyServer: unknown protocol version");
30  }
31  }
32 
33  /********************************************************************************************************************/
34 
36  doRead();
37  }
38 
40  auto self(shared_from_this());
41  std::shared_ptr<std::vector<uint32_t>> buffer;
42  buffer.reset(new std::vector<uint32_t>(RebotDummySession::BUFFER_SIZE_IN_WORDS));
43 
44  _currentClientConnection.async_read_some(
45  boost::asio::buffer(*buffer), [this, self, buffer](boost::system::error_code ec, std::size_t) {
46  if(ec) {
48  }
49  else {
50  processReceivedPackage(*buffer);
51  }
52  });
53  }
54 
56  if(_dataBuffer.empty()) {
57  doRead();
58  return;
59  }
60 
61  auto self(shared_from_this());
62  _currentClientConnection.async_write_some(
63  boost::asio::buffer(_dataBuffer), [this, self](boost::system::error_code ec, std::size_t) {
64  if(not ec) {
65  _dataBuffer.clear();
66  }
67  else {
68  std::cerr << ec << std::endl;
70  }
71  doRead();
72  });
73  }
74 
75  /********************************************************************************************************************/
76 
77  void RebotDummySession::processReceivedPackage(std::vector<uint32_t>& buffer) {
79  _state = _protocolImplementor->continueMultiWordWrite(buffer);
80  doWrite();
81  return;
82  }
83 
84  // cause an error condition: just don't answer
85  if(_dont_answer) {
86  doRead();
87  return;
88  }
89 
90  uint32_t requestedAction = buffer.at(0);
91  switch(requestedAction) {
92  case SINGLE_WORD_WRITE:
93  _protocolImplementor->singleWordWrite(buffer);
94  break;
95  case MULTI_WORD_WRITE:
96  _state = _protocolImplementor->multiWordWrite(buffer);
97  break;
98  case MULTI_WORD_READ:
99  _protocolImplementor->multiWordRead(buffer);
100  break;
101  case HELLO:
102  ++_helloCount;
103  _protocolImplementor->hello(buffer);
104  break;
105  case PING:
106  ++_heartbeatCount;
107  _protocolImplementor->ping(buffer);
108  break;
109  default:
110  std::cout << "Instruction unknown in all protocol versions " << requestedAction << std::endl;
112  }
113 
114  doWrite();
115  }
116 
117  /********************************************************************************************************************/
118 
119  void RebotDummySession::writeWordToRequestedAddress(std::vector<uint32_t>& buffer) {
120  // byte and address must be uint64_t (uint8_t/uint32_t combination not allowed in DummyBackend any more)
121  uint64_t registerAddress = buffer.at(1); // This is the word offset; since
122  // dummy device deals with byte
123  // addresses convert to bytes FIXME
124  registerAddress = registerAddress * 4;
125  int32_t wordToWrite = buffer.at(2);
126  uint64_t bar = 0;
127  _registerSpace->write(bar, registerAddress, &wordToWrite, sizeof(wordToWrite));
128  }
129 
130  /********************************************************************************************************************/
131 
132  void RebotDummySession::readRegisterAndSendData(std::vector<uint32_t>& buffer) {
133  // byte and address must be uint64_t (uint8_t/uint32_t combination not allowed in DummyBackend any more)
134  uint64_t registerAddress = buffer.at(1); // This is a word offset. convert to bytes before use. FIXME
135  registerAddress = registerAddress * 4;
136  uint32_t numberOfWordsToRead = buffer.at(2);
137 
138  // send data in two packets instead of one; this is done for test coverage.
139  // Let READ_SUCCESS_INDICATION go in the first write and data in the second.
141 
142  std::vector<uint32_t> dataToSend(numberOfWordsToRead);
143  uint64_t bar = 0;
144  // start putting in the read values from location dataToSend[1]:
145  int32_t* startAddressForReadInData = reinterpret_cast<int32_t*>(dataToSend.data());
146  _registerSpace->read(bar, registerAddress, startAddressForReadInData, numberOfWordsToRead * sizeof(int32_t));
147 
148  // FIXME: Nothing in protocol to indicate read failure.
149  write(dataToSend);
150  }
151 
152  void RebotDummySession::write(std::vector<uint32_t> dataToSend) {
153  _dataBuffer.insert(_dataBuffer.end(), dataToSend.begin(), dataToSend.end());
154  }
155 
156  /********************************************************************************************************************/
157 
158  void RebotDummySession::sendSingleWord(int32_t response) {
159  _dataBuffer.push_back(response);
160  }
161 
162  /********************************************************************************************************************/
163 
165  // if the terminate signal is caught while waiting for a connection
166  // there is no client connection, so we have to check the pointer here
167  _currentClientConnection.close();
168  }
169 
170  /********************************************************************************************************************/
171 
172  RebotDummyServer::RebotDummyServer(unsigned int portNumber, std::string mapFile, unsigned int protocolVersion)
173  : _protocolVersion(protocolVersion), _io(), _connectionAcceptor(_io, ip::tcp::endpoint(ip::tcp::v4(), portNumber)),
174  _socket(_io), _registerSpace(std::make_shared<DummyBackend>(mapFile)) {
175  // The first address of the register space is set to a reference value. This
176  // would be used to test the rebot client.
177  uint64_t registerAddress = 0x04;
178  int32_t wordToWrite = 0xDEADBEEF; // Change this to someting standardized
179  // later (eg FW version ..)
180  uint64_t bar = 0;
181  _registerSpace->open();
182  _registerSpace->write(bar, registerAddress, &wordToWrite, sizeof(wordToWrite));
183  }
184 
185  void RebotDummyServer::do_accept() {
186  _connectionAcceptor.async_accept(_socket, [this](boost::system::error_code ec) {
187  if(not ec) {
188  if(_currentSession.expired()) {
189  auto newSession = std::make_shared<RebotDummySession>(_protocolVersion, std::move(_socket), _registerSpace);
190  _currentSession = newSession;
191  newSession->start();
192  }
193  else {
194  auto code = boost::system::errc::make_error_code(boost::system::errc::connection_refused);
195  _socket.close(code);
196  }
197  }
198  do_accept();
199  });
200  }
201 
203  do_accept();
204  _io.run();
205  }
206 
208  _io.stop();
209  }
210 
212  return not _io.stopped();
213  }
214 
215 } /* namespace ChimeraTK */
ChimeraTK::RebotDummySession::~RebotDummySession
virtual ~RebotDummySession()
Definition: RebotDummyServer.cc:164
ChimeraTK::RebotDummySession::_protocolImplementor
std::unique_ptr< DummyProtocolImplementor > _protocolImplementor
Definition: RebotDummyServer.h:68
RebotDummyServer.h
ChimeraTK::RebotDummyServer::is_running
bool is_running()
Definition: RebotDummyServer.cc:211
ChimeraTK::RebotDummySession::BUFFER_SIZE_IN_WORDS
static const int BUFFER_SIZE_IN_WORDS
Definition: RebotDummyServer.h:36
ChimeraTK::RebotDummySession::_registerSpace
std::shared_ptr< DummyBackend > _registerSpace
Definition: RebotDummyServer.h:62
DummyProtocol1.h
ChimeraTK::RebotDummySession::_heartbeatCount
std::atomic< uint32_t > _heartbeatCount
Definition: RebotDummyServer.h:58
ChimeraTK::RebotDummySession::MULTI_WORD_READ
static const uint32_t MULTI_WORD_READ
Definition: RebotDummyServer.h:45
ChimeraTK::stop_rebot_server
std::atomic< bool > stop_rebot_server
ChimeraTK::DummyProtocol0
Only put commands which don't exist in all versions, or behave differently.
Definition: DummyProtocol0.h:12
ChimeraTK::RebotDummySession::sendSingleWord
void sendSingleWord(int32_t response)
Definition: RebotDummyServer.cc:158
ChimeraTK::RebotDummySession::PING
static const uint32_t PING
Definition: RebotDummyServer.h:47
ChimeraTK::RebotDummySession::HELLO
static const uint32_t HELLO
Definition: RebotDummyServer.h:46
ChimeraTK::RebotDummySession::INSIDE_MULTI_WORD_WRITE
static const uint32_t INSIDE_MULTI_WORD_WRITE
Definition: RebotDummyServer.h:53
ChimeraTK::RebotDummySession::READ_SUCCESS_INDICATION
static const int32_t READ_SUCCESS_INDICATION
Definition: RebotDummyServer.h:37
ChimeraTK::RebotDummySession::_dont_answer
std::atomic< bool > _dont_answer
Definition: RebotDummyServer.h:61
ChimeraTK::RebotDummySession::SINGLE_WORD_WRITE
static const uint32_t SINGLE_WORD_WRITE
Definition: RebotDummyServer.h:43
ChimeraTK::RebotDummySession::MULTI_WORD_WRITE
static const uint32_t MULTI_WORD_WRITE
Definition: RebotDummyServer.h:44
ChimeraTK::RebotDummySession::UNKNOWN_INSTRUCTION
static const int32_t UNKNOWN_INSTRUCTION
Definition: RebotDummyServer.h:41
ChimeraTK::RebotDummyServer::stop
void stop()
Definition: RebotDummyServer.cc:207
ChimeraTK::RebotDummySession::_currentClientConnection
ip::tcp::socket _currentClientConnection
Definition: RebotDummyServer.h:67
ChimeraTK::RebotDummySession::start
void start()
Definition: RebotDummyServer.cc:35
ChimeraTK::RebotDummyServer::RebotDummyServer
RebotDummyServer(unsigned int portNumber, std::string mapFile, unsigned int protocolVersion)
Definition: RebotDummyServer.cc:172
ChimeraTK::RebotDummySession::processReceivedPackage
void processReceivedPackage(std::vector< uint32_t > &buffer)
Definition: RebotDummyServer.cc:77
ChimeraTK::RebotDummySession::writeWordToRequestedAddress
void writeWordToRequestedAddress(std::vector< uint32_t > &buffer)
Definition: RebotDummyServer.cc:119
ChimeraTK::RebotDummySession::doWrite
void doWrite()
Definition: RebotDummyServer.cc:55
ChimeraTK::RebotDummySession::write
void write(std::vector< uint32_t > data)
Definition: RebotDummyServer.cc:152
ChimeraTK::RebotDummySession::RebotDummySession
RebotDummySession(unsigned int protocolVersion, ip::tcp::socket socket, std::shared_ptr< DummyBackend > regsiterSpace)
Definition: RebotDummyServer.cc:18
ChimeraTK::RebotDummySession::_state
uint32_t _state
Definition: RebotDummyServer.h:56
ChimeraTK::RebotDummySession::doRead
void doRead()
Definition: RebotDummyServer.cc:39
ChimeraTK::DummyBackend
The dummy device opens a mapping file instead of a device, and implements all registers defined in th...
Definition: DummyBackend.h:45
ChimeraTK::RebotDummySession::_dataBuffer
std::vector< uint32_t > _dataBuffer
Definition: RebotDummyServer.h:63
ChimeraTK::DummyProtocol1
Only put commands which don't exist in all versions, or behave differently.
Definition: DummyProtocol1.h:12
ChimeraTK
Definition: DummyBackend.h:16
ChimeraTK::RebotDummySession::readRegisterAndSendData
void readRegisterAndSendData(std::vector< uint32_t > &buffer)
Definition: RebotDummyServer.cc:132
ChimeraTK::RebotDummyServer::start
void start()
Definition: RebotDummyServer.cc:202
ChimeraTK::RebotDummySession::_helloCount
std::atomic< uint32_t > _helloCount
Definition: RebotDummyServer.h:59