Line data Source code
1 : /**
2 : * @file EthernetDevice.cxx
3 : *
4 : * This is part of the DUNE DAQ , copyright 2020.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 : #ifndef SSPMODULES_SRC_ANLBOARD_ETHERNETDEVICE_CXX_
9 : #define SSPMODULES_SRC_ANLBOARD_ETHERNETDEVICE_CXX_
10 :
11 : #include "EthernetDevice.hpp"
12 :
13 : #include "anlExceptions.hpp"
14 :
15 : #include <algorithm>
16 : #include <cstdlib>
17 : #include <vector>
18 :
19 : boost::asio::io_service dunedaq::sspmodules::EthernetDevice::fIo_service;
20 :
21 0 : dunedaq::sspmodules::EthernetDevice::EthernetDevice(unsigned long ipAddress) // NOLINT
22 : :
23 0 : isOpen(false)
24 0 : , fCommSocket(fIo_service)
25 0 : , fDataSocket(fIo_service)
26 0 : , fIP(boost::asio::ip::address_v4(ipAddress))
27 0 : {}
28 :
29 : void
30 0 : dunedaq::sspmodules::EthernetDevice::Open(bool slowControlOnly)
31 : {
32 :
33 0 : fSlowControlOnly = slowControlOnly;
34 :
35 : // dune::DAQLogger::LogInfo("SSP_EthernetDevice")<<"Looking for SSP Ethernet device at "<<fIP.to_string()<<std::endl;
36 0 : boost::asio::ip::tcp::resolver resolver(fIo_service);
37 0 : boost::asio::ip::tcp::resolver::query commQuery(fIP.to_string(), slowControlOnly ? "55002" : "55001");
38 0 : boost::asio::ip::tcp::resolver::iterator commEndpointIterator = resolver.resolve(commQuery);
39 0 : boost::asio::connect(fCommSocket, commEndpointIterator);
40 :
41 0 : if (slowControlOnly) {
42 : // dune::DAQLogger::LogInfo("SSP_EthernetDevice")<<"Connected to SSP Ethernet device at
43 : // "<<fIP.to_string()<<std::endl;
44 0 : return;
45 : }
46 :
47 0 : boost::asio::ip::tcp::resolver::query dataQuery(fIP.to_string(), "55010");
48 0 : boost::asio::ip::tcp::resolver::iterator dataEndpointIterator = resolver.resolve(dataQuery);
49 :
50 0 : boost::asio::connect(fDataSocket, dataEndpointIterator);
51 :
52 : // Set limited receive buffer size to avoid taxing switch
53 : // JTH: Remove this since it was causing event read errors. Could try again
54 : // with a different value if there are more issues which point to switch problems.
55 : // boost::asio::socket_base::receive_buffer_size option(16384);
56 : // fDataSocket.set_option(option);
57 :
58 : // dune::DAQLogger::LogInfo("SSP_EthernetDevice")<<"Connected to SSP Ethernet device at "<<fIP.to_string()<<std::endl;
59 0 : }
60 :
61 : void
62 0 : dunedaq::sspmodules::EthernetDevice::Close()
63 : {
64 0 : isOpen = false;
65 : // dune::DAQLogger::LogInfo("SSP_EthernetDevice")<<"Device closed"<<std::endl;
66 0 : }
67 :
68 : void
69 0 : dunedaq::sspmodules::EthernetDevice::DevicePurgeComm(void)
70 : {
71 0 : DevicePurge(fCommSocket);
72 0 : }
73 :
74 : void
75 0 : dunedaq::sspmodules::EthernetDevice::DevicePurgeData(void)
76 : {
77 0 : DevicePurge(fDataSocket);
78 0 : }
79 :
80 : void
81 0 : dunedaq::sspmodules::EthernetDevice::DeviceQueueStatus(unsigned int* numWords)
82 : {
83 0 : unsigned int numBytes = fDataSocket.available();
84 0 : (*numWords) = numBytes / sizeof(unsigned int);
85 0 : }
86 :
87 : void
88 0 : dunedaq::sspmodules::EthernetDevice::DeviceReceive(std::vector<unsigned int>& data, unsigned int size)
89 : {
90 0 : data.resize(size);
91 0 : unsigned int dataReturned = fDataSocket.read_some(boost::asio::buffer(data));
92 0 : if (dataReturned < size * sizeof(unsigned int)) {
93 0 : data.resize(dataReturned / sizeof(unsigned int));
94 : }
95 0 : }
96 :
97 : //==============================================================================
98 : // Command Functions
99 : //==============================================================================
100 :
101 : void
102 0 : dunedaq::sspmodules::EthernetDevice::DeviceRead(unsigned int address, unsigned int* value)
103 : {
104 0 : dunedaq::sspmodules::CtrlPacket tx;
105 0 : dunedaq::sspmodules::CtrlPacket rx;
106 0 : unsigned int txSize;
107 0 : unsigned int rxSizeExpected;
108 :
109 0 : tx.header.length = sizeof(dunedaq::sspmodules::CtrlHeader);
110 0 : tx.header.address = address;
111 0 : tx.header.command = dunedaq::sspmodules::cmdRead;
112 0 : tx.header.size = 1;
113 0 : tx.header.status = dunedaq::sspmodules::statusNoError;
114 0 : txSize = sizeof(dunedaq::sspmodules::CtrlHeader);
115 0 : rxSizeExpected = sizeof(dunedaq::sspmodules::CtrlHeader) + sizeof(unsigned int);
116 :
117 0 : SendReceive(tx, rx, txSize, rxSizeExpected, 3);
118 0 : *value = rx.data[0];
119 0 : }
120 :
121 : void
122 0 : dunedaq::sspmodules::EthernetDevice::DeviceReadMask(unsigned int address, unsigned int mask, unsigned int* value)
123 : {
124 0 : dunedaq::sspmodules::CtrlPacket tx;
125 0 : dunedaq::sspmodules::CtrlPacket rx;
126 0 : unsigned int txSize;
127 0 : unsigned int rxSizeExpected;
128 :
129 0 : tx.header.length = sizeof(dunedaq::sspmodules::CtrlHeader) + sizeof(uint);
130 0 : tx.header.address = address;
131 0 : tx.header.command = dunedaq::sspmodules::cmdReadMask;
132 0 : tx.header.size = 1;
133 0 : tx.header.status = dunedaq::sspmodules::statusNoError;
134 0 : tx.data[0] = mask;
135 0 : txSize = sizeof(dunedaq::sspmodules::CtrlHeader) + sizeof(unsigned int);
136 0 : rxSizeExpected = sizeof(dunedaq::sspmodules::CtrlHeader) + sizeof(unsigned int);
137 :
138 0 : SendReceive(tx, rx, txSize, rxSizeExpected, 3);
139 0 : *value = rx.data[0];
140 0 : }
141 :
142 : void
143 0 : dunedaq::sspmodules::EthernetDevice::DeviceWrite(unsigned int address, unsigned int value)
144 : {
145 0 : dunedaq::sspmodules::CtrlPacket tx;
146 0 : dunedaq::sspmodules::CtrlPacket rx;
147 0 : unsigned int txSize;
148 0 : unsigned int rxSizeExpected;
149 :
150 0 : tx.header.length = sizeof(dunedaq::sspmodules::CtrlHeader) + sizeof(uint);
151 0 : tx.header.address = address;
152 0 : tx.header.command = dunedaq::sspmodules::cmdWrite;
153 0 : tx.header.size = 1;
154 0 : tx.header.status = dunedaq::sspmodules::statusNoError;
155 0 : tx.data[0] = value;
156 0 : txSize = sizeof(dunedaq::sspmodules::CtrlHeader) + sizeof(unsigned int);
157 0 : rxSizeExpected = sizeof(dunedaq::sspmodules::CtrlHeader);
158 :
159 0 : SendReceive(tx, rx, txSize, rxSizeExpected, 3);
160 0 : }
161 :
162 : void
163 0 : dunedaq::sspmodules::EthernetDevice::DeviceWriteMask(unsigned int address, unsigned int mask, unsigned int value)
164 : {
165 0 : dunedaq::sspmodules::CtrlPacket tx;
166 0 : dunedaq::sspmodules::CtrlPacket rx;
167 0 : unsigned int txSize;
168 0 : unsigned int rxSizeExpected;
169 :
170 0 : tx.header.length = sizeof(dunedaq::sspmodules::CtrlHeader) + (sizeof(uint) * 2);
171 0 : tx.header.address = address;
172 0 : tx.header.command = dunedaq::sspmodules::cmdWriteMask;
173 0 : tx.header.size = 1;
174 0 : tx.header.status = dunedaq::sspmodules::statusNoError;
175 0 : tx.data[0] = mask;
176 0 : tx.data[1] = value;
177 0 : txSize = sizeof(dunedaq::sspmodules::CtrlHeader) + (sizeof(unsigned int) * 2);
178 0 : rxSizeExpected = sizeof(dunedaq::sspmodules::CtrlHeader) + sizeof(unsigned int);
179 :
180 0 : SendReceive(tx, rx, txSize, rxSizeExpected, 3);
181 0 : }
182 :
183 : void
184 0 : dunedaq::sspmodules::EthernetDevice::DeviceSet(unsigned int address, unsigned int mask)
185 : {
186 0 : DeviceWriteMask(address, mask, 0xFFFFFFFF);
187 0 : }
188 :
189 : void
190 0 : dunedaq::sspmodules::EthernetDevice::DeviceClear(unsigned int address, unsigned int mask)
191 : {
192 0 : DeviceWriteMask(address, mask, 0x00000000);
193 0 : }
194 :
195 : void
196 0 : dunedaq::sspmodules::EthernetDevice::DeviceArrayRead(unsigned int address, unsigned int size, unsigned int* data)
197 : {
198 0 : unsigned int i = 0;
199 0 : dunedaq::sspmodules::CtrlPacket tx;
200 0 : dunedaq::sspmodules::CtrlPacket rx;
201 0 : unsigned int txSize;
202 0 : unsigned int rxSizeExpected;
203 :
204 0 : tx.header.length = sizeof(dunedaq::sspmodules::CtrlHeader);
205 0 : tx.header.address = address;
206 0 : tx.header.command = dunedaq::sspmodules::cmdArrayRead;
207 0 : tx.header.size = size;
208 0 : tx.header.status = dunedaq::sspmodules::statusNoError;
209 0 : txSize = sizeof(dunedaq::sspmodules::CtrlHeader);
210 0 : rxSizeExpected = sizeof(dunedaq::sspmodules::CtrlHeader) + (sizeof(unsigned int) * size);
211 :
212 0 : SendReceive(tx, rx, txSize, rxSizeExpected, 3);
213 0 : for (i = 0; i < rx.header.size; i++) {
214 0 : data[i] = rx.data[i];
215 : }
216 0 : }
217 :
218 : void
219 0 : dunedaq::sspmodules::EthernetDevice::DeviceArrayWrite(unsigned int address, unsigned int size, unsigned int* data)
220 : {
221 0 : unsigned int i = 0;
222 0 : dunedaq::sspmodules::CtrlPacket tx;
223 0 : dunedaq::sspmodules::CtrlPacket rx;
224 0 : unsigned int txSize;
225 0 : unsigned int rxSizeExpected;
226 :
227 0 : tx.header.length = sizeof(dunedaq::sspmodules::CtrlHeader) + (sizeof(uint) * size);
228 0 : tx.header.address = address;
229 0 : tx.header.command = dunedaq::sspmodules::cmdArrayWrite;
230 0 : tx.header.size = size;
231 0 : tx.header.status = dunedaq::sspmodules::statusNoError;
232 0 : txSize = sizeof(dunedaq::sspmodules::CtrlHeader) + (sizeof(unsigned int) * size);
233 0 : rxSizeExpected = sizeof(dunedaq::sspmodules::CtrlHeader);
234 :
235 0 : for (i = 0; i < size; i++) {
236 0 : tx.data[i] = data[i];
237 : }
238 :
239 0 : SendReceive(tx, rx, txSize, rxSizeExpected, 3);
240 0 : }
241 :
242 : //==============================================================================
243 : // Support Functions
244 : //==============================================================================
245 :
246 : void
247 0 : dunedaq::sspmodules::EthernetDevice::SendReceive(dunedaq::sspmodules::CtrlPacket& tx,
248 : dunedaq::sspmodules::CtrlPacket& rx,
249 : unsigned int txSize,
250 : unsigned int rxSizeExpected,
251 : unsigned int retryCount)
252 : {
253 0 : unsigned int timesTried = 0;
254 0 : bool success = false;
255 :
256 0 : while (!success) {
257 0 : try {
258 0 : SendEthernet(tx, txSize);
259 : // Insert small delay between send and receive on Linux
260 0 : usleep(100);
261 0 : ReceiveEthernet(rx, rxSizeExpected);
262 0 : usleep(2000);
263 : success = true;
264 0 : } catch (ETCPError&) {
265 0 : if (timesTried < retryCount) {
266 0 : DevicePurgeComm();
267 0 : ++timesTried;
268 : // dune::DAQLogger::LogWarning("SSP_EthernetDevice")<<"Send/receive failed "<<timesTried<<" times on Ethernet
269 : // link, retrying..."<<std::endl;
270 : } else {
271 : // dune::DAQLogger::LogError("SSP_EthernetDevice")<<"Send/receive failed on Ethernet link, giving
272 : // up."<<std::endl;
273 0 : throw;
274 : }
275 0 : }
276 : }
277 0 : }
278 :
279 : void
280 0 : dunedaq::sspmodules::EthernetDevice::SendEthernet(dunedaq::sspmodules::CtrlPacket& tx, unsigned int txSize)
281 : {
282 0 : unsigned int txSizeWritten = fCommSocket.write_some(boost::asio::buffer(static_cast<void*>(&tx), txSize));
283 0 : if (txSizeWritten != txSize) {
284 0 : throw(ETCPError(""));
285 : }
286 0 : }
287 :
288 : void
289 0 : dunedaq::sspmodules::EthernetDevice::ReceiveEthernet(dunedaq::sspmodules::CtrlPacket& rx, unsigned int rxSizeExpected)
290 : {
291 0 : unsigned int rxSizeReturned = fCommSocket.read_some(boost::asio::buffer(static_cast<void*>(&rx), rxSizeExpected));
292 0 : if (rxSizeReturned != rxSizeExpected) {
293 0 : throw(ETCPError(""));
294 : }
295 0 : }
296 :
297 : void
298 0 : dunedaq::sspmodules::EthernetDevice::DevicePurge(boost::asio::ip::tcp::socket& socket)
299 : {
300 0 : bool done = false;
301 0 : unsigned int bytesQueued = 0;
302 0 : unsigned int sleepTime = 0;
303 :
304 : // Keep getting data from channel until queue is empty
305 0 : do {
306 0 : bytesQueued = socket.available();
307 :
308 : // Read data from device, up to 256 bytes
309 0 : if (bytesQueued != 0) {
310 0 : sleepTime = 0;
311 0 : unsigned int bytesToGet = std::min((unsigned int)256, bytesQueued);
312 0 : std::vector<char> junkBuf(bytesToGet);
313 0 : socket.read_some(boost::asio::buffer(junkBuf, bytesToGet));
314 0 : } else { // If queue is empty, wait a bit and check that it hasn't filled up again, then return
315 0 : usleep(1000); // 1ms
316 0 : sleepTime += 1000;
317 0 : bytesQueued = socket.available();
318 0 : if (bytesQueued == 0 && sleepTime > 1000000) {
319 0 : done = 1;
320 : }
321 : }
322 0 : } while (!done);
323 0 : }
324 :
325 : #endif // SSPMODULES_SRC_ANLBOARD_ETHERNETDEVICE_CXX_
|