ChimeraTK-DeviceAccess 03.25.00
Loading...
Searching...
No Matches
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
14namespace 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 {
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) {
93 _protocolImplementor->singleWordWrite(buffer);
94 break;
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:
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
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 */
The dummy device opens a mapping file instead of a device, and implements all registers defined in th...
RebotDummyServer(unsigned int portNumber, std::string mapFile, unsigned int protocolVersion)
static const uint32_t INSIDE_MULTI_WORD_WRITE
std::atomic< uint32_t > _heartbeatCount
static const uint32_t MULTI_WORD_WRITE
ip::tcp::socket _currentClientConnection
void writeWordToRequestedAddress(std::vector< uint32_t > &buffer)
void processReceivedPackage(std::vector< uint32_t > &buffer)
std::vector< uint32_t > _dataBuffer
static const uint32_t HELLO
RebotDummySession(unsigned int protocolVersion, ip::tcp::socket socket, std::shared_ptr< DummyBackend > regsiterSpace)
std::atomic< uint32_t > _helloCount
void sendSingleWord(int32_t response)
void readRegisterAndSendData(std::vector< uint32_t > &buffer)
static const uint32_t PING
void write(std::vector< uint32_t > data)
static const uint32_t MULTI_WORD_READ
static const int32_t READ_SUCCESS_INDICATION
std::unique_ptr< DummyProtocolImplementor > _protocolImplementor
static const int BUFFER_SIZE_IN_WORDS
static const int32_t UNKNOWN_INSTRUCTION
static const uint32_t SINGLE_WORD_WRITE
std::shared_ptr< DummyBackend > _registerSpace
std::atomic< bool > _dont_answer
std::atomic< bool > stop_rebot_server
STL namespace.
Only put commands which don't exist in all versions, or behave differently.
Only put commands which don't exist in all versions, or behave differently.