PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/guppi_daq/src/guppi_udp.c

http://github.com/david-macmahon/paper_gpu
C | 455 lines | 318 code | 66 blank | 71 comment | 62 complexity | 9cc55256fd476f7a4b60b41ec289f90b MD5 | raw file
  1. /* guppi_udp.c
  2. *
  3. * UDP implementations.
  4. */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <unistd.h>
  8. #include <string.h>
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <netinet/in.h>
  12. #include <netdb.h>
  13. #include <fcntl.h>
  14. #include <poll.h>
  15. #include <endian.h>
  16. #include "guppi_udp.h"
  17. #include "guppi_databuf.h"
  18. #include "guppi_error.h"
  19. #include "guppi_defines.h"
  20. #ifdef NEW_GBT
  21. #define BYTE_ARR_TO_UINT(array, idx) (ntohl(((unsigned int*)(array))[idx]))
  22. #endif
  23. int guppi_udp_init(struct guppi_udp_params *p) {
  24. /* Resolve sender hostname */
  25. struct addrinfo hints;
  26. struct addrinfo *result, *rp;
  27. memset(&hints, 0, sizeof(struct addrinfo));
  28. hints.ai_family = AF_INET;
  29. hints.ai_socktype = SOCK_DGRAM;
  30. int rv = getaddrinfo(p->sender, NULL, &hints, &result);
  31. if (rv!=0) {
  32. guppi_error("guppi_udp_init", "getaddrinfo failed");
  33. return(GUPPI_ERR_SYS);
  34. }
  35. /* Set up socket */
  36. p->sock = socket(PF_INET, SOCK_DGRAM, 0);
  37. if (p->sock==-1) {
  38. guppi_error("guppi_udp_init", "socket error");
  39. freeaddrinfo(result);
  40. return(GUPPI_ERR_SYS);
  41. }
  42. /* bind to local address */
  43. struct sockaddr_in local_ip;
  44. local_ip.sin_family = AF_INET;
  45. local_ip.sin_port = htons(p->port);
  46. local_ip.sin_addr.s_addr = INADDR_ANY;
  47. rv = bind(p->sock, (struct sockaddr *)&local_ip, sizeof(local_ip));
  48. if (rv==-1) {
  49. guppi_error("guppi_udp_init", "bind");
  50. return(GUPPI_ERR_SYS);
  51. }
  52. /* Set up socket to recv only from sender */
  53. for (rp=result; rp!=NULL; rp=rp->ai_next) {
  54. if (connect(p->sock, rp->ai_addr, rp->ai_addrlen)==0) { break; }
  55. }
  56. if (rp==NULL) {
  57. guppi_error("guppi_udp_init", "connect error");
  58. close(p->sock);
  59. freeaddrinfo(result);
  60. return(GUPPI_ERR_SYS);
  61. }
  62. memcpy(&p->sender_addr, rp, sizeof(struct addrinfo));
  63. freeaddrinfo(result);
  64. /* Non-blocking recv */
  65. fcntl(p->sock, F_SETFL, O_NONBLOCK);
  66. /* Increase recv buffer for this sock */
  67. int bufsize = 128*1024*1024;
  68. socklen_t ss = sizeof(int);
  69. rv = setsockopt(p->sock, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(int));
  70. if (rv<0) {
  71. guppi_error("guppi_udp_init", "Error setting rcvbuf size.");
  72. perror("setsockopt");
  73. }
  74. rv = getsockopt(p->sock, SOL_SOCKET, SO_RCVBUF, &bufsize, &ss);
  75. if (0 && rv==0) {
  76. printf("guppi_udp_init: SO_RCVBUF=%d\n", bufsize);
  77. }
  78. /* Poll command */
  79. p->pfd.fd = p->sock;
  80. p->pfd.events = POLLIN;
  81. return(GUPPI_OK);
  82. }
  83. int guppi_udp_wait(struct guppi_udp_params *p) {
  84. int rv = poll(&p->pfd, 1, 1000); /* Timeout 1sec */
  85. if (rv==1) { return(GUPPI_OK); } /* Data ready */
  86. else if (rv==0) { return(GUPPI_TIMEOUT); } /* Timed out */
  87. else { return(GUPPI_ERR_SYS); } /* Other error */
  88. }
  89. int guppi_udp_recv(struct guppi_udp_params *p, struct guppi_udp_packet *b) {
  90. int rv = recv(p->sock, b->data, GUPPI_MAX_PACKET_SIZE, 0);
  91. b->packet_size = rv;
  92. if (rv==-1) { return(GUPPI_ERR_SYS); }
  93. else if (p->packet_size) {
  94. #ifdef SPEAD
  95. printf("SPEAD\n");
  96. if (strncmp(p->packet_format, "SPEAD", 5) == 0)
  97. return guppi_chk_spead_pkt_size(b);
  98. else if (rv!=p->packet_size)
  99. return(GUPPI_ERR_PACKET);
  100. else
  101. return(GUPPI_OK);
  102. #else
  103. printf("NOT SPEAD\n");
  104. if (rv!=p->packet_size) { return(GUPPI_ERR_PACKET); }
  105. else { return(GUPPI_OK); }
  106. #endif
  107. } else {
  108. p->packet_size = rv;
  109. return(GUPPI_OK);
  110. }
  111. }
  112. unsigned long long guppi_udp_packet_seq_num(const struct guppi_udp_packet *p) {
  113. // XXX Temp for new baseband mode, blank out top 8 bits which
  114. // contain channel info.
  115. unsigned long long tmp = be64toh(*(unsigned long long *)p->data);
  116. tmp &= 0x00FFFFFFFFFFFFFF;
  117. return(tmp);
  118. }
  119. unsigned long long guppi_udp_packet_mcnt(const struct guppi_udp_packet *p) {
  120. // XXX Temp for new baseband mode, blank out top 16 bits which
  121. // should contain zeros anyway.
  122. unsigned long long tmp = be64toh(*(unsigned long long *)p->data);
  123. tmp &= 0x0000FFFFFFFFFFFF;
  124. return(tmp);
  125. }
  126. #define PACKET_SIZE_ORIG ((size_t)8208)
  127. #define PACKET_SIZE_SHORT ((size_t)544)
  128. #define PACKET_SIZE_1SFA ((size_t)8224)
  129. #define PACKET_SIZE_1SFA_OLD ((size_t)8160)
  130. #define PACKET_SIZE_FAST4K ((size_t)4128)
  131. #define PACKET_SIZE_PASP ((size_t)528)
  132. #define PACKET_SIZE_SPEAD ((size_t)8248)
  133. size_t guppi_udp_packet_datasize(size_t packet_size) {
  134. /* Special case for the new "1SFA" packets, which have an extra
  135. * 16 bytes at the end reserved for future use. All other guppi
  136. * packets have 8 bytes index at the front, and 8 bytes error
  137. * flags at the end.
  138. * NOTE: This represents the "full" packet output size...
  139. */
  140. if (packet_size==PACKET_SIZE_1SFA) // 1SFA packet size
  141. return((size_t)8192);
  142. else if (packet_size==PACKET_SIZE_SHORT)
  143. //return((size_t)256);
  144. return((size_t)512);
  145. else if (packet_size==PACKET_SIZE_SPEAD)
  146. return(packet_size - 6*8); // 8248-6*8
  147. else
  148. return(packet_size - 2*sizeof(unsigned long long));
  149. }
  150. char *guppi_udp_packet_data(const struct guppi_udp_packet *p) {
  151. /* This is valid for all guppi packet formats
  152. * PASP has 16 bytes of header rather than 8.
  153. */
  154. if (p->packet_size==PACKET_SIZE_PASP)
  155. return((char *)(p->data) + (size_t)16);
  156. return((char *)(p->data) + sizeof(unsigned long long));
  157. }
  158. unsigned long long guppi_udp_packet_flags(const struct guppi_udp_packet *p) {
  159. return(*(unsigned long long *)((char *)(p->data)
  160. + p->packet_size - sizeof(unsigned long long)));
  161. }
  162. /* Copy the data portion of a guppi udp packet to the given output
  163. * address. This function takes care of expanding out the
  164. * "missing" channels in 1SFA packets.
  165. */
  166. void guppi_udp_packet_data_copy(char *out, const struct guppi_udp_packet *p) {
  167. if (p->packet_size==PACKET_SIZE_1SFA_OLD) {
  168. /* Expand out, leaving space for missing data. So far only
  169. * need to deal with 4k-channel case of 2 spectra per packet.
  170. * May need to be updated in the future if 1SFA works with
  171. * different numbers of channels.
  172. *
  173. * TODO: Update 5/12/2009, newer 1SFA modes always will have full
  174. * data contents, and the old 4k ones never really worked, so
  175. * this code can probably be deleted.
  176. */
  177. const size_t pad = 16;
  178. const size_t spec_data_size = 4096 - 2*pad;
  179. memset(out, 0, pad);
  180. memcpy(out + pad, guppi_udp_packet_data(p), spec_data_size);
  181. memset(out + pad + spec_data_size, 0, 2*pad);
  182. memcpy(out + pad + spec_data_size + pad + pad,
  183. guppi_udp_packet_data(p) + spec_data_size,
  184. spec_data_size);
  185. memset(out + pad + spec_data_size + pad
  186. + pad + spec_data_size, 0, pad);
  187. } else {
  188. /* Packet has full data, just do a memcpy */
  189. memcpy(out, guppi_udp_packet_data(p),
  190. guppi_udp_packet_datasize(p->packet_size));
  191. }
  192. }
  193. /* Copy function for baseband data that does a partial
  194. * corner turn (or transpose) based on nchan. In this case
  195. * out should point to the beginning of the data buffer.
  196. * block_pkt_idx is the seq number of this packet relative
  197. * to the beginning of the block. packets_per_block
  198. * is the total number of packets per data block (all channels).
  199. */
  200. void guppi_udp_packet_data_copy_transpose(char *databuf, int nchan,
  201. unsigned block_pkt_idx, unsigned packets_per_block,
  202. const struct guppi_udp_packet *p) {
  203. const unsigned chan_per_packet = nchan;
  204. const size_t bytes_per_sample = 4;
  205. const unsigned samp_per_packet = guppi_udp_packet_datasize(p->packet_size)
  206. / bytes_per_sample / chan_per_packet;
  207. const unsigned samp_per_block = packets_per_block * samp_per_packet;
  208. char *iptr, *optr;
  209. unsigned isamp,ichan;
  210. iptr = guppi_udp_packet_data(p);
  211. for (isamp=0; isamp<samp_per_packet; isamp++) {
  212. optr = databuf + bytes_per_sample * (block_pkt_idx*samp_per_packet
  213. + isamp);
  214. for (ichan=0; ichan<chan_per_packet; ichan++) {
  215. memcpy(optr, iptr, bytes_per_sample);
  216. iptr += bytes_per_sample;
  217. optr += bytes_per_sample*samp_per_block;
  218. }
  219. }
  220. #if 0
  221. // Old version...
  222. const unsigned pkt_idx = block_pkt_idx / nchan;
  223. const unsigned ichan = block_pkt_idx % nchan;
  224. const unsigned offset = ichan * packets_per_block / nchan + pkt_idx;
  225. memcpy(databuf + offset*guppi_udp_packet_datasize(p->packet_size),
  226. guppi_udp_packet_data(p),
  227. guppi_udp_packet_datasize(p->packet_size));
  228. #endif
  229. }
  230. size_t parkes_udp_packet_datasize(size_t packet_size) {
  231. return(packet_size - sizeof(unsigned long long));
  232. }
  233. void parkes_to_guppi(struct guppi_udp_packet *b, const int acc_len,
  234. const int npol, const int nchan) {
  235. /* Convert IBOB clock count to packet count.
  236. * This assumes 2 samples per IBOB clock, and that
  237. * acc_len is the actual accumulation length (=reg_acclen+1).
  238. */
  239. const unsigned int counts_per_packet = (nchan/2) * acc_len;
  240. unsigned long long *packet_idx = (unsigned long long *)b->data;
  241. (*packet_idx) = be64toh(*packet_idx); // Convert to host byte order
  242. (*packet_idx) /= counts_per_packet; // Do math
  243. (*packet_idx) = htobe64(*packet_idx); // Convert to big endian byte order
  244. /* Reorder from the 2-pol Parkes ordering */
  245. int i;
  246. char tmp[GUPPI_MAX_PACKET_SIZE];
  247. char *pol0, *pol1, *pol2, *pol3, *in;
  248. in = b->data + sizeof(long long);
  249. if (npol==2) {
  250. pol0 = &tmp[0];
  251. pol1 = &tmp[nchan];
  252. for (i=0; i<nchan/2; i++) {
  253. /* Each loop handles 2 values from each pol */
  254. memcpy(pol0, in, 2*sizeof(char));
  255. memcpy(pol1, &in[2], 2*sizeof(char));
  256. pol0 += 2;
  257. pol1 += 2;
  258. in += 4;
  259. }
  260. } else if (npol==4) {
  261. pol0 = &tmp[0];
  262. pol1 = &tmp[nchan];
  263. pol2 = &tmp[2*nchan];
  264. pol3 = &tmp[3*nchan];
  265. for (i=0; i<nchan; i++) {
  266. /* Each loop handles one sample */
  267. *pol0 = *in; in++; pol0++;
  268. *pol1 = *in; in++; pol1++;
  269. *pol2 = *in; in++; pol2++;
  270. *pol3 = *in; in++; pol3++;
  271. }
  272. }
  273. memcpy(b->data + sizeof(long long), tmp, sizeof(char) * npol * nchan);
  274. }
  275. /* Check that the size of the received SPEAD packet is correct.
  276. * This is acheived by reading the size fields in the SPEAD packet header,
  277. * and comparing them to the actual size of the received packet. */
  278. int guppi_chk_spead_pkt_size(const struct guppi_udp_packet *p)
  279. {
  280. unsigned int spead_hdr_upr = 0x53040305;
  281. int num_items, payload_size;
  282. int i;
  283. //Confirm we have enough bytes for header + 3 fields
  284. if(p->packet_size < 8*4)
  285. return (GUPPI_ERR_PACKET);
  286. //Check that the header is valid
  287. if( BYTE_ARR_TO_UINT(p->data, 0) != spead_hdr_upr )
  288. return (GUPPI_ERR_PACKET);
  289. //Get number of items (from last 2 bytes of header)
  290. num_items = p->data[6]<<8 | p->data[7];
  291. payload_size = -1;
  292. //Get packet payload length, by searching through the fields
  293. for(i = 8; i < (8 + num_items*8); i+=8)
  294. {
  295. //If we found the packet payload length item
  296. if( (p->data[i+1]<<8 | p->data[i+2]) == 4 )
  297. {
  298. payload_size = BYTE_ARR_TO_UINT(p->data, i/4 + 1);
  299. break;
  300. }
  301. }
  302. if(payload_size == -1)
  303. return (GUPPI_ERR_PACKET);
  304. //Confirm that packet size is correct
  305. if(p->packet_size != 8 + num_items*8 + payload_size)
  306. return (GUPPI_ERR_PACKET);
  307. return (GUPPI_OK);
  308. }
  309. unsigned int guppi_spead_packet_heap_cntr(const struct guppi_udp_packet *p)
  310. {
  311. int i;
  312. //Get heap counter, by searching through the fields
  313. for(i = 8; i < (8 + 4*8); i+=8)
  314. {
  315. //If we found the heap counter item
  316. if( (p->data[i+1]<<8 | p->data[i+2]) == 1 )
  317. {
  318. return BYTE_ARR_TO_UINT(p->data, i/4 + 1);
  319. }
  320. }
  321. return (GUPPI_ERR_PACKET);
  322. }
  323. unsigned int guppi_spead_packet_heap_offset(const struct guppi_udp_packet *p)
  324. {
  325. int i;
  326. //Get heap offset, by searching through the fields
  327. for(i = 8; i < (8 + 4*8); i+=8)
  328. {
  329. //If we found the heap offset item
  330. if( (p->data[i+1]<<8 | p->data[i+2]) == 3 )
  331. {
  332. return BYTE_ARR_TO_UINT(p->data, i/4 + 1);
  333. }
  334. }
  335. return (GUPPI_ERR_PACKET);
  336. }
  337. unsigned int guppi_spead_packet_seq_num(int heap_cntr, int heap_offset, int packets_per_heap)
  338. {
  339. return (heap_cntr * packets_per_heap) + (heap_offset / PAYLOAD_SIZE);
  340. }
  341. char* guppi_spead_packet_data(const struct guppi_udp_packet *p)
  342. {
  343. return (char*)(p->data + 5*8);
  344. }
  345. unsigned int guppi_spead_packet_datasize(const struct guppi_udp_packet *p)
  346. {
  347. return p->packet_size - 5*8;
  348. }
  349. int guppi_spead_packet_copy(struct guppi_udp_packet *p, char *header_addr,
  350. char* payload_addr, char bw_mode[])
  351. {
  352. int i, num_items;
  353. char* pkt_payload;
  354. int payload_size, offset;
  355. num_items = p->data[6]<<8 | p->data[7];
  356. /* Copy header, reversing both the ID and value of each field */
  357. for(i = 0; i < num_items - 4; i++)
  358. {
  359. header_addr[0]
  360. = guppi_spead_packet_data(p)[i*8]; //mode byte
  361. *((unsigned short *)(header_addr + 1))
  362. = ntohs(*(unsigned short *)(guppi_spead_packet_data(p) + i*8 + 1)); //ID (16 bits)
  363. header_addr[3]
  364. = guppi_spead_packet_data(p)[i*8 + 3]; //pad byte
  365. *((unsigned int *)(header_addr + 4))
  366. = ntohl(*(unsigned int *)(guppi_spead_packet_data(p) + i*8 + 4)); //value (32 bits)
  367. header_addr = (char*)(header_addr + 8);
  368. }
  369. /* Copy payload */
  370. pkt_payload = guppi_spead_packet_data(p) + (num_items - 4) * 8;
  371. payload_size = guppi_spead_packet_datasize(p) - (num_items - 4) * 8;
  372. /* If high-bandwidth mode */
  373. if(strncmp(bw_mode, "high", 4) == 0)
  374. {
  375. for(offset = 0; offset < payload_size; offset += 4)
  376. {
  377. *(unsigned int *)(payload_addr + offset) =
  378. ntohl(*(unsigned int *)(pkt_payload + offset));
  379. }
  380. }
  381. /* Else if low-bandwidth mode */
  382. else if(strncmp(bw_mode, "low", 3) == 0)
  383. memcpy(payload_addr, pkt_payload, payload_size);
  384. return 0;
  385. }
  386. int guppi_udp_close(struct guppi_udp_params *p) {
  387. close(p->sock);
  388. return(GUPPI_OK);
  389. }