DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
DaphneV2Interface.cpp
Go to the documentation of this file.
1
8
10#include "logging/Logging.hpp"
11#include <sys/time.h>
12
13using namespace dunedaq::daphnemodules;
14
15DaphneV2Interface::DaphneV2Interface(const char* ipaddr, int port, std::chrono::milliseconds timeout)
16 : m_timeout(timeout)
17{
18
19 m_connection_id = socket(AF_INET, SOCK_DGRAM, 0);
20
21 if (m_connection_id < 0)
22 throw SocketCreationError(ERS_HERE);
23
24 m_target.sin_family = AF_INET;
25 m_target.sin_port = htons(port);
26 auto ret = inet_pton(AF_INET, ipaddr, &(m_target.sin_addr));
27 if (ret <= 0)
28 throw InvalidIPAddress(ERS_HERE, ipaddr);
29
30 m_ip = ipaddr;
31
33 throw FailedPing(ERS_HERE, ipaddr, port);
34}
35
36void
42
43bool
45{
46
47 auto ret = read_register(0xaa55, 1);
48
49 static const uint64_t good_value = 0xdeadbeef;
50 return ret[0] == good_value;
51}
52
54DaphneV2Interface::send_command_retry(std::string cmd, size_t retry) const
55{
56
57 do {
58 try {
59 auto ret = send_command(cmd);
60 return ret;
61 } catch (const CommandTimeout& e) {
62 ers::warning(e);
63 --retry;
64 } catch (const ers::Issue& e) {
65 throw FailedSocketInteraction(ERS_HERE, cmd, e);
66 }
67
68 } while (retry > 0);
69
71}
72
74DaphneV2Interface::send_command_interruptible(std::string cmd, std::function<bool()> can_retry) const
75{
76
77 do {
78 try {
79 auto ret = send_command(cmd);
80 return ret;
81 } catch (const CommandTimeout& e) {
82 ers::warning(e);
83 } catch (const ers::Issue& e) {
84 throw FailedSocketInteraction(ERS_HERE, cmd, e);
85 }
86
87 } while (can_retry());
88}
89
91DaphneV2Interface::send_command(std::string cmd) const
92{
93
94 TLOG() << "Board: " << m_ip << ", sending command " << cmd;
95 std::vector<uint64_t> bytes;
96 for (char ch : cmd) {
97 bytes.push_back(static_cast<uint64_t>(ch));
98 }
99 bytes.push_back(0x0d); // dedicated command flag
100
101 const std::lock_guard<std::mutex> lock(m_command_mutex);
102
103 // we send the bytes in chunks of 50 words
104 for (size_t i = 0; i < (bytes.size() + 49) / 50; ++i) {
105 std::vector<uint64_t> part(bytes.begin() + i * 50, bytes.begin() + std::min((i + 1) * 50, bytes.size()));
106 write_buffer(0x90000000, std::move(part));
107 }
108
109 TLOG() << "Board: " << m_ip << ", Command sent, waiting for result";
110
111 command_result res;
112 std::string* writing_pointer = nullptr;
113
114 auto start_time = std::chrono::high_resolution_clock::now();
115
116 int more = 40;
117 while (more > 0) {
118 auto data_block = read_buffer(0x90000000, 50);
119 for (size_t i = 0; i < data_block.size(); ++i) {
120 if (data_block[i] == 255) {
121 break;
122 } else if (data_block[i] == 1) {
123 // the following data are returning the command that was issued
124 writing_pointer = &res.command;
125 } else if (data_block[i] == 2) {
126 // the following data are the immediate command response
127 writing_pointer = &res.result;
128 } else if (data_block[i] == 3) {
129 // this is the message end
130 writing_pointer = nullptr;
131 } else if (isprint(static_cast<int>(data_block[i]))) {
132 more = 40;
133 char c = static_cast<char>(data_block[i]);
134 if (writing_pointer) {
135 *writing_pointer += static_cast<char>(data_block[i]);
136 } else {
137 TLOG() << "Failed adding charachter " << c;
138 }
139 }
140 }
141 auto now = std::chrono::high_resolution_clock::now();
142
143 auto delay = now - start_time;
144
145 if (delay > m_timeout) {
146 TLOG() << "Details of timeout";
147 for (size_t i = 0; i < data_block.size(); ++i) {
148 TLOG() << i << "\t" << std::hex << data_block[i] << std::dec;
149 }
150 TLOG() << "Received so far: " << res.result;
151 auto delay_us = std::chrono::duration_cast<std::chrono::microseconds>(delay);
152 throw CommandTimeout(ERS_HERE, cmd, delay_us.count());
153 }
154
155 std::this_thread::sleep_for(std::chrono::milliseconds(1));
156 --more;
157 }
158
159 return res;
160}
161
162std::vector<uint64_t>
163DaphneV2Interface::read(uint8_t command_id, uint64_t addr, uint8_t size) const
164{
165
166 const std::lock_guard<std::mutex> lock(m_access_mutex);
167
168 uint8_t cmd[10];
169 cmd[0] = command_id;
170 cmd[1] = size;
171 memcpy(cmd + 2, &addr, sizeof(uint64_t));
172 auto result = sendto(m_connection_id, cmd, sizeof(cmd), 0, (struct sockaddr*)&m_target, sizeof(m_target));
173
174 if (result < 0)
175 throw FailedSocketInteraction(ERS_HERE, "sendto");
176
177 struct timeval timeout;
178 timeout.tv_sec = m_timeout.count() / 1000;
179 timeout.tv_usec = (m_timeout.count() % 1000) * 1000;
180 fd_set readfds, masterfds;
181
182 FD_ZERO(&masterfds);
183 FD_SET(m_connection_id, &masterfds);
184
185 memcpy(&readfds, &masterfds, sizeof(fd_set));
186
187 auto start_time = std::chrono::high_resolution_clock::now();
188
189 if (select(m_connection_id + 1, &readfds, NULL, NULL, &timeout) < 0) {
190 throw FailedSocketInteraction(ERS_HERE, "select");
191 }
192
193 std::vector<uint64_t> ret_value;
194
195 if (FD_ISSET(m_connection_id, &readfds)) {
196 uint8_t buffer[2 + (8 * size)];
197 socklen_t addrlen = sizeof(m_target);
198 result = recvfrom(m_connection_id, buffer, sizeof(buffer), 0, (struct sockaddr*)&m_target, &addrlen);
199
200 if (result <= 0)
201 throw FailedSocketInteraction(ERS_HERE, "recvfrom");
202
203 uint8_t fmt[4 + size];
204 fmt[0] = '<';
205 fmt[1] = 'B';
206 fmt[2] = 'B';
207 fmt[3] = size;
208 for (int i = 0; i < size; i++) {
209 fmt[4 + i] = 'Q';
210 }
211
212 for (int i = 0; i < size; i++) {
213 uint64_t value;
214 memcpy(&value, buffer + 2 + (8 * i), sizeof(uint64_t));
215 ret_value.push_back(value);
216 }
217
218 } else {
219 // the socket timedout
220 auto end_time = std::chrono::high_resolution_clock::now();
221 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
222
223 throw SocketTimeout(ERS_HERE, duration.count());
224 }
225
226 return ret_value;
227}
228
229void
230DaphneV2Interface::write(uint8_t command_id, uint64_t addr, std::vector<uint64_t>&& data) const
231{
232
233 const std::lock_guard<std::mutex> lock(m_access_mutex);
234
235 uint8_t cmd[10 + (8 * data.size())];
236 cmd[0] = command_id;
237 cmd[1] = data.size();
238 memcpy(cmd + 2, &addr, sizeof(uint64_t));
239 for (size_t i = 0; i < data.size(); i++) {
240 memcpy(cmd + 10 + (8 * i), &(data[i]), sizeof(uint64_t));
241 }
242
243 auto result = sendto(m_connection_id, cmd, sizeof(cmd), 0, (struct sockaddr*)&m_target, sizeof(m_target));
244 if (result < 0)
245 throw FailedSocketInteraction(ERS_HERE, "sendto");
246}
#define ERS_HERE
void write(uint8_t command_id, uint64_t addr, std::vector< uint64_t > &&data) const
std::vector< uint64_t > read_buffer(uint64_t addr, uint8_t size) const
std::vector< uint64_t > read(uint8_t command_id, uint64_t addr, uint8_t size) const
void write_buffer(uint64_t addr, std::vector< uint64_t > &&data) const
command_result send_command_retry(std::string cmd, size_t retry=std::numeric_limits< size_t >::max()) const
DaphneV2Interface(const char *ipaddr, int port, std::chrono::milliseconds timeout=std::chrono::milliseconds(500))
std::vector< uint64_t > read_register(uint64_t addr, uint8_t size) const
command_result send_command(std::string cmd) const
command_result send_command_interruptible(std::string cmd, std::function< bool()> can_retry) const
Base class for any user define issue.
Definition Issue.hpp:76
#define TLOG(...)
Definition macro.hpp:21
FELIX Initialization std::string initerror FELIX queue timed std::string queuename Unexpected chunk size
Cannot add TPSet with start_time
void warning(const Issue &issue)
Definition ers.hpp:150