1 /******************************************************************************
3 Copyright (c) 2012, Intel Corporation
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
9 1. Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 3. Neither the name of the Intel Corporation nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
32 ******************************************************************************/
42 #include <sys/ioctl.h>
44 #include <sys/resource.h>
48 #include <sys/socket.h>
50 #include <netpacket/packet.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <net/ethernet.h>
73 int32_t ml_freqoffset;
74 int32_t ls_freqoffset;
79 #define SHM_SIZE 4*8 + sizeof(pthread_mutex_t) /* 3 - 64 bit and 2 - 32 bits */
80 #define SHM_NAME "/ptp"
82 #define MAX_SAMPLE_VALUE ((1U << ((sizeof(int32_t)*8)-1))-1)
84 #define SRC_CHANNELS (2)
85 #define SAMPLES_PER_SECOND (48000)
86 #define FREQUENCY (480)
87 #define SAMPLES_PER_CYCLE (SAMPLES_PER_SECOND/FREQUENCY)
91 #define ETH_TYPE 0x22F0
93 #define CD_SUBTYPE 0x02 /* for simple audio format */
94 #define SV_VER_MR_RS_GV_TV 0x81
96 #define SAMPLE_FORMAT_NON_INTR_FLOAT 0x02
97 #define NOMINAL_SAMPLE_RATE 0x09
98 #define LINEAR_SAMPLE_MSB 0x20
99 unsigned char GATEWAY_INFO[] =
100 { SAMPLE_FORMAT_NON_INTR_FLOAT, 0, NOMINAL_SAMPLE_RATE, LINEAR_SAMPLE_MSB };
102 #define SAMPLE_SIZE 4 /* 4 bytes */
103 #define SAMPLES_PER_FRAME 6
105 #define PAYLOAD_SIZE SAMPLE_SIZE*SAMPLES_PER_FRAME*CHANNELS /* 6*4 * 2 channels = 48 bytes */
107 #define IGB_BIND_NAMESZ 24
109 #define XMIT_DELAY (200000000) /* us */
110 #define RENDER_DELAY (XMIT_DELAY+2000000) /* us */
111 typedef enum { false = 0, true = 1 } bool;
112 typedef struct __attribute__ ((packed)) {
114 uint64_t cd_indicator:1;
115 uint64_t timestamp_valid:1;
116 uint64_t gateway_valid:1;
117 uint64_t reserved0:1;
120 uint64_t sid_valid:1;
121 uint64_t seq_number:8;
122 uint64_t timestamp_uncertain:1;
123 uint64_t reserved1:7;
125 uint64_t timestamp:32;
126 uint64_t gateway_info:32;
128 } seventeen22_header;
130 /* 61883 CIP with SYT Field */
132 uint16_t packet_channel:6;
133 uint16_t format_tag:2;
134 uint16_t app_control:4;
135 uint16_t packet_tcode:4;
136 uint16_t source_id:6;
137 uint16_t reserved0:2;
138 uint16_t data_block_size:8;
139 uint16_t reserved1:2;
140 uint16_t source_packet_header:1;
141 uint16_t quadlet_padding_count:3;
142 uint16_t fraction_number:2;
143 uint16_t data_block_continuity:8;
144 uint16_t format_id:6;
146 uint16_t format_dependent_field:8;
155 /* global variables */
156 int control_socket = -1;
158 volatile int halt_tx = 0;
159 volatile int listeners = 0;
160 volatile int mrp_okay;
161 volatile int mrp_error = 0;;
162 volatile int domain_a_valid = 0;
163 int domain_class_a_id;
164 int domain_class_a_priority;
165 int domain_class_a_vid;
166 volatile int domain_b_valid = 0;
167 int domain_class_b_id;
168 int domain_class_b_priority;
169 int domain_class_b_vid;
171 #define VERSION_STR "1.0"
172 static const char *version_str = "simple_talker v" VERSION_STR "\n"
173 "Copyright (c) 2012, Intel Corporation\n";
175 #define MRPD_PORT_DEFAULT 7500
176 static inline uint64_t ST_rdtsc(void)
180 asm volatile ("rdtsc":"=a" (c), "=d"(d));
187 static int shm_fd = -1;
188 static char *memory_offset_buffer = NULL;
191 shm_fd = shm_open(SHM_NAME, O_RDWR, 0);
193 perror("shm_open()");
196 memory_offset_buffer =
197 (char *)mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
199 if (memory_offset_buffer == (char *)-1) {
201 memory_offset_buffer = NULL;
202 shm_unlink(SHM_NAME);
208 void gptpdeinit(void)
210 if (memory_offset_buffer != NULL) {
211 munmap(memory_offset_buffer, SHM_SIZE);
218 int gptpscaling(gPtpTimeData * td)
220 pthread_mutex_lock((pthread_mutex_t *) memory_offset_buffer);
221 memcpy(td, memory_offset_buffer + sizeof(pthread_mutex_t), sizeof(*td));
222 pthread_mutex_unlock((pthread_mutex_t *) memory_offset_buffer);
224 fprintf(stderr, "ml_phoffset = %lld, ls_phoffset = %lld\n",
225 td->ml_phoffset, td->ls_phoffset);
226 fprintf(stderr, "ml_freqffset = %d, ls_freqoffset = %d\n",
227 td->ml_freqoffset, td->ls_freqoffset);
232 void gensine32(int32_t * buf, unsigned count)
234 long double interval = (2 * ((long double)M_PI)) / count;
236 for (i = 0; i < count; ++i) {
238 (int32_t) (MAX_SAMPLE_VALUE * sinl(i * interval) * GAIN);
242 int get_samples(unsigned count, int32_t * buffer)
245 static int32_t samples_onechannel[100];
246 static unsigned index = 0;
249 gensine32(samples_onechannel, 100);
255 for (i = 0; i < SRC_CHANNELS; ++i) {
256 *(buffer++) = samples_onechannel[index];
258 index = (index + 1) % 100;
265 int mrp_join_listener(uint8_t * streamid);
266 int send_mrp_msg(char *notify_data, int notify_len)
268 struct sockaddr_in addr;
270 memset(&addr, 0, sizeof(addr));
271 addr.sin_family = AF_INET;
272 addr.sin_port = htons(MRPD_PORT_DEFAULT);
273 inet_aton("127.0.0.1", &addr.sin_addr);
274 addr_len = sizeof(addr);
275 if (control_socket != -1)
277 (control_socket, notify_data, notify_len, 0,
278 (struct sockaddr *)&addr, addr_len));
286 struct sockaddr_in addr;
288 sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
291 memset(&addr, 0, sizeof(addr));
292 addr.sin_family = AF_INET;
293 addr.sin_port = htons(MRPD_PORT_DEFAULT);
294 inet_aton("127.0.0.1", &addr.sin_addr);
295 memset(&addr, 0, sizeof(addr));
296 control_socket = sock_fd;
298 out: if (sock_fd != -1)
311 memset(msgbuf, 0, 64);
312 sprintf(msgbuf, "BYE");
314 rc = send_mrp_msg(msgbuf, 1500);
316 /* rc = recv_mrp_okay(); */
323 while ((mrp_okay == 0) && (mrp_error == 0))
328 int mrp_register_domain(int *class_id, int *priority, u_int16_t * vid)
335 memset(msgbuf, 0, 64);
336 sprintf(msgbuf, "S+D:C=%d,P=%d,V=%04x", *class_id, *priority, *vid);
338 rc = send_mrp_msg(msgbuf, 1500);
340 /* rc = recv_mrp_okay(); */
345 int mrp_get_domain(int *class_a_id, int *a_priority, u_int16_t * a_vid,
346 int *class_b_id, int *b_priority, u_int16_t * b_vid)
350 /* we may not get a notification if we are joining late,
351 * so query for what is already there ...
356 memset(msgbuf, 0, 64);
357 sprintf(msgbuf, "S??");
358 send_mrp_msg(msgbuf, 64);
360 while (!halt_tx && (domain_a_valid == 0) && (domain_b_valid == 0))
368 if (domain_a_valid) {
369 *class_a_id = domain_class_a_id;
370 *a_priority = domain_class_a_priority;
371 *a_vid = domain_class_a_vid;
373 if (domain_b_valid) {
374 *class_b_id = domain_class_b_id;
375 *b_priority = domain_class_b_priority;
376 *b_vid = domain_class_b_vid;
380 unsigned char monitor_stream_id[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
382 int mrp_await_listener(unsigned char *streamid)
385 memcpy(monitor_stream_id, streamid, sizeof(monitor_stream_id));
389 memset(msgbuf, 0, 64);
390 sprintf(msgbuf, "S??");
391 send_mrp_msg(msgbuf, 64);
394 /* either already there ... or need to wait ... */
395 while (!halt_tx && (listeners == 0))
400 int process_mrp_msg(char *buf, int buflen)
404 * 1st character indicates application
405 * [MVS] - MAC, VLAN or STREAM
408 unsigned int priority;
411 unsigned int substate;
412 unsigned char recovered_streamid[8];
414 next_line:if (k >= buflen)
418 printf("%s from mrpd\n", buf);
427 printf("%s unhandled from mrpd\n", buf);
430 /* unhandled for now */
434 /* parse a listener attribute - see if it matches our monitor_stream_id */
436 while (buf[i] != 'D')
438 i += 2; /* skip the ':' */
439 sscanf(&(buf[i]), "%d", &substate);
440 while (buf[i] != 'S')
442 i += 2; /* skip the ':' */
443 for (j = 0; j < 8; j++) {
444 sscanf(&(buf[i + 2 * j]), "%02x", &id);
445 recovered_streamid[j] = (unsigned char)id;
447 ("FOUND STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ",
448 recovered_streamid[0], recovered_streamid[1],
449 recovered_streamid[2], recovered_streamid[3],
450 recovered_streamid[4], recovered_streamid[5],
451 recovered_streamid[6], recovered_streamid[7]);
454 printf("with state ignore\n");
457 printf("with state askfailed\n");
460 printf("with state ready\n");
463 printf("with state readyfail\n");
466 printf("with state UNKNOWN (%d)\n", substate);
469 if (substate > MSRP_LISTENER_ASKFAILED) {
471 (recovered_streamid, monitor_stream_id,
472 sizeof(recovered_streamid)) == 0) {
474 printf("added listener\n");
479 /* try to find a newline ... */
480 while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
493 /* save the domain attribute */
494 sscanf(&(buf[i]), "%d", &id);
495 while (buf[i] != 'P')
497 i += 2; /* skip the ':' */
498 sscanf(&(buf[i]), "%d", &priority);
499 while (buf[i] != 'V')
501 i += 2; /* skip the ':' */
502 sscanf(&(buf[i]), "%x", &vid);
504 domain_class_a_id = id;
505 domain_class_a_priority = priority;
506 domain_class_a_vid = vid;
509 domain_class_b_id = id;
510 domain_class_b_priority = priority;
511 domain_class_b_vid = vid;
514 while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
516 if ((i == buflen) || (buf[i] == '\0'))
524 /* as simple_talker we don't care about other talkers */
526 while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
538 /* handle the leave/join events */
539 switch (buf[k + 4]) {
542 while (buf[i] != 'D')
544 i += 2; /* skip the ':' */
545 sscanf(&(buf[i]), "%d", &substate);
546 while (buf[i] != 'S')
548 i += 2; /* skip the ':' */
549 for (j = 0; j < 8; j++) {
550 sscanf(&(buf[i + 2 * j]), "%02x", &id);
551 recovered_streamid[j] = (unsigned char)id;
553 ("EVENT on STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ",
554 recovered_streamid[0], recovered_streamid[1],
555 recovered_streamid[2], recovered_streamid[3],
556 recovered_streamid[4], recovered_streamid[5],
557 recovered_streamid[6], recovered_streamid[7]);
560 printf("with state ignore\n");
563 printf("with state askfailed\n");
566 printf("with state ready\n");
569 printf("with state readyfail\n");
572 printf("with state UNKNOWN (%d)\n", substate);
575 switch (buf[k + 1]) {
577 printf("got a leave indication\n");
579 (recovered_streamid, monitor_stream_id,
580 sizeof(recovered_streamid)) == 0) {
582 printf("listener left\n");
587 printf("got a new/join indication\n");
588 if (substate > MSRP_LISTENER_ASKFAILED) {
592 sizeof(recovered_streamid)) == 0)
598 /* only care about listeners ... */
610 void *mrp_monitor_thread(void *arg)
613 struct sockaddr_in client_addr;
624 msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
628 fds.fd = control_socket;
631 rc = poll(&fds, 1, 100);
638 if ((fds.revents & POLLIN) == 0) {
642 memset(&msg, 0, sizeof(msg));
643 memset(&client_addr, 0, sizeof(client_addr));
644 memset(msgbuf, 0, MAX_MRPD_CMDSZ);
645 iov.iov_len = MAX_MRPD_CMDSZ;
646 iov.iov_base = msgbuf;
647 msg.msg_name = &client_addr;
648 msg.msg_namelen = sizeof(client_addr);
651 bytes = recvmsg(control_socket, &msg, 0);
654 process_mrp_msg(msgbuf, bytes);
660 pthread_t monitor_thread;
661 pthread_attr_t monitor_attr;
664 pthread_attr_init(&monitor_attr);
665 pthread_create(&monitor_thread, NULL, mrp_monitor_thread, NULL);
669 int mrp_join_listener(uint8_t * streamid)
673 msgbuf = malloc(1500);
676 memset(msgbuf, 0, 1500);
677 sprintf(msgbuf, "S+L:S=%02X%02X%02X%02X%02X%02X%02X%02X"
678 ",D=2", streamid[0], streamid[1], streamid[2], streamid[3],
679 streamid[4], streamid[5], streamid[6], streamid[7]);
681 rc = send_mrp_msg(msgbuf, 1500);
683 /* rc = recv_mrp_okay(); */
689 mrp_advertise_stream(uint8_t * streamid,
692 int pktsz, int interval, int priority, int latency)
696 msgbuf = malloc(1500);
699 memset(msgbuf, 0, 1500);
700 sprintf(msgbuf, "S++:S=%02X%02X%02X%02X%02X%02X%02X%02X"
701 ",A=%02X%02X%02X%02X%02X%02X"
706 ",L=%d", streamid[0], streamid[1], streamid[2],
707 streamid[3], streamid[4], streamid[5], streamid[6],
708 streamid[7], destaddr[0], destaddr[1], destaddr[2],
709 destaddr[3], destaddr[4], destaddr[5], vlan, pktsz,
710 interval, priority << 5, latency);
712 rc = send_mrp_msg(msgbuf, 1500);
714 /* rc = recv_mrp_okay(); */
720 mrp_unadvertise_stream(uint8_t * streamid,
723 int pktsz, int interval, int priority, int latency)
727 msgbuf = malloc(1500);
730 memset(msgbuf, 0, 1500);
731 sprintf(msgbuf, "S--:S=%02X%02X%02X%02X%02X%02X%02X%02X"
732 ",A=%02X%02X%02X%02X%02X%02X"
737 ",L=%d", streamid[0], streamid[1], streamid[2],
738 streamid[3], streamid[4], streamid[5], streamid[6],
739 streamid[7], destaddr[0], destaddr[1], destaddr[2],
740 destaddr[3], destaddr[4], destaddr[5], vlan, pktsz,
741 interval, priority << 5, latency);
743 rc = send_mrp_msg(msgbuf, 1500);
745 /* rc = recv_mrp_okay(); */
750 void sigint_handler(int signum)
752 printf("got SIGINT\n");
758 struct pci_access *pacc;
761 char devpath[IGB_BIND_NAMESZ];
762 memset(&igb_dev, 0, sizeof(device_t));
766 for (dev = pacc->devices; dev; dev = dev->next) {
768 PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS);
769 igb_dev.pci_vendor_id = dev->vendor_id;
770 igb_dev.pci_device_id = dev->device_id;
771 igb_dev.domain = dev->domain;
772 igb_dev.bus = dev->bus;
773 igb_dev.dev = dev->dev;
774 igb_dev.func = dev->func;
775 snprintf(devpath, IGB_BIND_NAMESZ, "%04x:%02x:%02x.%d",
776 dev->domain, dev->bus, dev->dev, dev->func);
777 err = igb_probe(&igb_dev);
781 printf("attaching to %s\n", devpath);
782 err = igb_attach(devpath, &igb_dev);
784 printf("attach failed! (%s)\n", strerror(errno));
791 out: pci_cleanup(pacc);
795 unsigned char STATION_ADDR[] = { 0, 0, 0, 0, 0, 0 };
796 unsigned char STREAM_ID[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
798 /* IEEE 1722 reserved address */
799 unsigned char DEST_ADDR[] = { 0x91, 0xE0, 0xF0, 0x00, 0x0e, 0x80 };
801 int get_mac_address(char *interface)
803 struct ifreq if_request;
806 lsock = socket(PF_PACKET, SOCK_RAW, htons(0x800));
809 memset(&if_request, 0, sizeof(if_request));
810 strncpy(if_request.ifr_name, interface, sizeof(if_request.ifr_name));
811 rc = ioctl(lsock, SIOCGIFHWADDR, &if_request);
816 memcpy(STATION_ADDR, if_request.ifr_hwaddr.sa_data,
817 sizeof(STATION_ADDR));
822 static void usage(void)
825 "usage: simple_talker [-h] -i interface-name"
828 " -h show this message\n"
829 " -i specify interface for AVB connection\n"
830 "\n" "%s" "\n", version_str);
834 #define PACKET_IPG (125000) /* (1) packet every 125 usec */
836 int main(int argc, char *argv[])
840 struct igb_dma_alloc a_page;
841 struct igb_packet a_packet;
842 struct igb_packet *tmp_packet;
843 struct igb_packet *cleaned_packets;
844 struct igb_packet *free_packets;
848 char *interface = NULL;
859 unsigned total_samples = 0;
861 int32_t sample_buffer[SAMPLES_PER_FRAME * SRC_CHANNELS];
862 seventeen22_header *header0;
863 six1883_header *header1;
864 six1883_sample *sample;
865 uint64_t now_local, now_8021as;
866 uint64_t update_8021as;
867 unsigned delta_8021as, delta_local;
868 long double ml_ratio;
871 c = getopt(argc, argv, "hi:");
881 ("only one interface per daemon is supported\n");
884 interface = strdup(optarg);
890 if (NULL == interface) {
895 printf("socket creation failed\n");
900 printf("connect failed (%s) - are you running as root?\n",
904 err = igb_init(&igb_dev);
906 printf("init failed (%s) - is the driver really loaded?\n",
910 err = igb_dma_malloc_page(&igb_dev, &a_page);
912 printf("malloc failed (%s) - out of memory?\n",
916 signal(SIGINT, sigint_handler);
917 rc = get_mac_address(interface);
919 printf("failed to open interface\n");
926 * should use mrp_get_domain() above but this is a simplification
930 class_a_id = MSRP_SR_CLASS_A;
931 a_priority = MSRP_SR_CLASS_A_PRIO;
933 printf("detected domain Class A PRIO=%d VID=%04x...\n", a_priority,
938 mrp_register_domain(&class_a_id, &a_priority, &a_vid);
939 igb_set_class_bandwidth(&igb_dev, PACKET_IPG / 125000, 0, PKT_SZ - 22,
942 memset(STREAM_ID, 0, sizeof(STREAM_ID));
943 memcpy(STREAM_ID, STATION_ADDR, sizeof(STATION_ADDR));
945 a_packet.dmatime = a_packet.attime = a_packet.flags = 0;
946 a_packet.map.paddr = a_page.dma_paddr;
947 a_packet.map.mmap_size = a_page.mmap_size;
949 a_packet.vaddr = a_page.dma_vaddr + a_packet.offset;
950 a_packet.len = PKT_SZ;
954 /* divide the dma page into buffers for packets */
955 for (i = 1; i < ((a_page.mmap_size) / PKT_SZ); i++) {
956 tmp_packet = malloc(sizeof(struct igb_packet));
957 if (NULL == tmp_packet) {
958 printf("failed to allocate igb_packet memory!\n");
961 *tmp_packet = a_packet;
962 tmp_packet->offset = (i * PKT_SZ);
963 tmp_packet->vaddr += tmp_packet->offset;
964 tmp_packet->next = free_packets;
965 memset(tmp_packet->vaddr, 0, PKT_SZ); /* MAC header at least */
966 memcpy(tmp_packet->vaddr, DEST_ADDR, sizeof(DEST_ADDR));
967 memcpy(tmp_packet->vaddr + 6, STATION_ADDR,
968 sizeof(STATION_ADDR));
971 ((char *)tmp_packet->vaddr)[12] = 0x81;
972 ((char *)tmp_packet->vaddr)[13] = 0x00;
973 ((char *)tmp_packet->vaddr)[14] =
974 ((a_priority << 13 | a_vid)) >> 8;
975 ((char *)tmp_packet->vaddr)[15] =
976 ((a_priority << 13 | a_vid)) & 0xFF;
977 ((char *)tmp_packet->vaddr)[16] = 0x22; /* 1722 eth type */
978 ((char *)tmp_packet->vaddr)[17] = 0xF0;
980 /* 1722 header update + payload */
982 (seventeen22_header *) (((char *)tmp_packet->vaddr) + 18);
983 header0->cd_indicator = 0;
984 header0->subtype = 0;
985 header0->sid_valid = 1;
986 header0->version = 0;
988 header0->reserved0 = 0;
989 header0->gateway_valid = 0;
990 header0->reserved1 = 0;
991 header0->timestamp_uncertain = 0;
992 memset(&(header0->stream_id), 0, sizeof(header0->stream_id));
993 memcpy(&(header0->stream_id), STATION_ADDR,
994 sizeof(STATION_ADDR));
995 header0->length = htons(32);
996 header1 = (six1883_header *) (header0 + 1);
997 header1->format_tag = 1;
998 header1->packet_channel = 0x1F;
999 header1->packet_tcode = 0xA;
1000 header1->app_control = 0x0;
1001 header1->reserved0 = 0;
1002 header1->source_id = 0x3F;
1003 header1->data_block_size = 1;
1004 header1->fraction_number = 0;
1005 header1->quadlet_padding_count = 0;
1006 header1->source_packet_header = 0;
1007 header1->reserved1 = 0;
1009 header1->format_id = 0x10;
1010 header1->format_dependent_field = 0x02;
1011 header1->syt = 0xFFFF;
1013 18 + sizeof(seventeen22_header) + sizeof(six1883_header) +
1014 (SAMPLES_PER_FRAME * CHANNELS * sizeof(six1883_sample));
1015 free_packets = tmp_packet;
1019 * subtract 16 bytes for the MAC header/Q-tag - pktsz is limited to the
1020 * data payload of the ethernet frame .
1022 * IPG is scaled to the Class (A) observation interval of packets per 125 usec
1024 fprintf(stderr, "advertising stream ...\n");
1025 mrp_advertise_stream(STREAM_ID, DEST_ADDR, a_vid, PKT_SZ - 16,
1026 PACKET_IPG / 125000, a_priority, 3900);
1027 fprintf(stderr, "awaiting a listener ...\n");
1028 mrp_await_listener(STREAM_ID);
1029 printf("got a listener ...\n");
1035 if( igb_get_wallclock( &igb_dev, &now_local, NULL ) != 0 ) {
1036 fprintf( stderr, "Failed to get wallclock time\n" );
1039 update_8021as = td.local_time - td.ml_phoffset;
1040 delta_local = (unsigned)(now_local - td.local_time);
1041 ml_ratio = -1 * (((long double)td.ml_freqoffset) / 1000000000000) + 1;
1042 delta_8021as = (unsigned)(ml_ratio * delta_local);
1043 now_8021as = update_8021as + delta_8021as;
1045 last_time = now_local + XMIT_DELAY;
1046 time_stamp = now_8021as + RENDER_DELAY;
1050 while (listeners && !halt_tx) {
1051 tmp_packet = free_packets;
1052 if (NULL == tmp_packet)
1055 (seventeen22_header *) (((char *)tmp_packet->vaddr) + 18);
1056 header1 = (six1883_header *) (header0 + 1);
1057 free_packets = tmp_packet->next;
1059 /* unfortuntely unless this thread is at rtprio
1060 * you get pre-empted between fetching the time
1061 * and programming the packet and get a late packet
1063 tmp_packet->attime = last_time + PACKET_IPG;
1064 last_time += PACKET_IPG;
1066 get_samples(SAMPLES_PER_FRAME, sample_buffer);
1067 header0->seq_number = seqnum++;
1068 if (seqnum % 4 == 0)
1069 header0->timestamp_valid = 0;
1072 header0->timestamp_valid = 1;
1074 time_stamp = htonl(time_stamp);
1075 header0->timestamp = time_stamp;
1076 time_stamp = ntohl(time_stamp);
1077 time_stamp += PACKET_IPG;
1078 header1->data_block_continuity = total_samples;
1079 total_samples += SAMPLES_PER_FRAME*CHANNELS;
1081 (six1883_sample *) (((char *)tmp_packet->vaddr) +
1082 (18 + sizeof(seventeen22_header) +
1083 sizeof(six1883_header)));
1085 for (i = 0; i < SAMPLES_PER_FRAME * CHANNELS; ++i) {
1086 uint32_t tmp = htonl(sample_buffer[i]);
1087 sample[i].label = 0x40;
1088 memcpy(&(sample[i].value), &(tmp),
1089 sizeof(sample[i].value));
1092 err = igb_xmit(&igb_dev, 0, tmp_packet);
1098 if (ENOSPC == err) {
1100 /* put back for now */
1101 tmp_packet->next = free_packets;
1102 free_packets = tmp_packet;
1105 cleanup: igb_clean(&igb_dev, &cleaned_packets);
1107 while (cleaned_packets) {
1109 tmp_packet = cleaned_packets;
1110 cleaned_packets = cleaned_packets->next;
1111 tmp_packet->next = free_packets;
1112 free_packets = tmp_packet;
1118 printf("listener left ...\n");
1121 mrp_unadvertise_stream(STREAM_ID, DEST_ADDR, a_vid, PKT_SZ - 16,
1122 PACKET_IPG / 125000, a_priority, 3900);
1124 igb_set_class_bandwidth(&igb_dev, 0, 0, 0, 0); /* disable Qav */
1126 rc = mrp_disconnect();
1128 igb_dma_free_page(&igb_dev, &a_page);
1130 err = igb_detach(&igb_dev);