otsdaq_mu2e  v2_04_02
ots_udp_sw_emulator.cpp
1 // ots_udp_sw_emulator.cpp
2 // by rrivera at fnal dot gov
3 // created Feb 2016
4 //
5 // This is a simple emulator of a "data gen" front-end (hardware) interface
6 // using the otsdaq UDP protocol.
7 //
8 // Protocol is specified
9 // https://docs.google.com/document/d/1i3Z07n8Jq78NwgUFdjAv2sLGhH4rWjHeYEScAWBzSyw/edit?usp=sharing
10 //
11 // compile with:
12 // g++ ots_udp_sw_emulator.cpp -o sw.o
13 //
14 // if developing, consider appending -D_GLIBCXX_DEBUG to get more
15 // descriptive error messages
16 //
17 // run with:
18 //./sw.o localhost <type-of-test>
19 // or
20 //./sw.o ip.of.hw.o <type-of-test>
21 //
22 // 1 is write and read test
23 // 2 is data stream test
24 
25 #include <arpa/inet.h>
26 #include <errno.h>
27 #include <netdb.h>
28 #include <netinet/in.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/socket.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <iostream>
37 
38 using namespace std;
39 
40 #define HWPORT "4950" // the port of the front end (hardware) target
41 #define MAXBUFLEN 1492
42 
43 // get sockaddr, IPv4 or IPv6:
44 void* get_in_addr(struct sockaddr* sa)
45 {
46  if(sa->sa_family == AF_INET)
47  {
48  return &(((struct sockaddr_in*)sa)->sin_addr);
49  }
50 
51  return &(((struct sockaddr_in6*)sa)->sin6_addr);
52 }
53 
54 int makeSocket(char* ip, int port)
55 {
56  int sockfd;
57  struct addrinfo hints, *servinfo, *p;
58  int rv;
59  int numbytes;
60  struct sockaddr_storage their_addr;
61  socklen_t addr_len;
62  char s[INET6_ADDRSTRLEN];
63 
64  memset(&hints, 0, sizeof hints);
65  hints.ai_family = AF_UNSPEC;
66  hints.ai_socktype = SOCK_DGRAM;
67 
68  if((rv = getaddrinfo(ip, HWPORT, &hints, &servinfo)) != 0)
69  {
70  fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
71  return 1;
72  }
73 
74  // loop through all the results and make a socket
75  for(p = servinfo; p != NULL; p = p->ai_next)
76  {
77  if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
78  {
79  perror("sw: socket");
80  continue;
81  }
82 
83  break;
84  }
85 
86  if(p == NULL)
87  {
88  fprintf(stderr, "sw: failed to create socket\n");
89  return 2;
90  }
91 
92  freeaddrinfo(servinfo);
93 
94  return sockfd;
95 }
96 
97 int main(int argc, char* argv[])
98 {
99  // 2 types of tests defined:
100  // 1. write and read
101  // 2. burst data read test
102 
103  int sockfd;
104  struct addrinfo hints, *servinfo, *p;
105  int rv;
106  int numbytes;
107  struct sockaddr_storage their_addr;
108  socklen_t addr_len;
109  char s[INET6_ADDRSTRLEN];
110 
111  if(argc != 3)
112  {
113  fprintf(stderr, "usage: sw hostname type-of-test\n");
114  exit(1);
115  }
116 
117  memset(&hints, 0, sizeof hints);
118  hints.ai_family = AF_UNSPEC;
119  hints.ai_socktype = SOCK_DGRAM;
120 
121  if((rv = getaddrinfo(argv[1], HWPORT, &hints, &servinfo)) != 0)
122  {
123  fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
124  return 1;
125  }
126 
127  // loop through all the results and make a socket
128  for(p = servinfo; p != NULL; p = p->ai_next)
129  {
130  if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
131  {
132  perror("sw: socket");
133  continue;
134  }
135 
136  break;
137  }
138 
139  if(p == NULL)
140  {
141  fprintf(stderr, "sw: failed to create socket\n");
142  return 2;
143  }
144 
145  freeaddrinfo(servinfo);
146 
150 
151  char buff[MAXBUFLEN];
152  unsigned int packetSz;
153  int type = atoi(argv[2]);
154  cout << "sw: Line " << __LINE__ << ":::"
155  << "Type of Test: " << type << endl;
156 
157  uint64_t val = 0;
158  uint64_t addr;
159  bool a = 4;
160  string test = "hehehel";
161  if(a != test.size())
162  cout << endl;
163 
164  const unsigned int RX_ADDR_OFFSET = 2;
165  const unsigned int RX_DATA_OFFSET = 10;
166  const unsigned int TX_DATA_OFFSET = 2;
167 
168  switch(type)
169  {
170  case 1:
171  // write and read
172 
173  // setup write packet
174  // ///////////////////////////////////////////////////////////
175  buff[0] = 1; // write
176  buff[1] = 1; // num of quadwords
177  addr = 0x1001; // data_gen_cnt
178  memcpy((void*)&buff[RX_ADDR_OFFSET], (void*)&addr, 8);
179 
180  val = 4;
181  for(int i = 0; i < buff[1]; ++i, ++val)
182  memcpy((void*)&buff[RX_DATA_OFFSET + i * 8],
183  (void*)&val,
184  8); // increment each time
185  packetSz = RX_DATA_OFFSET + buff[1] * 8;
186 
187  if((numbytes = sendto(sockfd, buff, packetSz, 0, p->ai_addr, p->ai_addrlen)) ==
188  -1)
189  {
190  perror("sw: sendto");
191  exit(1);
192  }
193  printf("sw: sent %d bytes to %s\n", numbytes, argv[1]);
194 
195  buff[0] = 0; // read request
196  // ///////////////////////////////////////////////////////////
197  packetSz = RX_DATA_OFFSET;
198 
199  if((numbytes = sendto(sockfd, buff, packetSz, 0, p->ai_addr, p->ai_addrlen)) ==
200  -1)
201  {
202  perror("sw: sendto");
203  exit(1);
204  }
205  printf("sw: sent %d bytes to %s\n", numbytes, argv[1]);
206  printf("sent packet contents: ");
207 
208  for(int i = 0; i < numbytes; ++i)
209  {
210  printf("%2.2X", (unsigned char)buff[i]);
211  if(i % 8 == 7)
212  printf("\n");
213  }
214  printf("\n");
215 
216  // read response ///////////////////////////////////////////////////////////
217  if((numbytes = recvfrom(sockfd,
218  buff,
219  MAXBUFLEN - 1,
220  0,
221  (struct sockaddr*)&their_addr,
222  &addr_len)) == -1)
223  {
224  perror("recvfrom");
225  exit(1);
226  }
227 
228  printf("sw: got read response from %s\n",
229  inet_ntop(their_addr.ss_family,
230  get_in_addr((struct sockaddr*)&their_addr),
231  s,
232  sizeof s));
233  printf("sw: packet is %d bytes long\n", numbytes);
234  printf("recv packet contents: ");
235 
236  for(int i = 0; i < numbytes; ++i)
237  {
238  printf("%2.2X", (unsigned char)buff[i]);
239  if(i % 8 == 7)
240  printf("\n");
241  }
242  printf("\n");
243 
244  memcpy((void*)&val, (void*)&buff[TX_DATA_OFFSET], 8);
245  cout << "sw: Line " << __LINE__ << ":::"
246  << "Value read: " << hex << val << endl;
247 
248  break;
249  case 2:
250  // burst data read test
251 
252  // setup write packet
253  // ///////////////////////////////////////////////////////////
254  buff[0] = 1; // write
255  buff[1] = 1; // num of quadwords
256  addr = 0x0000000100000009; // data enable
257  memcpy((void*)&buff[RX_ADDR_OFFSET], (void*)&addr, 8);
258  memset((void*)&buff[RX_DATA_OFFSET], 0, 7);
259  memset((void*)&buff[RX_DATA_OFFSET + 7], 1, 1); // enable data
260  packetSz = RX_DATA_OFFSET + buff[1] * 8;
261 
262  if((numbytes = sendto(sockfd, buff, packetSz, 0, p->ai_addr, p->ai_addrlen)) ==
263  -1)
264  {
265  perror("sw: sendto");
266  exit(1);
267  }
268  printf("sw: sent %d bytes to %s\n", numbytes, argv[1]);
269 
270  // setup write packet
271  // ///////////////////////////////////////////////////////////
272  buff[0] = 1; // write
273  buff[1] = 1; // num of quadwords
274  addr = 0x1001; // data_gen_cnt
275  memcpy((void*)&buff[RX_ADDR_OFFSET], (void*)&addr, 8);
276 
277  val = 4; // this will be data count value
278  memcpy((void*)&buff[RX_DATA_OFFSET], (void*)&val, 8);
279  packetSz = RX_DATA_OFFSET + buff[1] * 8;
280 
281  if((numbytes = sendto(sockfd, buff, packetSz, 0, p->ai_addr, p->ai_addrlen)) ==
282  -1)
283  {
284  perror("sw: sendto");
285  exit(1);
286  }
287  printf("sw: sent %d bytes to %s\n", numbytes, argv[1]);
288 
289  // read data packets
290  // ///////////////////////////////////////////////////////////
291  {
292  int sz = val; // get from read in TYPE 1
293  cout << "sw: Line " << __LINE__ << ":::"
294  << "Number of packets expecting: " << sz << endl;
295  for(int i = 0; i < sz; ++i)
296  {
297  cout << "sw: Line " << __LINE__ << ":::"
298  << "Waiting for data packet: " << i << endl;
299 
300  // read response
301  // ///////////////////////////////////////////////////////////
302  if((numbytes = recvfrom(sockfd,
303  buff,
304  MAXBUFLEN - 1,
305  0,
306  (struct sockaddr*)&their_addr,
307  &addr_len)) == -1)
308  {
309  perror("recvfrom");
310  exit(1);
311  }
312 
313  printf("sw: got read response from %s\n",
314  inet_ntop(their_addr.ss_family,
315  get_in_addr((struct sockaddr*)&their_addr),
316  s,
317  sizeof s));
318  printf("sw: packet is %d bytes long\n", numbytes);
319  printf("recv packet contents: ");
320 
321  for(int i = 0; i < numbytes; ++i)
322  {
323  printf("%2.2X", (unsigned char)buff[i]);
324  if(i % 8 == 7)
325  printf("\n");
326  }
327  printf("\n");
328 
329  memcpy((void*)&val, (void*)&buff[TX_DATA_OFFSET], 8);
330  cout << "sw: Line " << __LINE__ << ":::"
331  << "Value read: " << val << endl;
332  }
333  }
334 
335  // setup write packet
336  // ///////////////////////////////////////////////////////////
337  buff[0] = 1; // write
338  buff[1] = 1; // num of quadwords
339  addr = 0x0000000100000009; // data enable
340  memcpy((void*)&buff[RX_ADDR_OFFSET], (void*)&addr, 8);
341  memset((void*)&buff[RX_DATA_OFFSET], 0, 7);
342  memset((void*)&buff[RX_DATA_OFFSET + 7], 0, 1); // disable data
343  packetSz = RX_DATA_OFFSET + buff[1] * 8;
344 
345  if((numbytes = sendto(sockfd, buff, packetSz, 0, p->ai_addr, p->ai_addrlen)) ==
346  -1)
347  {
348  perror("sw: sendto");
349  exit(1);
350  }
351  printf("sw: sent %d bytes to %s\n", numbytes, argv[1]);
352 
353  // read response ///////////////////////////////////////////////////////////
354  if((numbytes = recvfrom(sockfd,
355  buff,
356  MAXBUFLEN - 1,
357  0,
358  (struct sockaddr*)&their_addr,
359  &addr_len)) == -1)
360  {
361  perror("recvfrom");
362  exit(1);
363  }
364 
365  printf("sw: got read response from %s\n",
366  inet_ntop(their_addr.ss_family,
367  get_in_addr((struct sockaddr*)&their_addr),
368  s,
369  sizeof s));
370  printf("sw: packet is %d bytes long\n", numbytes);
371  printf("recv packet contents: ");
372 
373  for(int i = 0; i < numbytes; ++i)
374  {
375  printf("%2.2X", (unsigned char)buff[i]);
376  if(i % 8 == 7)
377  printf("\n");
378  }
379  printf("\n");
380  break;
381  default:
382  cout << "sw: Line " << __LINE__ << ":::"
383  << "INVALID Type of Test: " << type << endl;
384  }
385 
386  close(sockfd);
387 
388  return 0;
389 }