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