macosx/nicdrv.c
Go to the documentation of this file.
1 /*
2  * Licensed under the GNU General Public License version 2 with exceptions. See
3  * LICENSE file in the project root for full license information
4  */
5 
34 #include <assert.h>
35 #include <sys/types.h>
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <string.h>
39 
40 #include "ethercattype.h"
41 #include "nicdrv.h"
42 #include "osal.h"
43 
45 enum
46 {
51 };
52 
59 const uint16 priMAC[3] = { 0x0101, 0x0101, 0x0101 };
61 const uint16 secMAC[3] = { 0x0404, 0x0404, 0x0404 };
62 
64 #define RX_PRIM priMAC[1]
65 
66 #define RX_SEC secMAC[1]
67 
68 static char errbuf[PCAP_ERRBUF_SIZE];
69 
70 static void ecx_clear_rxbufstat(int *rxbufstat)
71 {
72  int i;
73  for(i = 0; i < EC_MAXBUF; i++)
74  {
75  rxbufstat[i] = EC_BUF_EMPTY;
76  }
77 }
78 
85 int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary)
86 {
87  int i, rval;
88  pcap_t **psock;
89 
90  rval = 0;
91  if (secondary)
92  {
93  /* secondary port struct available? */
94  if (port->redport)
95  {
96  /* when using secondary socket it is automatically a redundant setup */
97  psock = &(port->redport->sockhandle);
98  *psock = NULL;
99  port->redstate = ECT_RED_DOUBLE;
100  port->redport->stack.sock = &(port->redport->sockhandle);
101  port->redport->stack.txbuf = &(port->txbuf);
102  port->redport->stack.txbuflength = &(port->txbuflength);
103  port->redport->stack.tempbuf = &(port->redport->tempinbuf);
104  port->redport->stack.rxbuf = &(port->redport->rxbuf);
105  port->redport->stack.rxbufstat = &(port->redport->rxbufstat);
106  port->redport->stack.rxsa = &(port->redport->rxsa);
107  ecx_clear_rxbufstat(&(port->redport->rxbufstat[0]));
108  }
109  else
110  {
111  /* fail */
112  return 0;
113  }
114  }
115  else
116  {
117  pthread_mutex_init(&(port->getindex_mutex), NULL);
118  pthread_mutex_init(&(port->tx_mutex), NULL);
119  pthread_mutex_init(&(port->rx_mutex), NULL);
120  port->sockhandle = NULL;
121  port->lastidx = 0;
122  port->redstate = ECT_RED_NONE;
123  port->stack.sock = &(port->sockhandle);
124  port->stack.txbuf = &(port->txbuf);
125  port->stack.txbuflength = &(port->txbuflength);
126  port->stack.tempbuf = &(port->tempinbuf);
127  port->stack.rxbuf = &(port->rxbuf);
128  port->stack.rxbufstat = &(port->rxbufstat);
129  port->stack.rxsa = &(port->rxsa);
130  ecx_clear_rxbufstat(&(port->rxbufstat[0]));
131  psock = &(port->sockhandle);
132  }
133  *psock = pcap_open_live(ifname, 65536, 1, 0, errbuf);
134  if (NULL == *psock)
135  {
136  return 0;
137  }
138  rval = pcap_setdirection(*psock, PCAP_D_IN);
139  if (rval != 0)
140  {
141  return 0;
142  }
143  rval = pcap_setnonblock(*psock, 1, errbuf);
144  if (rval != 0)
145  {
146  return 0;
147  }
148 
149  for (i = 0; i < EC_MAXBUF; i++)
150  {
151  ec_setupheader(&(port->txbuf[i]));
152  port->rxbufstat[i] = EC_BUF_EMPTY;
153  }
154  ec_setupheader(&(port->txbuf2));
155 
156  return 1;
157 }
158 
164 {
165  if (port->sockhandle != NULL)
166  {
167  pthread_mutex_destroy(&(port->getindex_mutex));
168  pthread_mutex_destroy(&(port->tx_mutex));
169  pthread_mutex_destroy(&(port->rx_mutex));
170  pcap_close(port->sockhandle);
171  port->sockhandle = NULL;
172  }
173  if ((port->redport) && (port->redport->sockhandle != NULL))
174  {
175  pcap_close(port->redport->sockhandle);
176  port->redport->sockhandle = NULL;
177  }
178 
179  return 0;
180 }
181 
187 void ec_setupheader(void *p)
188 {
189  ec_etherheadert *bp;
190  bp = p;
191  bp->da0 = htons(0xffff);
192  bp->da1 = htons(0xffff);
193  bp->da2 = htons(0xffff);
194  bp->sa0 = htons(priMAC[0]);
195  bp->sa1 = htons(priMAC[1]);
196  bp->sa2 = htons(priMAC[2]);
197  bp->etype = htons(ETH_P_ECAT);
198 }
199 
205 {
206  int idx;
207  int cnt;
208 
209  pthread_mutex_lock(&(port->getindex_mutex));
210 
211  idx = port->lastidx + 1;
212  /* index can't be larger than buffer array */
213  if (idx >= EC_MAXBUF)
214  {
215  idx = 0;
216  }
217  cnt = 0;
218  /* try to find unused index */
219  while ((port->rxbufstat[idx] != EC_BUF_EMPTY) && (cnt < EC_MAXBUF))
220  {
221  idx++;
222  cnt++;
223  if (idx >= EC_MAXBUF)
224  {
225  idx = 0;
226  }
227  }
228  port->rxbufstat[idx] = EC_BUF_ALLOC;
229  if (port->redstate != ECT_RED_NONE)
230  port->redport->rxbufstat[idx] = EC_BUF_ALLOC;
231  port->lastidx = idx;
232 
233  pthread_mutex_unlock(&(port->getindex_mutex));
234 
235  return idx;
236 }
237 
243 void ecx_setbufstat(ecx_portt *port, int idx, int bufstat)
244 {
245  port->rxbufstat[idx] = bufstat;
246  if (port->redstate != ECT_RED_NONE)
247  port->redport->rxbufstat[idx] = bufstat;
248 }
249 
256 int ecx_outframe(ecx_portt *port, int idx, int stacknumber)
257 {
258  int lp, rval;
259  ec_stackT *stack;
260 
261  if (!stacknumber)
262  {
263  stack = &(port->stack);
264  }
265  else
266  {
267  stack = &(port->redport->stack);
268  }
269  lp = (*stack->txbuflength)[idx];
270  (*stack->rxbufstat)[idx] = EC_BUF_TX;
271  rval = pcap_sendpacket(*stack->sock, (*stack->txbuf)[idx], lp);
272  if (rval == PCAP_ERROR)
273  {
274  (*stack->rxbufstat)[idx] = EC_BUF_EMPTY;
275  }
276 
277  return rval;
278 }
279 
285 int ecx_outframe_red(ecx_portt *port, int idx)
286 {
287  ec_comt *datagramP;
288  ec_etherheadert *ehp;
289  int rval;
290 
291  ehp = (ec_etherheadert *)&(port->txbuf[idx]);
292  /* rewrite MAC source address 1 to primary */
293  ehp->sa1 = htons(priMAC[1]);
294  /* transmit over primary socket*/
295  rval = ecx_outframe(port, idx, 0);
296  if (port->redstate != ECT_RED_NONE)
297  {
298  pthread_mutex_lock( &(port->tx_mutex) );
299  ehp = (ec_etherheadert *)&(port->txbuf2);
300  /* use dummy frame for secondary socket transmit (BRD) */
301  datagramP = (ec_comt*)&(port->txbuf2[ETH_HEADERSIZE]);
302  /* write index to frame */
303  datagramP->index = idx;
304  /* rewrite MAC source address 1 to secondary */
305  ehp->sa1 = htons(secMAC[1]);
306  /* transmit over secondary socket */
307  port->redport->rxbufstat[idx] = EC_BUF_TX;
308  if (pcap_sendpacket(port->redport->sockhandle, (u_char const *)&(port->txbuf2), port->txbuflength2) == PCAP_ERROR)
309  {
310  port->redport->rxbufstat[idx] = EC_BUF_EMPTY;
311  }
312  pthread_mutex_unlock( &(port->tx_mutex) );
313  }
314 
315  return rval;
316 }
317 
323 static int ecx_recvpkt(ecx_portt *port, int stacknumber)
324 {
325  int lp, bytesrx;
326  ec_stackT *stack;
327  struct pcap_pkthdr * header;
328  unsigned char const * pkt_data;
329  int res;
330 
331  if (!stacknumber)
332  {
333  stack = &(port->stack);
334  }
335  else
336  {
337  stack = &(port->redport->stack);
338  }
339  lp = sizeof(port->tempinbuf);
340 
341  res = pcap_next_ex(*stack->sock, &header, &pkt_data);
342  if (res <=0 )
343  {
344  port->tempinbufs = 0;
345  return 0;
346  }
347 
348  bytesrx = header->len;
349  if (bytesrx > lp)
350  {
351  bytesrx = lp;
352  }
353  memcpy(*stack->tempbuf, pkt_data, bytesrx);
354  port->tempinbufs = bytesrx;
355  return (bytesrx > 0);
356 }
357 
374 int ecx_inframe(ecx_portt *port, int idx, int stacknumber)
375 {
376  uint16 l;
377  int rval;
378  int idxf;
379  ec_etherheadert *ehp;
380  ec_comt *ecp;
381  ec_stackT *stack;
382  ec_bufT *rxbuf;
383 
384  if (!stacknumber)
385  {
386  stack = &(port->stack);
387  }
388  else
389  {
390  stack = &(port->redport->stack);
391  }
392  rval = EC_NOFRAME;
393  rxbuf = &(*stack->rxbuf)[idx];
394  /* check if requested index is already in buffer ? */
395  if ((idx < EC_MAXBUF) && ((*stack->rxbufstat)[idx] == EC_BUF_RCVD))
396  {
397  l = (*rxbuf)[0] + ((uint16)((*rxbuf)[1] & 0x0f) << 8);
398  /* return WKC */
399  rval = ((*rxbuf)[l] + ((uint16)(*rxbuf)[l + 1] << 8));
400  /* mark as completed */
401  (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
402  }
403  else
404  {
405  pthread_mutex_lock(&(port->rx_mutex));
406  /* non blocking call to retrieve frame from socket */
407  if (ecx_recvpkt(port, stacknumber))
408  {
409  rval = EC_OTHERFRAME;
410  ehp =(ec_etherheadert*)(stack->tempbuf);
411  /* check if it is an EtherCAT frame */
412  if (ehp->etype == htons(ETH_P_ECAT))
413  {
414  ecp =(ec_comt*)(&(*stack->tempbuf)[ETH_HEADERSIZE]);
415  l = etohs(ecp->elength) & 0x0fff;
416  idxf = ecp->index;
417  /* found index equals requested index ? */
418  if (idxf == idx)
419  {
420  /* yes, put it in the buffer array (strip ethernet header) */
421  memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idx] - ETH_HEADERSIZE);
422  /* return WKC */
423  rval = ((*rxbuf)[l] + ((uint16)((*rxbuf)[l + 1]) << 8));
424  /* mark as completed */
425  (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
426  /* store MAC source word 1 for redundant routing info */
427  (*stack->rxsa)[idx] = ntohs(ehp->sa1);
428  }
429  else
430  {
431  /* check if index exist and someone is waiting for it */
432  if (idxf < EC_MAXBUF && (*stack->rxbufstat)[idxf] == EC_BUF_TX)
433  {
434  rxbuf = &(*stack->rxbuf)[idxf];
435  /* put it in the buffer array (strip ethernet header) */
436  memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idxf] - ETH_HEADERSIZE);
437  /* mark as received */
438  (*stack->rxbufstat)[idxf] = EC_BUF_RCVD;
439  (*stack->rxsa)[idxf] = ntohs(ehp->sa1);
440  }
441  else
442  {
443  assert(0);
444  /* strange things happened */
445  }
446  }
447  }
448  }
449  pthread_mutex_unlock( &(port->rx_mutex) );
450 
451  }
452 
453  /* WKC if matching frame found */
454  return rval;
455 }
456 
469 static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert *timer)
470 {
471  osal_timert timer2;
472  int wkc = EC_NOFRAME;
473  int wkc2 = EC_NOFRAME;
474  int primrx, secrx;
475 
476  /* if not in redundant mode then always assume secondary is OK */
477  if (port->redstate == ECT_RED_NONE)
478  wkc2 = 0;
479  do
480  {
481  /* only read frame if not already in */
482  if (wkc <= EC_NOFRAME)
483  wkc = ecx_inframe(port, idx, 0);
484  /* only try secondary if in redundant mode */
485  if (port->redstate != ECT_RED_NONE)
486  {
487  /* only read frame if not already in */
488  if (wkc2 <= EC_NOFRAME)
489  wkc2 = ecx_inframe(port, idx, 1);
490  }
491  /* wait for both frames to arrive or timeout */
492  } while (((wkc <= EC_NOFRAME) || (wkc2 <= EC_NOFRAME)) && !osal_timer_is_expired(timer));
493  /* only do redundant functions when in redundant mode */
494  if (port->redstate != ECT_RED_NONE)
495  {
496  /* primrx if the received MAC source on primary socket */
497  primrx = 0;
498  if (wkc > EC_NOFRAME) primrx = port->rxsa[idx];
499  /* secrx if the received MAC source on psecondary socket */
500  secrx = 0;
501  if (wkc2 > EC_NOFRAME) secrx = port->redport->rxsa[idx];
502 
503  /* primary socket got secondary frame and secondary socket got primary frame */
504  /* normal situation in redundant mode */
505  if ( ((primrx == RX_SEC) && (secrx == RX_PRIM)) )
506  {
507  /* copy secondary buffer to primary */
508  memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
509  wkc = wkc2;
510  }
511  /* primary socket got nothing or primary frame, and secondary socket got secondary frame */
512  /* we need to resend TX packet */
513  if ( ((primrx == 0) && (secrx == RX_SEC)) ||
514  ((primrx == RX_PRIM) && (secrx == RX_SEC)) )
515  {
516  /* If both primary and secondary have partial connection retransmit the primary received
517  * frame over the secondary socket. The result from the secondary received frame is a combined
518  * frame that traversed all slaves in standard order. */
519  if ( (primrx == RX_PRIM) && (secrx == RX_SEC) )
520  {
521  /* copy primary rx to tx buffer */
522  memcpy(&(port->txbuf[idx][ETH_HEADERSIZE]), &(port->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
523  }
524  osal_timer_start (&timer2, EC_TIMEOUTRET);
525  /* resend secondary tx */
526  ecx_outframe(port, idx, 1);
527  do
528  {
529  /* retrieve frame */
530  wkc2 = ecx_inframe(port, idx, 1);
531  } while ((wkc2 <= EC_NOFRAME) && !osal_timer_is_expired(&timer2));
532  if (wkc2 > EC_NOFRAME)
533  {
534  /* copy secondary result to primary rx buffer */
535  memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
536  wkc = wkc2;
537  }
538  }
539  }
540 
541  /* return WKC or EC_NOFRAME */
542  return wkc;
543 }
544 
552 int ecx_waitinframe(ecx_portt *port, int idx, int timeout)
553 {
554  int wkc;
555  osal_timert timer;
556 
557  osal_timer_start (&timer, timeout);
558  wkc = ecx_waitinframe_red(port, idx, &timer);
559 
560  return wkc;
561 }
562 
575 int ecx_srconfirm(ecx_portt *port, int idx, int timeout)
576 {
577  int wkc = EC_NOFRAME;
578  osal_timert timer1, timer2;
579 
580  osal_timer_start (&timer1, timeout);
581  do
582  {
583  /* tx frame on primary and if in redundant mode a dummy on secondary */
584  ecx_outframe_red(port, idx);
585  if (timeout < EC_TIMEOUTRET)
586  {
587  osal_timer_start (&timer2, timeout);
588  }
589  else
590  {
591  /* normally use partial timeout for rx */
592  osal_timer_start (&timer2, EC_TIMEOUTRET);
593  }
594  /* get frame from primary or if in redundant mode possibly from secondary */
595  wkc = ecx_waitinframe_red(port, idx, &timer2);
596  /* wait for answer with WKC>=0 or otherwise retry until timeout */
597  } while ((wkc <= EC_NOFRAME) && !osal_timer_is_expired (&timer1));
598 
599  return wkc;
600 }
601 
602 
603 #ifdef EC_VER1
604 
605 int ec_setupnic(const char *ifname, int secondary)
606 {
607  return ecx_setupnic(&ecx_port, ifname, secondary);
608 }
609 
610 int ec_closenic(void)
611 {
612  return ecx_closenic(&ecx_port);
613 }
614 
615 int ec_getindex(void)
616 {
617  return ecx_getindex(&ecx_port);
618 }
619 
620 void ec_setbufstat(int idx, int bufstat)
621 {
622  ecx_setbufstat(&ecx_port, idx, bufstat);
623 }
624 
625 int ec_outframe(int idx, int stacknumber)
626 {
627  return ecx_outframe(&ecx_port, idx, stacknumber);
628 }
629 
630 int ec_outframe_red(int idx)
631 {
632  return ecx_outframe_red(&ecx_port, idx);
633 }
634 
635 int ec_inframe(int idx, int stacknumber)
636 {
637  return ecx_inframe(&ecx_port, idx, stacknumber);
638 }
639 
640 int ec_waitinframe(int idx, int timeout)
641 {
642  return ecx_waitinframe(&ecx_port, idx, timeout);
643 }
644 
645 int ec_srconfirm(int idx, int timeout)
646 {
647  return ecx_srconfirm(&ecx_port, idx, timeout);
648 }
649 
650 #endif
int ec_outframe(int idx, int sock)
void ecx_setbufstat(ecx_portt *port, int idx, int bufstat)
ec_bufT rxbuf[EC_MAXBUF]
Definition: erika/nicdrv.h:43
int rxsa[EC_MAXBUF]
Definition: erika/nicdrv.h:47
ec_bufT txbuf[EC_MAXBUF]
Definition: erika/nicdrv.h:68
boolean osal_timer_is_expired(osal_timert *self)
Definition: erika/osal.c:74
int(* rxsa)[EC_MAXBUF]
Definition: erika/nicdrv.h:34
int txbuflength[EC_MAXBUF]
Definition: erika/nicdrv.h:70
int ec_setupnic(const char *ifname, int secondary)
static int ecx_recvpkt(ecx_portt *port, int stacknumber)
struct pcap pcap_t
Definition: pcap/pcap.h:87
static char errbuf[PCAP_ERRBUF_SIZE]
Definition: macosx/nicdrv.c:68
#define EC_MAXBUF
Definition: ethercattype.h:62
ec_bufT txbuf2
Definition: erika/nicdrv.h:72
Headerfile for nicdrv.c.
int rxsa[EC_MAXBUF]
Definition: erika/nicdrv.h:62
int(* txbuflength)[EC_MAXBUF]
Definition: erika/nicdrv.h:26
PACKED_BEGIN struct PACKED ec_etherheadert
bpf_u_int32 len
Definition: pcap/pcap.h:170
ec_bufT * tempbuf
Definition: erika/nicdrv.h:28
int ecx_closenic(ecx_portt *port)
int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary)
Definition: macosx/nicdrv.c:85
const uint16 priMAC[3]
Definition: macosx/nicdrv.c:59
int txbuflength2
Definition: erika/nicdrv.h:74
int pcap_setdirection(pcap_t *, pcap_direction_t)
uint16_t uint16
Definition: osal.h:29
#define RX_SEC
Definition: macosx/nicdrv.c:66
int pcap_setnonblock(pcap_t *, int, char *)
General typedefs and defines for EtherCAT.
#define etohs(A)
Definition: ethercattype.h:536
#define ETH_HEADERSIZE
Definition: ethercattype.h:103
int rxbufstat[EC_MAXBUF]
Definition: erika/nicdrv.h:45
ec_stackT stack
Definition: erika/nicdrv.h:55
ec_bufT rxbuf[EC_MAXBUF]
Definition: erika/nicdrv.h:58
pthread_mutex_t tx_mutex
Definition: linux/nicdrv.h:85
ec_stackT stack
Definition: erika/nicdrv.h:40
ec_bufT tempinbuf
Definition: erika/nicdrv.h:64
ec_bufT(* rxbuf)[EC_MAXBUF]
Definition: erika/nicdrv.h:30
static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert *timer)
int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **)
int ecx_outframe(ecx_portt *port, int idx, int stacknumber)
int ec_srconfirm(int idx, int timeout)
void ec_setupheader(void *p)
int tempinbufs
Definition: erika/nicdrv.h:66
pcap_t * pcap_open_live(const char *, int, int, int, char *)
ec_bufT(* txbuf)[EC_MAXBUF]
Definition: erika/nicdrv.h:24
#define RX_PRIM
Definition: macosx/nicdrv.c:64
void ec_setbufstat(int idx, int bufstat)
ecx_redportt * redport
Definition: erika/nicdrv.h:80
PACKED_BEGIN struct PACKED ec_comt
void pcap_close(pcap_t *)
int pcap_sendpacket(pcap_t *, const u_char *, int)
#define PCAP_ERROR
Definition: pcap/pcap.h:253
int ecx_srconfirm(ecx_portt *port, int idx, int timeout)
#define EC_TIMEOUTRET
Definition: ethercattype.h:64
#define EC_OTHERFRAME
Definition: ethercattype.h:43
pthread_mutex_t getindex_mutex
Definition: linux/nicdrv.h:84
int ec_outframe_red(int idx)
int redstate
Definition: erika/nicdrv.h:78
#define ETH_P_ECAT
Definition: ethercattype.h:459
int wkc
Definition: aliastool.c:47
static void ecx_clear_rxbufstat(int *rxbufstat)
Definition: macosx/nicdrv.c:70
int rxbufstat[EC_MAXBUF]
Definition: erika/nicdrv.h:60
uint8 ec_bufT[EC_BUFSIZE]
Definition: ethercattype.h:87
ec_bufT tempinbuf
Definition: erika/nicdrv.h:49
int ec_closenic(void)
int ecx_getindex(ecx_portt *port)
int ec_getindex(void)
const uint16 secMAC[3]
Definition: macosx/nicdrv.c:61
int ecx_outframe_red(ecx_portt *port, int idx)
int ec_waitinframe(int idx, int timeout)
void osal_timer_start(osal_timert *self, uint32 timeout_usec)
Definition: erika/osal.c:59
int(* rxbufstat)[EC_MAXBUF]
Definition: erika/nicdrv.h:32
int sockhandle
Definition: erika/nicdrv.h:56
#define EC_NOFRAME
Definition: ethercattype.h:41
int * sock
Definition: erika/nicdrv.h:22
int ecx_waitinframe(ecx_portt *port, int idx, int timeout)
pthread_mutex_t rx_mutex
Definition: linux/nicdrv.h:86
int ecx_inframe(ecx_portt *port, int idx, int stacknumber)
uint8 rxbuf[1024]
Definition: eoe_test.c:50
#define PCAP_ERRBUF_SIZE
Definition: pcap/pcap.h:76


soem
Author(s): Arthur Ketels and M.J.G. van den Molengraft
autogenerated on Mon Feb 28 2022 23:46:57