DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
BNL_UDP.cpp
Go to the documentation of this file.
3#include <sys/socket.h>
4#include <string.h> //memset, strerror
5#include <errno.h>
6#include <string>
7#include <fcntl.h> //fcntl
8
9#include <sstream>
10#include <iomanip>
11
12#include <netdb.h>
13
14#include <errno.h>
15#include <algorithm> //STD::COUNT
16
17#define WIB_WR_BASE_PORT 32000
18#define WIB_RD_BASE_PORT 32001
19#define WIB_RPLY_BASE_PORT 32002
20
21#define WIB_PACKET_KEY 0xDEADBEEF
22//#define WIB_REQUEST_PACKET_SIZE (4+2+4+2)
23#define WIB_REQUEST_PACKET_TRAILER 0xFFFF
24
25#define WIB_RPLY_PACKET_SIZE 12
26
27#define TIMEOUT_SECONDS 2
28#define TIMEOUT_MICROSECONDS 0
30 uint32_t key;
31 uint32_t reg_addr : 16;
32 uint32_t data_MSW : 16;
33 uint32_t data_LSW : 16;
34 uint32_t trailer : 16;
35};
36
37static std::string dump_packet(uint8_t * data, size_t size){
38 // printf("Err: %p %zu\n",data,size);
39 std::stringstream ss;
40 for(size_t iWord = 0; iWord < size;iWord++){
41 ss << "0x" << std::hex << std::setfill('0') << std::setw(4) << iWord;
42 ss << ": 0x" << std::hex << std::setfill('0') << std::setw(2) << int(data[iWord]);
43 iWord++;
44 if(iWord < size){
45 ss << std::hex << std::setfill('0') << std::setw(2) << int(data[iWord]);
46 }
47 ss << std::endl;
48 }
49 // printf("%s",ss.str().c_str());
50 return ss.str();
51}
52
53void BNL_UDP::FlushSocket(int sock){
54 //turn on non-blocking
55 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL)| O_NONBLOCK);
56 int ret;
57 do{
58 ret = recv(sock,buffer,buffer_size,0);
59 }while(ret != -1);
60 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) & (~O_NONBLOCK));
61}
62
64 //close sockets
65 if(readSocketFD != -1){
66 close(readSocketFD);
67 readSocketFD = -1;
68 }
69 if(writeSocketFD != -1){
70 close(writeSocketFD);
71 writeSocketFD = -1;
72 }
73 //Clear packet buffer
74 if(buffer != NULL){
75 delete [] buffer;
76 buffer_size = 0;
77 }
78 writeAck = false;
79 connected = false;
80
81 //Reset send/recv addr structures
82 memset(&readAddr,0,sizeof(readAddr));
83 memset(&writeAddr,0,sizeof(writeAddr));
84}
85
86//static void printaddress(struct sockaddr_in const * addr){
87// printf("%u: %u.%u.%u.%u : %u\n",
88// addr->sin_family,
89// (addr->sin_addr.s_addr >> 0)&0xFF,
90// (addr->sin_addr.s_addr >> 8)&0xFF,
91// (addr->sin_addr.s_addr >> 16)&0xFF,
92// (addr->sin_addr.s_addr >> 24)&0xFF,
93// ntohs(addr->sin_port));
94//}
95
96void BNL_UDP::Setup(std::string const & address,uint16_t port_offset){
97 //Reset the network structures
98 Clear();
99
100 //Allocate the recv buffer
101 ResizeBuffer();
102
103 //Check port_offset range
104 if(port_offset > 128){
105 BUException::BNL_UDP_PORT_OUT_OF_RANGE e;
106 throw e;
107 }
108
109 //Set the ports for this device (FEMBs are iFEMB*0x10 above the base)
110 readPort = WIB_RD_BASE_PORT + port_offset;
111 writePort = WIB_WR_BASE_PORT + port_offset;
112 // replyPort = WIB_RPLY_BASE_PORT + port_offset;
113
114 remoteAddress = address;
115 //Get the sockaddr for the address
116 struct addrinfo * res;
117 if(getaddrinfo(address.c_str(),NULL,NULL,&res)){
118 //Check if we have just one "." character and is less than 5 characters
119 if(address.size() <= 5 && 1 == std::count(address.begin(),address.end(),'.')){
120 std::string strCrate = address.substr(0,address.find('.'));
121 std::string strSlot = address.substr(address.find('.')+1);
122 if(strCrate.size() != 0 && strSlot.size() != 0){
123 uint8_t crate = strtoul(strCrate.c_str(),NULL,0);
124 uint8_t slot = strtoul(strSlot.c_str(), NULL,0);
125 if( (((crate > 0) && (crate < 7)) || 0xF == crate) &&
126 (((slot > 0) && (slot < 7)) || 0xF == slot)){
127 remoteAddress = std::string("192.168.");
128 //Add the crate part of the address (200 + crate number)
129 if(crate == 0xF){
130 remoteAddress += "200.";
131 }else{
132 //generate the crate number which is 200 + crate number
133 remoteAddress += "20";
134 remoteAddress += ('0' + crate);
135 remoteAddress += '.';
136 }
137 if(slot == 0xF){
138 remoteAddress += "50";
139 }else{
140 //crate last IP octet that is slot number
141 remoteAddress += ('0' + slot);
142 }
143 }
144 }
145 }
146 //try a second time assumin gthis is a crate.slot address, fail if this still doesn't work
147 if(getaddrinfo(address.c_str(),NULL,NULL,&res)){
148 BUException::BAD_REMOTE_IP e;
149 e.Append("Addr: ");
150 e.Append(address.c_str());
151 e.Append(" could not be resolved.\n");
152 throw e;
153 }
154 }
155 // readAddr = *((struct sockaddr_in *) res->ai_addr);
156 // printaddress(&readAddr);
157
158 //Generate the sockets for read and write
159 if((readSocketFD = socket(AF_INET,SOCK_DGRAM,0)) < 0){
160 BUException::BAD_SOCKET e;
161 e.Append("read socket\n");
162 throw e;
163 }
164 if((writeSocketFD = socket(AF_INET,SOCK_DGRAM,0)) < 0){
165 BUException::BAD_SOCKET e;
166 e.Append("write socket\n");
167 throw e;
168 }
169 //Set a timeout for the recv socket so we don't hang on a reply
170 struct timeval tv; tv.tv_sec=TIMEOUT_SECONDS; tv.tv_usec=TIMEOUT_MICROSECONDS;
171 setsockopt(readSocketFD, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval));
172 setsockopt(writeSocketFD, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval));
173
174 //connect the read socket
175 readAddr = *((struct sockaddr_in *) res->ai_addr);
176 readAddr.sin_port = htons(readPort);
177 if(connect(readSocketFD,(struct sockaddr *) &readAddr,sizeof(readAddr)) < 0){
178 BUException::CONNECTION_FAILED e;
179 e.Append("read socket connect\n");
180 e.Append(strerror(errno));
181 throw e;
182 }
183 //connect the write socket
184 writeAddr = *((struct sockaddr_in *) res->ai_addr);
185 writeAddr.sin_port = htons(writePort);
186 if(connect(writeSocketFD,(struct sockaddr *) &writeAddr,sizeof(writeAddr)) < 0){
187 BUException::CONNECTION_FAILED e;
188 e.Append("write socket connect\n");
189 e.Append(strerror(errno));
190 throw e;
191 }
192
193 //Allocate the receive buffer to default size
194 ResizeBuffer();
195}
196
197void BNL_UDP::WriteWithRetry(uint16_t address, uint32_t value, uint8_t retry_count){
198 while(retry_count > 1){
199 try{
200 //Do the write
201 Write(address,value);
202 usleep(10);
203 //if everything goes well, return
204 return;
205 }catch(BUException::BAD_REPLY &e){
206 //eat the exception
207 }
209 retry_count--;
210 usleep(10);
211 }
212 //Last chance we don't catch the exception and let it fall down the stack
213 //Do the write
214 Write(address,value);
215 usleep(10);
216}
217void BNL_UDP::Write(uint16_t address, uint32_t value){
218
219 //Flush this socket
221
222 //Build the packet to send
223 //build the send packet
224 WIB_packet_t packet;
225 packet.key = htonl(WIB_PACKET_KEY);
226 packet.reg_addr = htons(address);
227 packet.data_MSW = htons(uint16_t((value >> 16) & 0xFFFF));
228 packet.data_LSW = htons(uint16_t((value >> 0) & 0xFFFF));
229 packet.trailer = htons(WIB_REQUEST_PACKET_TRAILER);
230
231 //send the packet
232 ssize_t send_size = sizeof(packet);
233 ssize_t sent_size = 0;
234 if( send_size != (sent_size = send(writeSocketFD,
235 &packet,send_size,0))){
236 //bad send
237 BUException::SEND_FAILED e;
238 if(sent_size == -1){
239 e.Append("BNL_UDP::Write(uint16_t,uint32_t)\n");
240 e.Append("Errnum: ");
241 e.Append(strerror(errno));
242 }
243 throw e;
244 }
245
246 //If configured, capture confirmation packet
247 if(writeAck ){
248 ssize_t reply_size = recv(writeSocketFD,
250
251 if(-1 == reply_size){
252 BUException::BAD_REPLY e;
253 std::stringstream ss;
254 e.Append("BNL_UDP::Write(uint16_t,uint32_t)\n");
255 ss << "Errnum(" << errno << "): " << strerror(errno) << "\n";
256 e.Append(ss.str().c_str());
257 e.Append(dump_packet((uint8_t*) &packet,send_size).c_str());
258 throw e;
259 }else if( reply_size < WIB_RPLY_PACKET_SIZE){
260 BUException::BAD_REPLY e;
261 std::stringstream ss;
262 ss << "Bad Size: " << reply_size << "\n";
263 e.Append("BNL_UDP::Write(uint16_t,uint32_t)\n");
264 e.Append(ss.str().c_str());
265 e.Append(dump_packet(buffer,reply_size).c_str());
266 throw e;
267 }
268 uint16_t reply_address = uint16_t(buffer[0] << 8 | buffer[1]);
269 if( reply_address != address){
270 BUException::BAD_REPLY e;
271 std::stringstream ss;
272 ss << "Bad address: " << uint32_t(address) << " != " << uint32_t(reply_address) << "\n";
273 e.Append("BNL_UDP::Write(uint16_t,uint32_t)\n");
274 e.Append(ss.str().c_str());
275 e.Append(dump_packet(buffer,reply_size).c_str());
276 throw e;
277 }
278 }
279}
280void BNL_UDP::Write(uint16_t address, std::vector<uint32_t> const & values){
281 Write(address,values.data(),values.size());
282}
283void BNL_UDP::Write(uint16_t address, uint32_t const * values, size_t word_count){
284 for(size_t iWrite = 0; iWrite < word_count;iWrite++){
285 WriteWithRetry(address,values[iWrite]);
286 address++;
287 }
288
368}
369
370uint32_t BNL_UDP::ReadWithRetry(uint16_t address,uint8_t retry_count){
371 uint32_t val;
372 while(retry_count > 1){
373 try{
374 //Do the write
375 val = Read(address);
376 usleep(10);
377 //if everything goes well, return
378 return val;
379 }catch(BUException::BAD_REPLY &e){
380 //eat the exception
381 }
382 usleep(10);
384 retry_count--;
385 }
386 //Last chance we don't catch the exception and let it fall down the stack
387 val = Read(address);
388 usleep(10);
389 return val;
390}
391uint32_t BNL_UDP::Read(uint16_t address){
392 //Flush the socket
394
395 //build the send packet
396 WIB_packet_t packet;
397 packet.key = htonl(WIB_PACKET_KEY);
398 packet.reg_addr = htons(address);
399 packet.data_MSW = packet.data_LSW = 0;
400 packet.trailer = htons(WIB_REQUEST_PACKET_TRAILER);
401
402 //send the packet
403 ssize_t send_size = sizeof(packet);
404 ssize_t sent_size = 0;
405 if( send_size != (sent_size = send(readSocketFD,
406 &packet,send_size,0))){
407 //bad send
408 BUException::SEND_FAILED e;
409 if(sent_size == -1){
410 e.Append("BNL_UDP::Read(uint16_t)\n");
411 e.Append("Errnum: ");
412 e.Append(strerror(errno));
413 }
414 throw e;
415 }
416
417 //Get the reply packet with the register data in it.
418 ssize_t reply_size = recv(readSocketFD,
420
421 if(ssize_t(-1) == reply_size){
422 BUException::BAD_REPLY e;
423 std::stringstream ss;
424 e.Append("BNL_UDP::Read(uint16_t)\n");
425 ss << "Errnum(" << errno << "): " << strerror(errno) << "\n";
426 e.Append(ss.str().c_str());
427 e.Append(dump_packet((uint8_t *)&packet,send_size).c_str());
428 throw e;
429 }else if( reply_size < WIB_RPLY_PACKET_SIZE){
430 BUException::BAD_REPLY e;
431 std::stringstream ss;
432 ss << "Bad Size: " << reply_size << "\n";
433 e.Append("BNL_UDP::Read(uint16_t)\n");
434 e.Append(ss.str().c_str());
435 e.Append(dump_packet(buffer,reply_size).c_str());
436 throw e;
437 }
438 uint16_t reply_address = uint16_t(buffer[0] << 8 | buffer[1]);
439 if( reply_address != address){
440 BUException::BAD_REPLY e;
441 std::stringstream ss;
442 ss << "Bad address: " << uint32_t(address) << " != " << uint32_t(reply_address) << "\n";
443 e.Append("BNL_UDP::Read(uint16_t)\n");
444 e.Append(ss.str().c_str());
445 e.Append(dump_packet(buffer,reply_size).c_str());
446 throw e;
447 }
448
449
450 // }
451 uint32_t ret = ( (uint32_t(buffer[2]) << 24) |
452 (uint32_t(buffer[3]) << 16) |
453 (uint32_t(buffer[4]) << 8) |
454 (uint32_t(buffer[5]) << 0));
455 return ret;
456}
457
458
462
463
464void BNL_UDP::ResizeBuffer(size_t size){
465 //CHeck if the requested size is larger than the already allocated size
466 // printf("before %p %zu %zd\n",buffer,buffer_size,buffer_size);
467 if(buffer_size < size){
468 //We need to re-allocate
469 if(buffer != NULL){
470 delete [] buffer;
471 }
472 buffer = new uint8_t[size];
473 buffer_size = size;
474 }
475 // printf("after %p %zu %zd\n",buffer,buffer_size,buffer_size);
476}
#define WIB_REQUEST_PACKET_TRAILER
Definition BNL_UDP.cpp:23
#define WIB_RD_BASE_PORT
Definition BNL_UDP.cpp:18
#define WIB_RPLY_PACKET_SIZE
Definition BNL_UDP.cpp:25
static std::string dump_packet(uint8_t *data, size_t size)
Definition BNL_UDP.cpp:37
#define WIB_WR_BASE_PORT
Definition BNL_UDP.cpp:17
#define TIMEOUT_MICROSECONDS
Definition BNL_UDP.cpp:28
#define WIB_PACKET_KEY
Definition BNL_UDP.cpp:21
#define TIMEOUT_SECONDS
Definition BNL_UDP.cpp:27
struct sockaddr_in writeAddr
Definition BNL_UDP.hh:61
int16_t readPort
Definition BNL_UDP.hh:52
void Setup(std::string const &address, uint16_t port_offset=0)
Definition BNL_UDP.cpp:96
std::string remoteAddress
Definition BNL_UDP.hh:51
void Write(uint16_t address, uint32_t value)
Definition BNL_UDP.cpp:217
bool connected
Definition BNL_UDP.hh:57
void WriteWithRetry(uint16_t address, uint32_t value, uint8_t retry_count=10)
Definition BNL_UDP.cpp:197
uint32_t ReadWithRetry(uint16_t address, uint8_t retry_count=10)
Definition BNL_UDP.cpp:370
int writeSocketFD
Definition BNL_UDP.hh:59
uint32_t Read(uint16_t address)
Definition BNL_UDP.cpp:391
void FlushSocket(int sock)
Definition BNL_UDP.cpp:53
uint64_t total_retry_count
Definition BNL_UDP.hh:66
void Clear()
Definition BNL_UDP.cpp:63
struct sockaddr_in readAddr
Definition BNL_UDP.hh:60
size_t buffer_size
Definition BNL_UDP.hh:64
int readSocketFD
Definition BNL_UDP.hh:58
void ResizeBuffer(size_t size=WIB_RESPONSE_PACKET_BUFFER_SIZE)
Definition BNL_UDP.cpp:464
uint8_t * buffer
Definition BNL_UDP.hh:65
int16_t writePort
Definition BNL_UDP.hh:53
bool writeAck
Definition BNL_UDP.hh:48
uint32_t key
Definition BNL_UDP.cpp:30
uint32_t data_LSW
Definition BNL_UDP.cpp:33
uint32_t reg_addr
Definition BNL_UDP.cpp:31
uint32_t data_MSW
Definition BNL_UDP.cpp:32
uint32_t trailer
Definition BNL_UDP.cpp:34