linux/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 
33 #include <sys/types.h>
34 #include <sys/ioctl.h>
35 #include <net/if.h>
36 #include <sys/socket.h>
37 #include <unistd.h>
38 #include <sys/time.h>
39 #include <time.h>
40 #include <arpa/inet.h>
41 #include <stdio.h>
42 #include <fcntl.h>
43 #include <string.h>
44 #include <netpacket/packet.h>
45 #include <pthread.h>
46 
47 #include "oshw.h"
48 #include "osal.h"
49 
51 enum
52 {
57 };
58 
59 
66 const uint16 priMAC[3] = { 0x0101, 0x0101, 0x0101 };
68 const uint16 secMAC[3] = { 0x0404, 0x0404, 0x0404 };
69 
71 #define RX_PRIM priMAC[1]
72 
73 #define RX_SEC secMAC[1]
74 
75 static void ecx_clear_rxbufstat(int *rxbufstat)
76 {
77  int i;
78  for(i = 0; i < EC_MAXBUF; i++)
79  {
80  rxbufstat[i] = EC_BUF_EMPTY;
81  }
82 }
83 
90 int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary)
91 {
92  int i;
93  int r, rval, ifindex;
94  struct timeval timeout;
95  struct ifreq ifr;
96  struct sockaddr_ll sll;
97  int *psock;
98  pthread_mutexattr_t mutexattr;
99 
100  rval = 0;
101  if (secondary)
102  {
103  /* secondary port struct available? */
104  if (port->redport)
105  {
106  /* when using secondary socket it is automatically a redundant setup */
107  psock = &(port->redport->sockhandle);
108  *psock = -1;
109  port->redstate = ECT_RED_DOUBLE;
110  port->redport->stack.sock = &(port->redport->sockhandle);
111  port->redport->stack.txbuf = &(port->txbuf);
112  port->redport->stack.txbuflength = &(port->txbuflength);
113  port->redport->stack.tempbuf = &(port->redport->tempinbuf);
114  port->redport->stack.rxbuf = &(port->redport->rxbuf);
115  port->redport->stack.rxbufstat = &(port->redport->rxbufstat);
116  port->redport->stack.rxsa = &(port->redport->rxsa);
117  ecx_clear_rxbufstat(&(port->redport->rxbufstat[0]));
118  }
119  else
120  {
121  /* fail */
122  return 0;
123  }
124  }
125  else
126  {
127  pthread_mutexattr_init(&mutexattr);
128  pthread_mutexattr_setprotocol(&mutexattr , PTHREAD_PRIO_INHERIT);
129  pthread_mutex_init(&(port->getindex_mutex), &mutexattr);
130  pthread_mutex_init(&(port->tx_mutex) , &mutexattr);
131  pthread_mutex_init(&(port->rx_mutex) , &mutexattr);
132  port->sockhandle = -1;
133  port->lastidx = 0;
134  port->redstate = ECT_RED_NONE;
135  port->stack.sock = &(port->sockhandle);
136  port->stack.txbuf = &(port->txbuf);
137  port->stack.txbuflength = &(port->txbuflength);
138  port->stack.tempbuf = &(port->tempinbuf);
139  port->stack.rxbuf = &(port->rxbuf);
140  port->stack.rxbufstat = &(port->rxbufstat);
141  port->stack.rxsa = &(port->rxsa);
142  ecx_clear_rxbufstat(&(port->rxbufstat[0]));
143  psock = &(port->sockhandle);
144  }
145  /* we use RAW packet socket, with packet type ETH_P_ECAT */
146  *psock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ECAT));
147 
148  timeout.tv_sec = 0;
149  timeout.tv_usec = 1;
150  r = setsockopt(*psock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
151  r = setsockopt(*psock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
152  i = 1;
153  r = setsockopt(*psock, SOL_SOCKET, SO_DONTROUTE, &i, sizeof(i));
154  /* connect socket to NIC by name */
155  strcpy(ifr.ifr_name, ifname);
156  r = ioctl(*psock, SIOCGIFINDEX, &ifr);
157  ifindex = ifr.ifr_ifindex;
158  strcpy(ifr.ifr_name, ifname);
159  ifr.ifr_flags = 0;
160  /* reset flags of NIC interface */
161  r = ioctl(*psock, SIOCGIFFLAGS, &ifr);
162  /* set flags of NIC interface, here promiscuous and broadcast */
163  ifr.ifr_flags = ifr.ifr_flags | IFF_PROMISC | IFF_BROADCAST;
164  r = ioctl(*psock, SIOCSIFFLAGS, &ifr);
165  /* bind socket to protocol, in this case RAW EtherCAT */
166  sll.sll_family = AF_PACKET;
167  sll.sll_ifindex = ifindex;
168  sll.sll_protocol = htons(ETH_P_ECAT);
169  r = bind(*psock, (struct sockaddr *)&sll, sizeof(sll));
170  /* setup ethernet headers in tx buffers so we don't have to repeat it */
171  for (i = 0; i < EC_MAXBUF; i++)
172  {
173  ec_setupheader(&(port->txbuf[i]));
174  port->rxbufstat[i] = EC_BUF_EMPTY;
175  }
176  ec_setupheader(&(port->txbuf2));
177  if (r == 0) rval = 1;
178 
179  return rval;
180 }
181 
187 {
188  if (port->sockhandle >= 0)
189  close(port->sockhandle);
190  if ((port->redport) && (port->redport->sockhandle >= 0))
191  close(port->redport->sockhandle);
192 
193  return 0;
194 }
195 
201 void ec_setupheader(void *p)
202 {
203  ec_etherheadert *bp;
204  bp = p;
205  bp->da0 = htons(0xffff);
206  bp->da1 = htons(0xffff);
207  bp->da2 = htons(0xffff);
208  bp->sa0 = htons(priMAC[0]);
209  bp->sa1 = htons(priMAC[1]);
210  bp->sa2 = htons(priMAC[2]);
211  bp->etype = htons(ETH_P_ECAT);
212 }
213 
219 {
220  int idx;
221  int cnt;
222 
223  pthread_mutex_lock( &(port->getindex_mutex) );
224 
225  idx = port->lastidx + 1;
226  /* index can't be larger than buffer array */
227  if (idx >= EC_MAXBUF)
228  {
229  idx = 0;
230  }
231  cnt = 0;
232  /* try to find unused index */
233  while ((port->rxbufstat[idx] != EC_BUF_EMPTY) && (cnt < EC_MAXBUF))
234  {
235  idx++;
236  cnt++;
237  if (idx >= EC_MAXBUF)
238  {
239  idx = 0;
240  }
241  }
242  port->rxbufstat[idx] = EC_BUF_ALLOC;
243  if (port->redstate != ECT_RED_NONE)
244  port->redport->rxbufstat[idx] = EC_BUF_ALLOC;
245  port->lastidx = idx;
246 
247  pthread_mutex_unlock( &(port->getindex_mutex) );
248 
249  return idx;
250 }
251 
257 void ecx_setbufstat(ecx_portt *port, int idx, int bufstat)
258 {
259  port->rxbufstat[idx] = bufstat;
260  if (port->redstate != ECT_RED_NONE)
261  port->redport->rxbufstat[idx] = bufstat;
262 }
263 
270 int ecx_outframe(ecx_portt *port, int idx, int stacknumber)
271 {
272  int lp, rval;
273  ec_stackT *stack;
274 
275  if (!stacknumber)
276  {
277  stack = &(port->stack);
278  }
279  else
280  {
281  stack = &(port->redport->stack);
282  }
283  lp = (*stack->txbuflength)[idx];
284  (*stack->rxbufstat)[idx] = EC_BUF_TX;
285  rval = send(*stack->sock, (*stack->txbuf)[idx], lp, 0);
286  if (rval == -1)
287  {
288  (*stack->rxbufstat)[idx] = EC_BUF_EMPTY;
289  }
290 
291  return rval;
292 }
293 
299 int ecx_outframe_red(ecx_portt *port, int idx)
300 {
301  ec_comt *datagramP;
302  ec_etherheadert *ehp;
303  int rval;
304 
305  ehp = (ec_etherheadert *)&(port->txbuf[idx]);
306  /* rewrite MAC source address 1 to primary */
307  ehp->sa1 = htons(priMAC[1]);
308  /* transmit over primary socket*/
309  rval = ecx_outframe(port, idx, 0);
310  if (port->redstate != ECT_RED_NONE)
311  {
312  pthread_mutex_lock( &(port->tx_mutex) );
313  ehp = (ec_etherheadert *)&(port->txbuf2);
314  /* use dummy frame for secondary socket transmit (BRD) */
315  datagramP = (ec_comt*)&(port->txbuf2[ETH_HEADERSIZE]);
316  /* write index to frame */
317  datagramP->index = idx;
318  /* rewrite MAC source address 1 to secondary */
319  ehp->sa1 = htons(secMAC[1]);
320  /* transmit over secondary socket */
321  port->redport->rxbufstat[idx] = EC_BUF_TX;
322  if (send(port->redport->sockhandle, &(port->txbuf2), port->txbuflength2 , 0) == -1)
323  {
324  port->redport->rxbufstat[idx] = EC_BUF_EMPTY;
325  }
326  pthread_mutex_unlock( &(port->tx_mutex) );
327  }
328 
329  return rval;
330 }
331 
337 static int ecx_recvpkt(ecx_portt *port, int stacknumber)
338 {
339  int lp, bytesrx;
340  ec_stackT *stack;
341 
342  if (!stacknumber)
343  {
344  stack = &(port->stack);
345  }
346  else
347  {
348  stack = &(port->redport->stack);
349  }
350  lp = sizeof(port->tempinbuf);
351  bytesrx = recv(*stack->sock, (*stack->tempbuf), lp, 0);
352  port->tempinbufs = bytesrx;
353 
354  return (bytesrx > 0);
355 }
356 
373 int ecx_inframe(ecx_portt *port, int idx, int stacknumber)
374 {
375  uint16 l;
376  int rval;
377  int idxf;
378  ec_etherheadert *ehp;
379  ec_comt *ecp;
380  ec_stackT *stack;
381  ec_bufT *rxbuf;
382 
383  if (!stacknumber)
384  {
385  stack = &(port->stack);
386  }
387  else
388  {
389  stack = &(port->redport->stack);
390  }
391  rval = EC_NOFRAME;
392  rxbuf = &(*stack->rxbuf)[idx];
393  /* check if requested index is already in buffer ? */
394  if ((idx < EC_MAXBUF) && ((*stack->rxbufstat)[idx] == EC_BUF_RCVD))
395  {
396  l = (*rxbuf)[0] + ((uint16)((*rxbuf)[1] & 0x0f) << 8);
397  /* return WKC */
398  rval = ((*rxbuf)[l] + ((uint16)(*rxbuf)[l + 1] << 8));
399  /* mark as completed */
400  (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
401  }
402  else
403  {
404  pthread_mutex_lock(&(port->rx_mutex));
405  /* non blocking call to retrieve frame from socket */
406  if (ecx_recvpkt(port, stacknumber))
407  {
408  rval = EC_OTHERFRAME;
409  ehp =(ec_etherheadert*)(stack->tempbuf);
410  /* check if it is an EtherCAT frame */
411  if (ehp->etype == htons(ETH_P_ECAT))
412  {
413  ecp =(ec_comt*)(&(*stack->tempbuf)[ETH_HEADERSIZE]);
414  l = etohs(ecp->elength) & 0x0fff;
415  idxf = ecp->index;
416  /* found index equals requested index ? */
417  if (idxf == idx)
418  {
419  /* yes, put it in the buffer array (strip ethernet header) */
420  memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idx] - ETH_HEADERSIZE);
421  /* return WKC */
422  rval = ((*rxbuf)[l] + ((uint16)((*rxbuf)[l + 1]) << 8));
423  /* mark as completed */
424  (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
425  /* store MAC source word 1 for redundant routing info */
426  (*stack->rxsa)[idx] = ntohs(ehp->sa1);
427  }
428  else
429  {
430  /* check if index exist and someone is waiting for it */
431  if (idxf < EC_MAXBUF && (*stack->rxbufstat)[idxf] == EC_BUF_TX)
432  {
433  rxbuf = &(*stack->rxbuf)[idxf];
434  /* put it in the buffer array (strip ethernet header) */
435  memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idxf] - ETH_HEADERSIZE);
436  /* mark as received */
437  (*stack->rxbufstat)[idxf] = EC_BUF_RCVD;
438  (*stack->rxsa)[idxf] = ntohs(ehp->sa1);
439  }
440  else
441  {
442  /* strange things happened */
443  }
444  }
445  }
446  }
447  pthread_mutex_unlock( &(port->rx_mutex) );
448 
449  }
450 
451  /* WKC if matching frame found */
452  return rval;
453 }
454 
467 static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert *timer)
468 {
469  osal_timert timer2;
470  int wkc = EC_NOFRAME;
471  int wkc2 = EC_NOFRAME;
472  int primrx, secrx;
473 
474  /* if not in redundant mode then always assume secondary is OK */
475  if (port->redstate == ECT_RED_NONE)
476  wkc2 = 0;
477  do
478  {
479  /* only read frame if not already in */
480  if (wkc <= EC_NOFRAME)
481  wkc = ecx_inframe(port, idx, 0);
482  /* only try secondary if in redundant mode */
483  if (port->redstate != ECT_RED_NONE)
484  {
485  /* only read frame if not already in */
486  if (wkc2 <= EC_NOFRAME)
487  wkc2 = ecx_inframe(port, idx, 1);
488  }
489  /* wait for both frames to arrive or timeout */
490  } while (((wkc <= EC_NOFRAME) || (wkc2 <= EC_NOFRAME)) && !osal_timer_is_expired(timer));
491  /* only do redundant functions when in redundant mode */
492  if (port->redstate != ECT_RED_NONE)
493  {
494  /* primrx if the received MAC source on primary socket */
495  primrx = 0;
496  if (wkc > EC_NOFRAME) primrx = port->rxsa[idx];
497  /* secrx if the received MAC source on psecondary socket */
498  secrx = 0;
499  if (wkc2 > EC_NOFRAME) secrx = port->redport->rxsa[idx];
500 
501  /* primary socket got secondary frame and secondary socket got primary frame */
502  /* normal situation in redundant mode */
503  if ( ((primrx == RX_SEC) && (secrx == RX_PRIM)) )
504  {
505  /* copy secondary buffer to primary */
506  memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
507  wkc = wkc2;
508  }
509  /* primary socket got nothing or primary frame, and secondary socket got secondary frame */
510  /* we need to resend TX packet */
511  if ( ((primrx == 0) && (secrx == RX_SEC)) ||
512  ((primrx == RX_PRIM) && (secrx == RX_SEC)) )
513  {
514  /* If both primary and secondary have partial connection retransmit the primary received
515  * frame over the secondary socket. The result from the secondary received frame is a combined
516  * frame that traversed all slaves in standard order. */
517  if ( (primrx == RX_PRIM) && (secrx == RX_SEC) )
518  {
519  /* copy primary rx to tx buffer */
520  memcpy(&(port->txbuf[idx][ETH_HEADERSIZE]), &(port->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
521  }
522  osal_timer_start (&timer2, EC_TIMEOUTRET);
523  /* resend secondary tx */
524  ecx_outframe(port, idx, 1);
525  do
526  {
527  /* retrieve frame */
528  wkc2 = ecx_inframe(port, idx, 1);
529  } while ((wkc2 <= EC_NOFRAME) && !osal_timer_is_expired(&timer2));
530  if (wkc2 > EC_NOFRAME)
531  {
532  /* copy secondary result to primary rx buffer */
533  memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
534  wkc = wkc2;
535  }
536  }
537  }
538 
539  /* return WKC or EC_NOFRAME */
540  return wkc;
541 }
542 
550 int ecx_waitinframe(ecx_portt *port, int idx, int timeout)
551 {
552  int wkc;
553  osal_timert timer;
554 
555  osal_timer_start (&timer, timeout);
556  wkc = ecx_waitinframe_red(port, idx, &timer);
557 
558  return wkc;
559 }
560 
573 int ecx_srconfirm(ecx_portt *port, int idx, int timeout)
574 {
575  int wkc = EC_NOFRAME;
576  osal_timert timer1, timer2;
577 
578  osal_timer_start (&timer1, timeout);
579  do
580  {
581  /* tx frame on primary and if in redundant mode a dummy on secondary */
582  ecx_outframe_red(port, idx);
583  if (timeout < EC_TIMEOUTRET)
584  {
585  osal_timer_start (&timer2, timeout);
586  }
587  else
588  {
589  /* normally use partial timeout for rx */
590  osal_timer_start (&timer2, EC_TIMEOUTRET);
591  }
592  /* get frame from primary or if in redundant mode possibly from secondary */
593  wkc = ecx_waitinframe_red(port, idx, &timer2);
594  /* wait for answer with WKC>=0 or otherwise retry until timeout */
595  } while ((wkc <= EC_NOFRAME) && !osal_timer_is_expired (&timer1));
596 
597  return wkc;
598 }
599 
600 #ifdef EC_VER1
601 int ec_setupnic(const char *ifname, int secondary)
602 {
603  return ecx_setupnic(&ecx_port, ifname, secondary);
604 }
605 
606 int ec_closenic(void)
607 {
608  return ecx_closenic(&ecx_port);
609 }
610 
611 int ec_getindex(void)
612 {
613  return ecx_getindex(&ecx_port);
614 }
615 
616 void ec_setbufstat(int idx, int bufstat)
617 {
618  ecx_setbufstat(&ecx_port, idx, bufstat);
619 }
620 
621 int ec_outframe(int idx, int stacknumber)
622 {
623  return ecx_outframe(&ecx_port, idx, stacknumber);
624 }
625 
626 int ec_outframe_red(int idx)
627 {
628  return ecx_outframe_red(&ecx_port, idx);
629 }
630 
631 int ec_inframe(int idx, int stacknumber)
632 {
633  return ecx_inframe(&ecx_port, idx, stacknumber);
634 }
635 
636 int ec_waitinframe(int idx, int timeout)
637 {
638  return ecx_waitinframe(&ecx_port, idx, timeout);
639 }
640 
641 int ec_srconfirm(int idx, int timeout)
642 {
643  return ecx_srconfirm(&ecx_port, idx, timeout);
644 }
645 #endif
int ecx_getindex(ecx_portt *port)
Definition: linux/nicdrv.c:218
int ec_outframe(int idx, int sock)
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)
int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary)
Definition: linux/nicdrv.c:90
#define EC_MAXBUF
Definition: ethercattype.h:62
#define RX_SEC
Definition: linux/nicdrv.c:73
ec_bufT txbuf2
Definition: erika/nicdrv.h:72
int rxsa[EC_MAXBUF]
Definition: erika/nicdrv.h:62
static int ecx_recvpkt(ecx_portt *port, int stacknumber)
Definition: linux/nicdrv.c:337
int ecx_inframe(ecx_portt *port, int idx, int stacknumber)
Definition: linux/nicdrv.c:373
int(* txbuflength)[EC_MAXBUF]
Definition: erika/nicdrv.h:26
PACKED_BEGIN struct PACKED ec_etherheadert
ec_bufT * tempbuf
Definition: erika/nicdrv.h:28
int txbuflength2
Definition: erika/nicdrv.h:74
uint16_t uint16
Definition: osal.h:29
#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
#define RX_PRIM
Definition: linux/nicdrv.c:71
int ec_srconfirm(int idx, int timeout)
int tempinbufs
Definition: erika/nicdrv.h:66
const uint16 secMAC[3]
Definition: linux/nicdrv.c:68
ec_bufT(* txbuf)[EC_MAXBUF]
Definition: erika/nicdrv.h:24
void ec_setbufstat(int idx, int bufstat)
ecx_redportt * redport
Definition: erika/nicdrv.h:80
int ecx_waitinframe(ecx_portt *port, int idx, int timeout)
Definition: linux/nicdrv.c:550
PACKED_BEGIN struct PACKED ec_comt
int ecx_outframe(ecx_portt *port, int idx, int stacknumber)
Definition: linux/nicdrv.c:270
Headerfile for ethercatbase.c.
static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert *timer)
Definition: linux/nicdrv.c:467
#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
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)
static void ecx_clear_rxbufstat(int *rxbufstat)
Definition: linux/nicdrv.c:75
const uint16 priMAC[3]
Definition: linux/nicdrv.c:66
int ecx_closenic(ecx_portt *port)
Definition: linux/nicdrv.c:186
int ec_getindex(void)
int ecx_outframe_red(ecx_portt *port, int idx)
Definition: linux/nicdrv.c:299
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
void ec_setupheader(void *p)
Definition: linux/nicdrv.c:201
int * sock
Definition: erika/nicdrv.h:22
void ecx_setbufstat(ecx_portt *port, int idx, int bufstat)
Definition: linux/nicdrv.c:257
pthread_mutex_t rx_mutex
Definition: linux/nicdrv.h:86
uint8 rxbuf[1024]
Definition: eoe_test.c:50
int ecx_srconfirm(ecx_portt *port, int idx, int timeout)
Definition: linux/nicdrv.c:573


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