PageRenderTime 218ms CodeModel.GetById 28ms RepoModel.GetById 58ms app.codeStats 0ms

/examples/simple_talker/simple_talker.c

https://github.com/masche842/Open-AVB
C | 1473 lines | 1252 code | 145 blank | 76 comment | 199 complexity | d8eaa69c51d621d693d20935b7aa137c MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0
  1. /******************************************************************************
  2. Copyright (c) 2012, Intel Corporation
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are met:
  6. 1. Redistributions of source code must retain the above copyright notice,
  7. this list of conditions and the following disclaimer.
  8. 2. Redistributions in binary form must reproduce the above copyright
  9. notice, this list of conditions and the following disclaimer in the
  10. documentation and/or other materials provided with the distribution.
  11. 3. Neither the name of the Intel Corporation nor the names of its
  12. contributors may be used to endorse or promote products derived from
  13. this software without specific prior written permission.
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  18. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  19. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  20. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  21. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  22. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  23. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  24. POSSIBILITY OF SUCH DAMAGE.
  25. ******************************************************************************/
  26. #include <unistd.h>
  27. #include <fcntl.h>
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <syslog.h>
  32. #include <signal.h>
  33. #include <errno.h>
  34. #include <sys/ioctl.h>
  35. #include <sys/time.h>
  36. #include <sys/resource.h>
  37. #include <sys/mman.h>
  38. #include <sys/user.h>
  39. #include <pci/pci.h>
  40. #include <sys/socket.h>
  41. #include <linux/if.h>
  42. #include <netpacket/packet.h>
  43. #include <netinet/in.h>
  44. #include <netinet/ip.h>
  45. #include <arpa/inet.h>
  46. #include <net/ethernet.h>
  47. #include <sys/un.h>
  48. #include <pthread.h>
  49. #include <poll.h>
  50. #include <sys/mman.h>
  51. #include <sys/stat.h>
  52. #include <fcntl.h>
  53. #include "igb.h"
  54. #include "mrpd.h"
  55. #include "mrp.h"
  56. #include "msrp.h"
  57. #include <math.h>
  58. #include <endian.h>
  59. #include <stdint.h>
  60. typedef struct {
  61. int64_t ml_phoffset;
  62. int64_t ls_phoffset;
  63. long double ml_freqoffset;
  64. long double ls_freqoffset;
  65. uint64_t local_time;
  66. } gPtpTimeData;
  67. #define SHM_SIZE 4*8 + sizeof(pthread_mutex_t) /* 3 - 64 bit and 2 - 32 bits */
  68. #define SHM_NAME "/ptp"
  69. #define MAX_SAMPLE_VALUE ((1U << ((sizeof(int32_t)*8)-1))-1)
  70. #define SRC_CHANNELS (2)
  71. #define SAMPLES_PER_SECOND (48000)
  72. #define FREQUENCY (480)
  73. #define SAMPLES_PER_CYCLE (SAMPLES_PER_SECOND/FREQUENCY)
  74. #define GAIN (.5)
  75. #define L16_PAYLOAD_TYPE 96 /* Should be negotiated via RTSP */
  76. #define ID_B_HDR_EXT_ID 0 /* Should be negotiated via RTSP */
  77. #define CD_SUBTYPE 0x02 /* for simple audio format */
  78. #define SV_VER_MR_RS_GV_TV 0x81
  79. #define RS_TU 0x00
  80. #define SAMPLE_FORMAT_NON_INTR_FLOAT 0x02
  81. #define NOMINAL_SAMPLE_RATE 0x09
  82. #define LINEAR_SAMPLE_MSB 0x20
  83. unsigned char GATEWAY_INFO[] =
  84. { SAMPLE_FORMAT_NON_INTR_FLOAT, 0, NOMINAL_SAMPLE_RATE, LINEAR_SAMPLE_MSB };
  85. #define SAMPLE_SIZE 4 /* 4 bytes */
  86. #define L2_SAMPLES_PER_FRAME 6
  87. #define L4_SAMPLES_PER_FRAME 60
  88. #define L4_SAMPLE_SIZE 2
  89. #define CHANNELS 2
  90. #define PAYLOAD_SIZE SAMPLE_SIZE*SAMPLES_PER_FRAME*CHANNELS /* 6*4 * 2 channels = 48 bytes */
  91. #define RTP_SUBNS_SCALE_NUM 20000000
  92. #define RTP_SUBNS_SCALE_DEN 4656613
  93. #define IGB_BIND_NAMESZ 24
  94. #define XMIT_DELAY (200000000) /* us */
  95. #define RENDER_DELAY (XMIT_DELAY+2000000) /* us */
  96. typedef enum { false = 0, true = 1 } bool;
  97. typedef struct __attribute__ ((packed)) {
  98. uint64_t subtype:7;
  99. uint64_t cd_indicator:1;
  100. uint64_t timestamp_valid:1;
  101. uint64_t gateway_valid:1;
  102. uint64_t reserved0:1;
  103. uint64_t reset:1;
  104. uint64_t version:3;
  105. uint64_t sid_valid:1;
  106. uint64_t seq_number:8;
  107. uint64_t timestamp_uncertain:1;
  108. uint64_t reserved1:7;
  109. uint64_t stream_id;
  110. uint64_t timestamp:32;
  111. uint64_t gateway_info:32;
  112. uint64_t length:16;
  113. } seventeen22_header;
  114. /* 61883 CIP with SYT Field */
  115. typedef struct __attribute__ ((packed)) {
  116. uint16_t packet_channel:6;
  117. uint16_t format_tag:2;
  118. uint16_t app_control:4;
  119. uint16_t packet_tcode:4;
  120. uint16_t source_id:6;
  121. uint16_t reserved0:2;
  122. uint16_t data_block_size:8;
  123. uint16_t reserved1:2;
  124. uint16_t source_packet_header:1;
  125. uint16_t quadlet_padding_count:3;
  126. uint16_t fraction_number:2;
  127. uint16_t data_block_continuity:8;
  128. uint16_t format_id:6;
  129. uint16_t eoh:2;
  130. uint16_t format_dependent_field:8;
  131. uint16_t syt;
  132. } six1883_header;
  133. typedef struct __attribute__ ((packed)) {
  134. uint8_t label;
  135. uint8_t value[3];
  136. } six1883_sample;
  137. typedef struct __attribute__ ((packed)) {
  138. uint8_t version_length;
  139. uint8_t DSCP_ECN;
  140. uint16_t ip_length;
  141. uint16_t id;
  142. uint16_t fragmentation;
  143. uint8_t ttl;
  144. uint8_t protocol;
  145. uint16_t hdr_cksum;
  146. uint32_t src;
  147. uint32_t dest;
  148. uint16_t source_port;
  149. uint16_t dest_port;
  150. uint16_t udp_length;
  151. uint16_t cksum;
  152. uint8_t version_cc;
  153. uint8_t mark_payload;
  154. uint16_t sequence;
  155. uint32_t timestamp;
  156. uint32_t ssrc;
  157. uint8_t tag[2];
  158. uint16_t total_length;
  159. uint8_t tag_length;
  160. uint8_t seconds[3];
  161. uint32_t nanoseconds;
  162. } IP_RTP_Header;
  163. typedef struct __attribute__ ((packed)) {
  164. uint32_t source;
  165. uint32_t dest;
  166. uint8_t zero;
  167. uint8_t protocol;
  168. uint16_t length;
  169. } IP_PseudoHeader;
  170. /* global variables */
  171. int control_socket = -1;
  172. device_t igb_dev;
  173. volatile int halt_tx = 0;
  174. volatile int listeners = 0;
  175. volatile int mrp_okay;
  176. volatile int mrp_error = 0;;
  177. volatile int domain_a_valid = 0;
  178. int domain_class_a_id;
  179. int domain_class_a_priority;
  180. int domain_class_a_vid;
  181. volatile int domain_b_valid = 0;
  182. int domain_class_b_id;
  183. int domain_class_b_priority;
  184. int domain_class_b_vid;
  185. #define VERSION_STR "1.0"
  186. static const char *version_str = "simple_talker v" VERSION_STR "\n"
  187. "Copyright (c) 2012, Intel Corporation\n";
  188. #define MRPD_PORT_DEFAULT 7500
  189. uint16_t inet_checksum(uint8_t *ip, int len){
  190. uint32_t sum = 0; /* assume 32 bit long, 16 bit short */
  191. while(len > 1){
  192. sum += *(( uint16_t *) ip); ip += 2;
  193. if(sum & 0x80000000) /* if high order bit set, fold */
  194. sum = (sum & 0xFFFF) + (sum >> 16);
  195. len -= 2;
  196. }
  197. if(len) /* take care of left over byte */
  198. sum += (uint16_t) *(uint8_t *)ip;
  199. while(sum>>16)
  200. sum = (sum & 0xFFFF) + (sum >> 16);
  201. return ~sum;
  202. }
  203. #if 0
  204. else {
  205. if(sum & 0x80000000) /* if high order bit set, fold */
  206. sum = (sum & 0xFFFF) + (sum >> 16);
  207. sum += *(( uint16_t *) buf_iov->iov_base); buf_iov->iov_base += 2;
  208. buf_iov->iov_len -= 2;
  209. }
  210. #endif
  211. uint16_t inet_checksum_sg( struct iovec *buf_iov, size_t buf_iovlen ){
  212. size_t i;
  213. uint32_t sum = 0; /* assume 32 bit long, 16 bit short */
  214. uint8_t residual;
  215. int has_residual = 0;
  216. for( i = 0; i < buf_iovlen; ++i,++buf_iov ) {
  217. if( has_residual ) {
  218. if( buf_iov->iov_len > 0 ) {
  219. if(sum & 0x80000000) /* if high order bit set, fold */
  220. sum = (sum & 0xFFFF) + (sum >> 16);
  221. sum += residual | (*(( uint8_t *) buf_iov->iov_base) << 8);
  222. buf_iov->iov_base += 1;
  223. buf_iov->iov_len -= 1;
  224. } else {
  225. if(sum & 0x80000000) /* if high order bit set, fold */
  226. sum = (sum & 0xFFFF) + (sum >> 16);
  227. sum += (uint16_t) residual;
  228. }
  229. has_residual = 0;
  230. }
  231. while(buf_iov->iov_len > 1){
  232. if(sum & 0x80000000) /* if high order bit set, fold */
  233. sum = (sum & 0xFFFF) + (sum >> 16);
  234. sum += *(( uint16_t *) buf_iov->iov_base); buf_iov->iov_base += 2;
  235. buf_iov->iov_len -= 2;
  236. }
  237. if( buf_iov->iov_len ) {
  238. residual = *(( uint8_t *) buf_iov->iov_base);
  239. has_residual = 1;
  240. }
  241. }
  242. if( has_residual ) {
  243. sum += (uint16_t) residual;
  244. }
  245. while(sum>>16)
  246. sum = (sum & 0xFFFF) + (sum >> 16);
  247. return ~sum;
  248. }
  249. static inline uint64_t ST_rdtsc(void)
  250. {
  251. uint64_t ret;
  252. unsigned c, d;
  253. asm volatile ("rdtsc":"=a" (c), "=d"(d));
  254. ret = d;
  255. ret <<= 32;
  256. ret |= c;
  257. return ret;
  258. }
  259. static int shm_fd = -1;
  260. static char *memory_offset_buffer = NULL;
  261. int gptpinit(void)
  262. {
  263. shm_fd = shm_open(SHM_NAME, O_RDWR, 0);
  264. if (shm_fd == -1) {
  265. perror("shm_open()");
  266. return false;
  267. }
  268. memory_offset_buffer =
  269. (char *)mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
  270. shm_fd, 0);
  271. if (memory_offset_buffer == (char *)-1) {
  272. perror("mmap()");
  273. memory_offset_buffer = NULL;
  274. shm_unlink(SHM_NAME);
  275. return false;
  276. }
  277. return true;
  278. }
  279. void gptpdeinit(void)
  280. {
  281. if (memory_offset_buffer != NULL) {
  282. munmap(memory_offset_buffer, SHM_SIZE);
  283. }
  284. if (shm_fd != -1) {
  285. close(shm_fd);
  286. }
  287. }
  288. int gptpscaling(gPtpTimeData * td)
  289. {
  290. pthread_mutex_lock((pthread_mutex_t *) memory_offset_buffer);
  291. memcpy(td, memory_offset_buffer + sizeof(pthread_mutex_t), sizeof(*td));
  292. pthread_mutex_unlock((pthread_mutex_t *) memory_offset_buffer);
  293. fprintf(stderr, "ml_phoffset = %lld, ls_phoffset = %lld\n",
  294. td->ml_phoffset, td->ls_phoffset);
  295. fprintf(stderr, "ml_freqffset = %Lf, ls_freqoffset = %Lf\n",
  296. td->ml_freqoffset, td->ls_freqoffset);
  297. return true;
  298. }
  299. void gensine32(int32_t * buf, unsigned count)
  300. {
  301. long double interval = (2 * ((long double)M_PI)) / count;
  302. unsigned i;
  303. for (i = 0; i < count; ++i) {
  304. buf[i] =
  305. (int32_t) (MAX_SAMPLE_VALUE * sinl(i * interval) * GAIN);
  306. }
  307. }
  308. int get_samples(unsigned count, int32_t * buffer)
  309. {
  310. static int init = 0;
  311. static int32_t samples_onechannel[100];
  312. static unsigned index = 0;
  313. if (init == 0) {
  314. gensine32(samples_onechannel, 100);
  315. init = 1;
  316. }
  317. while (count > 0) {
  318. int i;
  319. for (i = 0; i < SRC_CHANNELS; ++i) {
  320. *(buffer++) = samples_onechannel[index];
  321. }
  322. index = (index + 1) % 100;
  323. --count;
  324. }
  325. return 0;
  326. }
  327. int mrp_join_listener(uint8_t * streamid);
  328. int send_mrp_msg(char *notify_data, int notify_len)
  329. {
  330. struct sockaddr_in addr;
  331. socklen_t addr_len;
  332. memset(&addr, 0, sizeof(addr));
  333. addr.sin_family = AF_INET;
  334. addr.sin_port = htons(MRPD_PORT_DEFAULT);
  335. inet_aton("127.0.0.1", &addr.sin_addr);
  336. addr_len = sizeof(addr);
  337. if (control_socket != -1)
  338. return (sendto
  339. (control_socket, notify_data, notify_len, 0,
  340. (struct sockaddr *)&addr, addr_len));
  341. else
  342. return (0);
  343. }
  344. int mrp_connect()
  345. {
  346. struct sockaddr_in addr;
  347. int sock_fd = -1;
  348. sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  349. if (sock_fd < 0)
  350. goto out;
  351. memset(&addr, 0, sizeof(addr));
  352. addr.sin_family = AF_INET;
  353. addr.sin_port = htons(MRPD_PORT_DEFAULT);
  354. inet_aton("127.0.0.1", &addr.sin_addr);
  355. memset(&addr, 0, sizeof(addr));
  356. control_socket = sock_fd;
  357. return (0);
  358. out: if (sock_fd != -1)
  359. close(sock_fd);
  360. sock_fd = -1;
  361. return (-1);
  362. }
  363. int mrp_disconnect()
  364. {
  365. char *msgbuf;
  366. int rc;
  367. msgbuf = malloc(64);
  368. if (NULL == msgbuf)
  369. return -1;
  370. memset(msgbuf, 0, 64);
  371. sprintf(msgbuf, "BYE");
  372. mrp_okay = 0;
  373. rc = send_mrp_msg(msgbuf, 1500);
  374. /* rc = recv_mrp_okay(); */
  375. free(msgbuf);
  376. return rc;
  377. }
  378. int recv_mrp_okay()
  379. {
  380. while ((mrp_okay == 0) && (mrp_error == 0))
  381. usleep(20000);
  382. return 0;
  383. }
  384. int mrp_register_domain(int *class_id, int *priority, u_int16_t * vid)
  385. {
  386. char *msgbuf;
  387. int rc;
  388. msgbuf = malloc(64);
  389. if (NULL == msgbuf)
  390. return -1;
  391. memset(msgbuf, 0, 64);
  392. sprintf(msgbuf, "S+D:C=%d,P=%d,V=%04x", *class_id, *priority, *vid);
  393. mrp_okay = 0;
  394. rc = send_mrp_msg(msgbuf, 1500);
  395. /* rc = recv_mrp_okay(); */
  396. free(msgbuf);
  397. return rc;
  398. }
  399. int mrp_get_domain(int *class_a_id, int *a_priority, u_int16_t * a_vid,
  400. int *class_b_id, int *b_priority, u_int16_t * b_vid)
  401. {
  402. char *msgbuf;
  403. /* we may not get a notification if we are joining late,
  404. * so query for what is already there ...
  405. */
  406. msgbuf = malloc(64);
  407. if (NULL == msgbuf)
  408. return -1;
  409. memset(msgbuf, 0, 64);
  410. sprintf(msgbuf, "S??");
  411. send_mrp_msg(msgbuf, 64);
  412. free(msgbuf);
  413. while (!halt_tx && (domain_a_valid == 0) && (domain_b_valid == 0))
  414. usleep(20000);
  415. *class_a_id = 0;
  416. *a_priority = 0;
  417. *a_vid = 0;
  418. *class_b_id = 0;
  419. *b_priority = 0;
  420. *b_vid = 0;
  421. if (domain_a_valid) {
  422. *class_a_id = domain_class_a_id;
  423. *a_priority = domain_class_a_priority;
  424. *a_vid = domain_class_a_vid;
  425. }
  426. if (domain_b_valid) {
  427. *class_b_id = domain_class_b_id;
  428. *b_priority = domain_class_b_priority;
  429. *b_vid = domain_class_b_vid;
  430. }
  431. return (0);
  432. }
  433. unsigned char monitor_stream_id[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  434. int mrp_await_listener(unsigned char *streamid)
  435. {
  436. char *msgbuf;
  437. memcpy(monitor_stream_id, streamid, sizeof(monitor_stream_id));
  438. msgbuf = malloc(64);
  439. if (NULL == msgbuf)
  440. return -1;
  441. memset(msgbuf, 0, 64);
  442. sprintf(msgbuf, "S??");
  443. send_mrp_msg(msgbuf, 64);
  444. free(msgbuf);
  445. /* either already there ... or need to wait ... */
  446. while (!halt_tx && (listeners == 0))
  447. usleep(20000);
  448. return (0);
  449. }
  450. int process_mrp_msg(char *buf, int buflen)
  451. {
  452. /*
  453. * 1st character indicates application
  454. * [MVS] - MAC, VLAN or STREAM
  455. */
  456. unsigned int id;
  457. unsigned int priority;
  458. unsigned int vid;
  459. int i, j, k;
  460. unsigned int substate;
  461. unsigned char recovered_streamid[8];
  462. k = 0;
  463. next_line:if (k >= buflen)
  464. return (0);
  465. switch (buf[k]) {
  466. case 'E':
  467. printf("%s from mrpd\n", buf);
  468. fflush(stdout);
  469. mrp_error = 1;
  470. break;
  471. case 'O':
  472. mrp_okay = 1;
  473. break;
  474. case 'M':
  475. case 'V':
  476. printf("%s unhandled from mrpd\n", buf);
  477. fflush(stdout);
  478. /* unhandled for now */
  479. break;
  480. case 'L':
  481. /* parse a listener attribute - see if it matches our monitor_stream_id */
  482. i = k;
  483. while (buf[i] != 'D')
  484. i++;
  485. i += 2; /* skip the ':' */
  486. sscanf(&(buf[i]), "%d", &substate);
  487. while (buf[i] != 'S')
  488. i++;
  489. i += 2; /* skip the ':' */
  490. for (j = 0; j < 8; j++) {
  491. sscanf(&(buf[i + 2 * j]), "%02x", &id);
  492. recovered_streamid[j] = (unsigned char)id;
  493. } printf
  494. ("FOUND STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ",
  495. recovered_streamid[0], recovered_streamid[1],
  496. recovered_streamid[2], recovered_streamid[3],
  497. recovered_streamid[4], recovered_streamid[5],
  498. recovered_streamid[6], recovered_streamid[7]);
  499. switch (substate) {
  500. case 0:
  501. printf("with state ignore\n");
  502. break;
  503. case 1:
  504. printf("with state askfailed\n");
  505. break;
  506. case 2:
  507. printf("with state ready\n");
  508. break;
  509. case 3:
  510. printf("with state readyfail\n");
  511. break;
  512. default:
  513. printf("with state UNKNOWN (%d)\n", substate);
  514. break;
  515. }
  516. if (substate > MSRP_LISTENER_ASKFAILED) {
  517. if (memcmp
  518. (recovered_streamid, monitor_stream_id,
  519. sizeof(recovered_streamid)) == 0) {
  520. listeners = 1;
  521. printf("added listener\n");
  522. }
  523. }
  524. fflush(stdout);
  525. /* try to find a newline ... */
  526. while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
  527. i++;
  528. if (i == buflen)
  529. return (0);
  530. if (buf[i] == '\0')
  531. return (0);
  532. i++;
  533. k = i;
  534. goto next_line;
  535. break;
  536. case 'D':
  537. i = k + 4;
  538. /* save the domain attribute */
  539. sscanf(&(buf[i]), "%d", &id);
  540. while (buf[i] != 'P')
  541. i++;
  542. i += 2; /* skip the ':' */
  543. sscanf(&(buf[i]), "%d", &priority);
  544. while (buf[i] != 'V')
  545. i++;
  546. i += 2; /* skip the ':' */
  547. sscanf(&(buf[i]), "%x", &vid);
  548. if (id == 6) {
  549. domain_class_a_id = id;
  550. domain_class_a_priority = priority;
  551. domain_class_a_vid = vid;
  552. domain_a_valid = 1;
  553. } else {
  554. domain_class_b_id = id;
  555. domain_class_b_priority = priority;
  556. domain_class_b_vid = vid;
  557. domain_b_valid = 1;
  558. }
  559. while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
  560. i++;
  561. if ((i == buflen) || (buf[i] == '\0'))
  562. return (0);
  563. i++;
  564. k = i;
  565. goto next_line;
  566. break;
  567. case 'T':
  568. /* as simple_talker we don't care about other talkers */
  569. i = k;
  570. while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
  571. i++;
  572. if (i == buflen)
  573. return (0);
  574. if (buf[i] == '\0')
  575. return (0);
  576. i++;
  577. k = i;
  578. goto next_line;
  579. break;
  580. case 'S':
  581. /* handle the leave/join events */
  582. switch (buf[k + 4]) {
  583. case 'L':
  584. i = k + 5;
  585. while (buf[i] != 'D')
  586. i++;
  587. i += 2; /* skip the ':' */
  588. sscanf(&(buf[i]), "%d", &substate);
  589. while (buf[i] != 'S')
  590. i++;
  591. i += 2; /* skip the ':' */
  592. for (j = 0; j < 8; j++) {
  593. sscanf(&(buf[i + 2 * j]), "%02x", &id);
  594. recovered_streamid[j] = (unsigned char)id;
  595. } printf
  596. ("EVENT on STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ",
  597. recovered_streamid[0], recovered_streamid[1],
  598. recovered_streamid[2], recovered_streamid[3],
  599. recovered_streamid[4], recovered_streamid[5],
  600. recovered_streamid[6], recovered_streamid[7]);
  601. switch (substate) {
  602. case 0:
  603. printf("with state ignore\n");
  604. break;
  605. case 1:
  606. printf("with state askfailed\n");
  607. break;
  608. case 2:
  609. printf("with state ready\n");
  610. break;
  611. case 3:
  612. printf("with state readyfail\n");
  613. break;
  614. default:
  615. printf("with state UNKNOWN (%d)\n", substate);
  616. break;
  617. }
  618. switch (buf[k + 1]) {
  619. case 'L':
  620. printf("got a leave indication\n");
  621. if (memcmp
  622. (recovered_streamid, monitor_stream_id,
  623. sizeof(recovered_streamid)) == 0) {
  624. listeners = 0;
  625. printf("listener left\n");
  626. }
  627. break;
  628. case 'J':
  629. case 'N':
  630. printf("got a new/join indication\n");
  631. if (substate > MSRP_LISTENER_ASKFAILED) {
  632. if (memcmp
  633. (recovered_streamid,
  634. monitor_stream_id,
  635. sizeof(recovered_streamid)) == 0)
  636. listeners = 1;
  637. }
  638. break;
  639. }
  640. /* only care about listeners ... */
  641. default:
  642. return (0);
  643. break;
  644. }
  645. break;
  646. case '\0':
  647. break;
  648. }
  649. return (0);
  650. }
  651. void *mrp_monitor_thread(void *arg)
  652. {
  653. char *msgbuf;
  654. struct sockaddr_in client_addr;
  655. struct msghdr msg;
  656. struct iovec iov;
  657. int bytes = 0;
  658. struct pollfd fds;
  659. int rc;
  660. if (NULL == arg)
  661. rc = 0;
  662. else
  663. rc = 1;
  664. msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
  665. if (NULL == msgbuf)
  666. return NULL;
  667. while (!halt_tx) {
  668. fds.fd = control_socket;
  669. fds.events = POLLIN;
  670. fds.revents = 0;
  671. rc = poll(&fds, 1, 100);
  672. if (rc < 0) {
  673. free(msgbuf);
  674. pthread_exit(NULL);
  675. }
  676. if (rc == 0)
  677. continue;
  678. if ((fds.revents & POLLIN) == 0) {
  679. free(msgbuf);
  680. pthread_exit(NULL);
  681. }
  682. memset(&msg, 0, sizeof(msg));
  683. memset(&client_addr, 0, sizeof(client_addr));
  684. memset(msgbuf, 0, MAX_MRPD_CMDSZ);
  685. iov.iov_len = MAX_MRPD_CMDSZ;
  686. iov.iov_base = msgbuf;
  687. msg.msg_name = &client_addr;
  688. msg.msg_namelen = sizeof(client_addr);
  689. msg.msg_iov = &iov;
  690. msg.msg_iovlen = 1;
  691. bytes = recvmsg(control_socket, &msg, 0);
  692. if (bytes < 0)
  693. continue;
  694. process_mrp_msg(msgbuf, bytes);
  695. }
  696. free(msgbuf);
  697. pthread_exit(NULL);
  698. }
  699. pthread_t monitor_thread;
  700. pthread_attr_t monitor_attr;
  701. int mrp_monitor()
  702. {
  703. pthread_attr_init(&monitor_attr);
  704. pthread_create(&monitor_thread, NULL, mrp_monitor_thread, NULL);
  705. return (0);
  706. }
  707. int mrp_join_vlan()
  708. {
  709. char *msgbuf;
  710. int rc;
  711. msgbuf = malloc(1500);
  712. if (NULL == msgbuf)
  713. return -1;
  714. memset(msgbuf, 0, 1500);
  715. sprintf(msgbuf, "V++:I=0002");
  716. rc = send_mrp_msg(msgbuf, 1500);
  717. free(msgbuf);
  718. return rc;
  719. }
  720. int mrp_join_listener(uint8_t * streamid)
  721. {
  722. char *msgbuf;
  723. int rc;
  724. msgbuf = malloc(1500);
  725. if (NULL == msgbuf)
  726. return -1;
  727. memset(msgbuf, 0, 1500);
  728. sprintf(msgbuf, "S+L:S=%02X%02X%02X%02X%02X%02X%02X%02X"
  729. ",D=2", streamid[0], streamid[1], streamid[2], streamid[3],
  730. streamid[4], streamid[5], streamid[6], streamid[7]);
  731. mrp_okay = 0;
  732. rc = send_mrp_msg(msgbuf, 1500);
  733. /* rc = recv_mrp_okay(); */
  734. free(msgbuf);
  735. return rc;
  736. }
  737. int
  738. mrp_advertise_stream(uint8_t * streamid,
  739. uint8_t * destaddr,
  740. u_int16_t vlan,
  741. int pktsz, int interval, int priority, int latency)
  742. {
  743. char *msgbuf;
  744. int rc;
  745. msgbuf = malloc(1500);
  746. if (NULL == msgbuf)
  747. return -1;
  748. memset(msgbuf, 0, 1500);
  749. sprintf(msgbuf, "S++:S=%02X%02X%02X%02X%02X%02X%02X%02X"
  750. ",A=%02X%02X%02X%02X%02X%02X"
  751. ",V=%04X"
  752. ",Z=%d"
  753. ",I=%d"
  754. ",P=%d"
  755. ",L=%d", streamid[0], streamid[1], streamid[2],
  756. streamid[3], streamid[4], streamid[5], streamid[6],
  757. streamid[7], destaddr[0], destaddr[1], destaddr[2],
  758. destaddr[3], destaddr[4], destaddr[5], vlan, pktsz,
  759. interval, priority << 5, latency);
  760. mrp_okay = 0;
  761. rc = send_mrp_msg(msgbuf, 1500);
  762. /* rc = recv_mrp_okay(); */
  763. free(msgbuf);
  764. return rc;
  765. }
  766. int
  767. mrp_unadvertise_stream(uint8_t * streamid,
  768. uint8_t * destaddr,
  769. u_int16_t vlan,
  770. int pktsz, int interval, int priority, int latency)
  771. {
  772. char *msgbuf;
  773. int rc;
  774. msgbuf = malloc(1500);
  775. if (NULL == msgbuf)
  776. return -1;
  777. memset(msgbuf, 0, 1500);
  778. sprintf(msgbuf, "S--:S=%02X%02X%02X%02X%02X%02X%02X%02X"
  779. ",A=%02X%02X%02X%02X%02X%02X"
  780. ",V=%04X"
  781. ",Z=%d"
  782. ",I=%d"
  783. ",P=%d"
  784. ",L=%d", streamid[0], streamid[1], streamid[2],
  785. streamid[3], streamid[4], streamid[5], streamid[6],
  786. streamid[7], destaddr[0], destaddr[1], destaddr[2],
  787. destaddr[3], destaddr[4], destaddr[5], vlan, pktsz,
  788. interval, priority << 5, latency);
  789. mrp_okay = 0;
  790. rc = send_mrp_msg(msgbuf, 1500);
  791. /* rc = recv_mrp_okay(); */
  792. free(msgbuf);
  793. return rc;
  794. }
  795. void sigint_handler(int signum)
  796. {
  797. printf("got SIGINT\n");
  798. halt_tx = signum;
  799. }
  800. int pci_connect()
  801. {
  802. struct pci_access *pacc;
  803. struct pci_dev *dev;
  804. int err;
  805. char devpath[IGB_BIND_NAMESZ];
  806. memset(&igb_dev, 0, sizeof(device_t));
  807. pacc = pci_alloc();
  808. pci_init(pacc);
  809. pci_scan_bus(pacc);
  810. for (dev = pacc->devices; dev; dev = dev->next) {
  811. pci_fill_info(dev,
  812. PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS);
  813. igb_dev.pci_vendor_id = dev->vendor_id;
  814. igb_dev.pci_device_id = dev->device_id;
  815. igb_dev.domain = dev->domain;
  816. igb_dev.bus = dev->bus;
  817. igb_dev.dev = dev->dev;
  818. igb_dev.func = dev->func;
  819. snprintf(devpath, IGB_BIND_NAMESZ, "%04x:%02x:%02x.%d",
  820. dev->domain, dev->bus, dev->dev, dev->func);
  821. err = igb_probe(&igb_dev);
  822. if (err) {
  823. continue;
  824. }
  825. printf("attaching to %s\n", devpath);
  826. err = igb_attach(devpath, &igb_dev);
  827. if (err) {
  828. printf("attach failed! (%s)\n", strerror(errno));
  829. continue;
  830. }
  831. goto out;
  832. }
  833. pci_cleanup(pacc);
  834. return ENXIO;
  835. out: pci_cleanup(pacc);
  836. return 0;
  837. }
  838. unsigned char STATION_ADDR[] = { 0, 0, 0, 0, 0, 0 };
  839. unsigned char STREAM_ID[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  840. /* IEEE 1722 reserved address */
  841. unsigned char L2_DEST_ADDR[] = { 0x91, 0xE0, 0xF0, 0x00, 0x0e, 0x80 };
  842. unsigned char L3_DEST_ADDR[] = { 224, 0, 0, 115 };
  843. uint16_t L3_PORT = 5004;
  844. void l3_to_l2_multicast( unsigned char *l2, unsigned char *l3 ) {
  845. l2[0] = 0x1;
  846. l2[1] = 0x0;
  847. l2[2] = 0x5e;
  848. l2[3] = l3[1] & 0x7F;
  849. l2[4] = l3[2];
  850. l2[5] = l3[3];
  851. }
  852. int get_mac_address(char *interface)
  853. {
  854. struct ifreq if_request;
  855. int lsock;
  856. int rc;
  857. lsock = socket(PF_PACKET, SOCK_RAW, htons(0x800));
  858. if (lsock < 0)
  859. return -1;
  860. memset(&if_request, 0, sizeof(if_request));
  861. strncpy(if_request.ifr_name, interface, sizeof(if_request.ifr_name));
  862. rc = ioctl(lsock, SIOCGIFHWADDR, &if_request);
  863. if (rc < 0) {
  864. close(lsock);
  865. return -1;
  866. }
  867. memcpy(STATION_ADDR, if_request.ifr_hwaddr.sa_data,
  868. sizeof(STATION_ADDR));
  869. close(lsock);
  870. return 0;
  871. }
  872. static void usage(void)
  873. {
  874. fprintf(stderr, "\n"
  875. "usage: simple_talker [-h] -i interface-name"
  876. "\n"
  877. "options:\n"
  878. " -h show this message\n"
  879. " -i specify interface for AVB connection\n"
  880. " -t transport equal to 2 for 1722 or 3 for RTP\n"
  881. "\n" "%s" "\n", version_str);
  882. exit(1);
  883. }
  884. #define L2_PACKET_IPG (125000) /* (1) packet every 125 usec */
  885. #define L4_PACKET_IPG (1250000) /* (1) packet every 1.25 millisec */
  886. int main(int argc, char *argv[])
  887. {
  888. unsigned i;
  889. int err;
  890. struct igb_dma_alloc a_page;
  891. struct igb_packet a_packet;
  892. struct igb_packet *tmp_packet;
  893. struct igb_packet *cleaned_packets;
  894. struct igb_packet *free_packets;
  895. int c;
  896. u_int64_t last_time;
  897. int rc = 0;
  898. char *interface = NULL;
  899. int transport = -1;
  900. int class_a_id = 0;
  901. int a_priority = 0;
  902. u_int16_t a_vid = 0;
  903. #ifdef DOMAIN_QUERY
  904. int class_b_id = 0;
  905. int b_priority = 0;
  906. u_int16_t b_vid = 0;
  907. #endif
  908. uint16_t seqnum;
  909. uint32_t rtp_timestamp;
  910. uint64_t time_stamp;
  911. unsigned total_samples = 0;
  912. gPtpTimeData td;
  913. int32_t sample_buffer[L4_SAMPLES_PER_FRAME * SRC_CHANNELS];
  914. seventeen22_header *l2_header0;
  915. six1883_header *l2_header1;
  916. six1883_sample *sample;
  917. IP_RTP_Header *l4_headers;
  918. IP_PseudoHeader pseudo_hdr;
  919. unsigned l4_local_address = 0;
  920. int sd;
  921. struct sockaddr_in local;
  922. struct ifreq if_request;
  923. uint64_t now_local, now_8021as;
  924. uint64_t update_8021as;
  925. unsigned delta_8021as, delta_local;
  926. uint8_t dest_addr[6];
  927. size_t packet_size;
  928. for (;;) {
  929. c = getopt(argc, argv, "hi:t:");
  930. if (c < 0)
  931. break;
  932. switch (c) {
  933. case 'h':
  934. usage();
  935. break;
  936. case 'i':
  937. if (interface) {
  938. printf
  939. ("only one interface per daemon is supported\n");
  940. usage();
  941. }
  942. interface = strdup(optarg);
  943. break;
  944. case 't':
  945. transport = strtoul( optarg, NULL, 10 );
  946. }
  947. }
  948. if (optind < argc)
  949. usage();
  950. if (NULL == interface) {
  951. usage();
  952. }
  953. if( transport != 2 && transport != 4 ) {
  954. fprintf( stderr, "Must specify valid transport\n" );
  955. usage();
  956. }
  957. rc = mrp_connect();
  958. if (rc) {
  959. printf("socket creation failed\n");
  960. return (errno);
  961. }
  962. err = pci_connect();
  963. if (err) {
  964. printf("connect failed (%s) - are you running as root?\n",
  965. strerror(errno));
  966. return (errno);
  967. }
  968. err = igb_init(&igb_dev);
  969. if (err) {
  970. printf("init failed (%s) - is the driver really loaded?\n",
  971. strerror(errno));
  972. return (errno);
  973. }
  974. err = igb_dma_malloc_page(&igb_dev, &a_page);
  975. if (err) {
  976. printf("malloc failed (%s) - out of memory?\n",
  977. strerror(errno));
  978. return (errno);
  979. }
  980. signal(SIGINT, sigint_handler);
  981. rc = get_mac_address(interface);
  982. if (rc) {
  983. printf("failed to open interface\n");
  984. usage();
  985. }
  986. if( transport == 2 ) {
  987. memcpy( dest_addr, L2_DEST_ADDR, sizeof(dest_addr));
  988. } else {
  989. memset( &local, 0, sizeof( local ));
  990. local.sin_family = PF_INET;
  991. local.sin_addr.s_addr = htonl( INADDR_ANY );
  992. local.sin_port = htons( L3_PORT );
  993. l3_to_l2_multicast( dest_addr, L3_DEST_ADDR );
  994. memset( &if_request, 0, sizeof( if_request ));
  995. strncpy(if_request.ifr_name, interface, sizeof(if_request.ifr_name)-1);
  996. sd = socket( AF_INET, SOCK_DGRAM, 0 );
  997. if( sd == -1 ) {
  998. printf( "Failed to open socket: %s\n", strerror( errno ));
  999. return errno;
  1000. }
  1001. if( bind( sd, (struct sockaddr *) &local, sizeof( local )) != 0 ) {
  1002. printf( "Failed to bind on socket: %s\n", strerror( errno ));
  1003. return errno;
  1004. }
  1005. if( ioctl( sd, SIOCGIFADDR, &if_request ) != 0 ) {
  1006. printf
  1007. ( "Failed to get interface address (ioctl) on socket: %s\n",
  1008. strerror( errno ));
  1009. return errno;
  1010. }
  1011. memcpy
  1012. ( &l4_local_address,
  1013. &(( struct sockaddr_in *)&if_request.ifr_addr)->sin_addr,
  1014. sizeof( l4_local_address ));
  1015. }
  1016. mrp_monitor();
  1017. #ifdef DOMAIN_QUERY
  1018. /*
  1019. * should use mrp_get_domain() above but this is a simplification
  1020. */
  1021. #endif
  1022. domain_a_valid = 1;
  1023. class_a_id = MSRP_SR_CLASS_A;
  1024. a_priority = MSRP_SR_CLASS_A_PRIO;
  1025. a_vid = 2;
  1026. printf("detected domain Class A PRIO=%d VID=%04x...\n", a_priority,
  1027. a_vid);
  1028. #define PKT_SZ 100
  1029. mrp_register_domain(&class_a_id, &a_priority, &a_vid);
  1030. mrp_join_vlan();
  1031. if( transport == 2 ) {
  1032. igb_set_class_bandwidth
  1033. (&igb_dev, 125000/L2_PACKET_IPG, 0, PKT_SZ - 22, 0);
  1034. } else {
  1035. igb_set_class_bandwidth
  1036. (&igb_dev, 1, 0,
  1037. sizeof(*l4_headers)+L4_SAMPLES_PER_FRAME*CHANNELS*2, 0);
  1038. }
  1039. memset(STREAM_ID, 0, sizeof(STREAM_ID));
  1040. memcpy(STREAM_ID, STATION_ADDR, sizeof(STATION_ADDR));
  1041. if( transport == 2 ) {
  1042. packet_size = PKT_SZ;
  1043. } else {
  1044. packet_size = 18 + sizeof(*l4_headers) +
  1045. (L4_SAMPLES_PER_FRAME * CHANNELS * L4_SAMPLE_SIZE );
  1046. }
  1047. a_packet.dmatime = a_packet.attime = a_packet.flags = 0;
  1048. a_packet.map.paddr = a_page.dma_paddr;
  1049. a_packet.map.mmap_size = a_page.mmap_size;
  1050. a_packet.offset = 0;
  1051. a_packet.vaddr = a_page.dma_vaddr + a_packet.offset;
  1052. a_packet.len = packet_size;
  1053. free_packets = NULL;
  1054. seqnum = 0;
  1055. rtp_timestamp = 0; /* Should be random start */
  1056. /* divide the dma page into buffers for packets */
  1057. for (i = 1; i < ((a_page.mmap_size) / packet_size); i++) {
  1058. tmp_packet = malloc(sizeof(struct igb_packet));
  1059. if (NULL == tmp_packet) {
  1060. printf("failed to allocate igb_packet memory!\n");
  1061. return (errno);
  1062. }
  1063. *tmp_packet = a_packet;
  1064. tmp_packet->offset = (i * packet_size);
  1065. tmp_packet->vaddr += tmp_packet->offset;
  1066. tmp_packet->next = free_packets;
  1067. memset(tmp_packet->vaddr, 0, packet_size); /* MAC header at least */
  1068. memcpy(tmp_packet->vaddr, dest_addr, sizeof(dest_addr));
  1069. memcpy(tmp_packet->vaddr + 6, STATION_ADDR,
  1070. sizeof(STATION_ADDR));
  1071. /* Q-tag */
  1072. ((char *)tmp_packet->vaddr)[12] = 0x81;
  1073. ((char *)tmp_packet->vaddr)[13] = 0x00;
  1074. ((char *)tmp_packet->vaddr)[14] =
  1075. ((a_priority << 13 | a_vid)) >> 8;
  1076. ((char *)tmp_packet->vaddr)[15] =
  1077. ((a_priority << 13 | a_vid)) & 0xFF;
  1078. if( transport == 2 ) {
  1079. ((char *)tmp_packet->vaddr)[16] = 0x22; /* 1722 eth type */
  1080. ((char *)tmp_packet->vaddr)[17] = 0xF0;
  1081. } else {
  1082. ((char *)tmp_packet->vaddr)[16] = 0x08; /* IP eth type */
  1083. ((char *)tmp_packet->vaddr)[17] = 0x00;
  1084. }
  1085. if( transport == 2 ) {
  1086. /* 1722 header update + payload */
  1087. l2_header0 =
  1088. (seventeen22_header *) (((char *)tmp_packet->vaddr) + 18);
  1089. l2_header0->cd_indicator = 0;
  1090. l2_header0->subtype = 0;
  1091. l2_header0->sid_valid = 1;
  1092. l2_header0->version = 0;
  1093. l2_header0->reset = 0;
  1094. l2_header0->reserved0 = 0;
  1095. l2_header0->gateway_valid = 0;
  1096. l2_header0->reserved1 = 0;
  1097. l2_header0->timestamp_uncertain = 0;
  1098. memset(&(l2_header0->stream_id), 0, sizeof(l2_header0->stream_id));
  1099. memcpy(&(l2_header0->stream_id), STATION_ADDR,
  1100. sizeof(STATION_ADDR));
  1101. l2_header0->length = htons(32);
  1102. l2_header1 = (six1883_header *) (l2_header0 + 1);
  1103. l2_header1->format_tag = 1;
  1104. l2_header1->packet_channel = 0x1F;
  1105. l2_header1->packet_tcode = 0xA;
  1106. l2_header1->app_control = 0x0;
  1107. l2_header1->reserved0 = 0;
  1108. l2_header1->source_id = 0x3F;
  1109. l2_header1->data_block_size = 1;
  1110. l2_header1->fraction_number = 0;
  1111. l2_header1->quadlet_padding_count = 0;
  1112. l2_header1->source_packet_header = 0;
  1113. l2_header1->reserved1 = 0;
  1114. l2_header1->eoh = 0x2;
  1115. l2_header1->format_id = 0x10;
  1116. l2_header1->format_dependent_field = 0x02;
  1117. l2_header1->syt = 0xFFFF;
  1118. tmp_packet->len =
  1119. 18 + sizeof(seventeen22_header) + sizeof(six1883_header) +
  1120. (L2_SAMPLES_PER_FRAME * CHANNELS * sizeof(six1883_sample));
  1121. } else {
  1122. pseudo_hdr.source = l4_local_address;
  1123. memcpy
  1124. ( &pseudo_hdr.dest, L3_DEST_ADDR, sizeof( pseudo_hdr.dest ));
  1125. pseudo_hdr.zero = 0;
  1126. pseudo_hdr.protocol = 0x11;
  1127. pseudo_hdr.length = htons(packet_size-18-20);
  1128. l4_headers =
  1129. (IP_RTP_Header *) (((char *)tmp_packet->vaddr) + 18);
  1130. l4_headers->version_length = 0x45;
  1131. l4_headers->DSCP_ECN = 0x20;
  1132. l4_headers->ip_length = htons(packet_size-18);
  1133. l4_headers->id = 0;
  1134. l4_headers->fragmentation = 0;
  1135. l4_headers->ttl = 64;
  1136. l4_headers->protocol = 0x11;
  1137. l4_headers->hdr_cksum = 0;
  1138. l4_headers->src = l4_local_address;
  1139. memcpy
  1140. ( &l4_headers->dest, L3_DEST_ADDR, sizeof( l4_headers->dest ));
  1141. {
  1142. struct iovec iv0;
  1143. iv0.iov_base = l4_headers;
  1144. iv0.iov_len = 20;
  1145. l4_headers->hdr_cksum =
  1146. inet_checksum_sg( &iv0, 1 );
  1147. }
  1148. l4_headers->source_port = htons( L3_PORT );
  1149. l4_headers->dest_port = htons( L3_PORT );;
  1150. l4_headers->udp_length = htons(packet_size-18-20);
  1151. l4_headers->version_cc = 2;
  1152. l4_headers->mark_payload = L16_PAYLOAD_TYPE;
  1153. l4_headers->sequence = 0;
  1154. l4_headers->timestamp = 0;
  1155. l4_headers->ssrc = 0;
  1156. l4_headers->tag[0] = 0xBE;
  1157. l4_headers->tag[1] = 0xDE;
  1158. l4_headers->total_length = htons(2);
  1159. l4_headers->tag_length = (6 << 4) | ID_B_HDR_EXT_ID;
  1160. tmp_packet->len =
  1161. 18 + sizeof(*l4_headers) +
  1162. (L4_SAMPLES_PER_FRAME * CHANNELS * L4_SAMPLE_SIZE );
  1163. }
  1164. free_packets = tmp_packet;
  1165. }
  1166. /*
  1167. * subtract 16 bytes for the MAC header/Q-tag - pktsz is limited to the
  1168. * data payload of the ethernet frame .
  1169. *
  1170. * IPG is scaled to the Class (A) observation interval of packets per 125 usec
  1171. */
  1172. fprintf(stderr, "advertising stream ...\n");
  1173. if( transport == 2 ) {
  1174. mrp_advertise_stream
  1175. (STREAM_ID, dest_addr, a_vid, PKT_SZ - 16, L2_PACKET_IPG / 125000,
  1176. a_priority, 3900);
  1177. } else {
  1178. /* 1 is the wrong number for frame rate, but fractional values not
  1179. allowed, not sure the significance of the value 6, but using it
  1180. consistently */
  1181. mrp_advertise_stream
  1182. (STREAM_ID, dest_addr, a_vid,
  1183. sizeof(*l4_headers)+L4_SAMPLES_PER_FRAME*CHANNELS*2 + 6, 1,
  1184. a_priority, 3900);
  1185. }
  1186. fprintf(stderr, "awaiting a listener ...\n");
  1187. //mrp_await_listener(STREAM_ID);
  1188. listeners = 1;
  1189. printf("got a listener ...\n");
  1190. halt_tx = 0;
  1191. gptpinit();
  1192. gptpscaling(&td);
  1193. if( igb_get_wallclock( &igb_dev, &now_local, NULL ) != 0 ) {
  1194. fprintf( stderr, "Failed to get wallclock time\n" );
  1195. return -1;
  1196. }
  1197. update_8021as = td.local_time - td.ml_phoffset;
  1198. delta_local = (unsigned)(now_local - td.local_time);
  1199. delta_8021as = (unsigned)(td.ml_freqoffset * delta_local);
  1200. now_8021as = update_8021as + delta_8021as;
  1201. last_time = now_local + XMIT_DELAY;
  1202. time_stamp = now_8021as + RENDER_DELAY;
  1203. rc = nice(-20);
  1204. while (listeners && !halt_tx) {
  1205. tmp_packet = free_packets;
  1206. if (NULL == tmp_packet)
  1207. goto cleanup;
  1208. free_packets = tmp_packet->next;
  1209. if( transport == 2 ) {
  1210. uint32_t timestamp_l;
  1211. get_samples( L2_SAMPLES_PER_FRAME, sample_buffer );
  1212. l2_header0 =
  1213. (seventeen22_header *) (((char *)tmp_packet->vaddr) + 18);
  1214. l2_header1 = (six1883_header *) (l2_header0 + 1);
  1215. /* unfortuntely unless this thread is at rtprio
  1216. * you get pre-empted between fetching the time
  1217. * and programming the packet and get a late packet
  1218. */
  1219. tmp_packet->attime = last_time + L2_PACKET_IPG;
  1220. last_time += L2_PACKET_IPG;
  1221. l2_header0->seq_number = seqnum++;
  1222. if (seqnum % 4 == 0)
  1223. l2_header0->timestamp_valid = 0;
  1224. else
  1225. l2_header0->timestamp_valid = 1;
  1226. timestamp_l = time_stamp;
  1227. l2_header0->timestamp = htonl(timestamp_l);
  1228. time_stamp += L2_PACKET_IPG;
  1229. l2_header1->data_block_continuity = total_samples;
  1230. total_samples += L2_SAMPLES_PER_FRAME*CHANNELS;
  1231. sample =
  1232. (six1883_sample *) (((char *)tmp_packet->vaddr) +
  1233. (18 + sizeof(seventeen22_header) +
  1234. sizeof(six1883_header)));
  1235. for (i = 0; i < L2_SAMPLES_PER_FRAME * CHANNELS; ++i) {
  1236. uint32_t tmp = htonl(sample_buffer[i]);
  1237. sample[i].label = 0x40;
  1238. memcpy(&(sample[i].value), &(tmp),
  1239. sizeof(sample[i].value));
  1240. }
  1241. } else {
  1242. uint16_t *l16_sample;
  1243. uint8_t *tmp;
  1244. get_samples( L4_SAMPLES_PER_FRAME, sample_buffer );
  1245. l4_headers =
  1246. (IP_RTP_Header *) (((char *)tmp_packet->vaddr) + 18);
  1247. l4_headers->sequence = seqnum++;
  1248. l4_headers->timestamp = rtp_timestamp;
  1249. tmp_packet->attime = last_time + L4_PACKET_IPG;
  1250. last_time += L4_PACKET_IPG;
  1251. l4_headers->nanoseconds = time_stamp/1000000000;
  1252. tmp = (uint8_t *) &l4_headers->nanoseconds;
  1253. l4_headers->seconds[0] = tmp[2];
  1254. l4_headers->seconds[1] = tmp[1];
  1255. l4_headers->seconds[2] = tmp[0];
  1256. {
  1257. uint64_t tmp;
  1258. tmp = time_stamp % 1000000000;
  1259. tmp *= RTP_SUBNS_SCALE_NUM;
  1260. tmp /= RTP_SUBNS_SCALE_DEN;
  1261. l4_headers->nanoseconds = (uint32_t) tmp;
  1262. }
  1263. l4_headers->nanoseconds = htons(l4_headers->nanoseconds);
  1264. time_stamp += L4_PACKET_IPG;
  1265. l16_sample = (uint16_t *) (l4_headers+1);
  1266. for (i = 0; i < L4_SAMPLES_PER_FRAME * CHANNELS; ++i) {
  1267. uint16_t tmp = sample_buffer[i]/65536;
  1268. l16_sample[i] = htons(tmp);
  1269. }
  1270. l4_headers->cksum = 0;
  1271. {
  1272. struct iovec iv[2];
  1273. iv[0].iov_base = &pseudo_hdr;
  1274. iv[0].iov_len = sizeof(pseudo_hdr);
  1275. iv[1].iov_base = ((uint8_t *)l4_headers) + 20;
  1276. iv[1].iov_len = packet_size-18-20;
  1277. l4_headers->cksum =
  1278. inet_checksum_sg( iv, 2 );
  1279. }
  1280. }
  1281. err = igb_xmit(&igb_dev, 0, tmp_packet);
  1282. if (!err) {
  1283. continue;
  1284. }
  1285. if (ENOSPC == err) {
  1286. /* put back for now */
  1287. tmp_packet->next = free_packets;
  1288. free_packets = tmp_packet;
  1289. }
  1290. cleanup:
  1291. igb_clean(&igb_dev, &cleaned_packets);
  1292. i = 0;
  1293. while (cleaned_packets) {
  1294. i++;
  1295. tmp_packet = cleaned_packets;
  1296. cleaned_packets = cleaned_packets->next;
  1297. tmp_packet->next = free_packets;
  1298. free_packets = tmp_packet;
  1299. }
  1300. }
  1301. rc = nice(0);
  1302. if (halt_tx == 0)
  1303. printf("listener left ...\n");
  1304. halt_tx = 1;
  1305. if( transport == 2 ) {
  1306. mrp_unadvertise_stream
  1307. (STREAM_ID, dest_addr, a_vid, PKT_SZ - 16, L2_PACKET_IPG / 125000,
  1308. a_priority, 3900);
  1309. } else {
  1310. mrp_unadvertise_stream
  1311. (STREAM_ID, dest_addr, a_vid,
  1312. sizeof(*l4_headers)+L4_SAMPLES_PER_FRAME*CHANNELS*2 + 6, 1,
  1313. a_priority, 3900);
  1314. }
  1315. igb_set_class_bandwidth(&igb_dev, 0, 0, 0, 0); /* disable Qav */
  1316. rc = mrp_disconnect();
  1317. igb_dma_free_page(&igb_dev, &a_page);
  1318. err = igb_detach(&igb_dev);
  1319. pthread_exit(NULL);
  1320. return (0);
  1321. }