erika/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/time.h>
34 #include <time.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37 #include <stdio.h>
38 #include <fcntl.h>
39 #include <string.h>
40 #include <assert.h>
41 
42 #include "oshw.h"
43 #include "osal.h"
44 #include "nicdrv.h"
45 #include "ee.h"
46 #include "intel_i210.h"
47 #include "ee_x86_64_tsc.h"
48 
50 enum
51 {
56 };
57 
58 
65 const uint16 priMAC[3] = { 0x0201, 0x0101, 0x0101 };
67 const uint16 secMAC[3] = { 0x0604, 0x0404, 0x0404 };
68 
70 #define RX_PRIM priMAC[1]
71 
72 #define RX_SEC secMAC[1]
73 
74 void ee_port_lock(void);
75 void ee_port_unlock(void);
76 
77 static inline void ecx_clear_rxbufstat(int *rxbufstat)
78 {
79  int i;
80  for(i = 0; i < EC_MAXBUF; i++)
81  rxbufstat[i] = EC_BUF_EMPTY;
82 }
83 
90 int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary)
91 {
92  int d;
93  struct eth_device *dev;
94  OSEE_PRINT("ecx_setupnic() searching %s...\n", ifname);
95 
96  for (d = 0;; ++d) {
97  dev = eth_get_device(d);
98 
99  if (dev == NULL)
100  break; // ERROR: device not found
101 
102  if (!strncmp(dev->name, ifname, MAX_DEVICE_NAME)){
103  // Device found
104  int i;
105 
106  eth_setup_device(d, 1, 100);
107  port->dev_id = d;
108 
109  port->sockhandle = -1;
110  port->lastidx = 0;
111  port->redstate = ECT_RED_NONE;
112  port->stack.sock = &(port->sockhandle);
113  port->stack.txbuf = &(port->txbuf);
114  port->stack.txbuflength = &(port->txbuflength);
115  port->stack.tempbuf = &(port->tempinbuf);
116  port->stack.rxbuf = &(port->rxbuf);
117  port->stack.rxbufstat = &(port->rxbufstat);
118  port->stack.rxsa = &(port->rxsa);
119  ecx_clear_rxbufstat(&(port->rxbufstat[0]));
120 
121  /* setup ethernet headers in tx buffers so we don't have to repeat it */
122  for (i = 0; i < EC_MAXBUF; i++)
123  {
124  ec_setupheader(&(port->txbuf[i]));
125  port->rxbufstat[i] = EC_BUF_EMPTY;
126  }
127  ec_setupheader(&(port->txbuf2));
128 
129  break; // device found
130  }
131  }
132 
133  return (dev != NULL);
134 }
135 
140 inline int ecx_closenic(ecx_portt *port)
141 {
142  // Nothing to do
143  return 0;
144 }
145 
151 void ec_setupheader(void *p)
152 {
153  ec_etherheadert *bp;
154  bp = p;
155  bp->da0 = oshw_htons(0xffff);
156  bp->da1 = oshw_htons(0xffff);
157  bp->da2 = oshw_htons(0xffff);
158  bp->sa0 = oshw_htons(priMAC[0]);
159  bp->sa1 = oshw_htons(priMAC[1]);
160  bp->sa2 = oshw_htons(priMAC[2]);
161  bp->etype = oshw_htons(ETH_P_ECAT);
162 }
163 
169 {
170  int idx;
171  int cnt = 0;
172 
173  ee_port_lock();
174 
175  idx = port->lastidx + 1;
176  /* index can't be larger than buffer array */
177  if (idx >= EC_MAXBUF)
178  idx = 0;
179 
180  /* try to find unused index */
181  while ((port->rxbufstat[idx] != EC_BUF_EMPTY) && (cnt < EC_MAXBUF)) {
182  idx++;
183  cnt++;
184  if (idx >= EC_MAXBUF)
185  idx = 0;
186  }
187  port->rxbufstat[idx] = EC_BUF_ALLOC;
188  if (port->redstate != ECT_RED_NONE)
189  port->redport->rxbufstat[idx] = EC_BUF_ALLOC;
190  port->lastidx = idx;
191 
192  ee_port_unlock();
193 
194  return idx;
195 }
196 
202 void ecx_setbufstat(ecx_portt *port, int idx, int bufstat)
203 {
204  port->rxbufstat[idx] = bufstat;
205  if (port->redstate != ECT_RED_NONE)
206  port->redport->rxbufstat[idx] = bufstat;
207 }
208 
215 int ecx_outframe(ecx_portt *port, int idx, int stacknumber)
216 {
217  int lp;
218  ec_stackT *stack;
219 
220  if (!stacknumber)
221  stack = &(port->stack);
222  else
223  stack = &(port->redport->stack);
224  lp = (*stack->txbuflength)[idx];
225  (*stack->rxbufstat)[idx] = EC_BUF_TX;
226 
227  eth_send_packet(port->dev_id, (*stack->txbuf)[idx], lp, 1);
228 
229  return 1;
230 }
231 
237 int ecx_outframe_red(ecx_portt *port, int idx)
238 {
239  ec_comt *datagramP;
240  ec_etherheadert *ehp;
241  int rval;
242 
243  ehp = (ec_etherheadert *)&(port->txbuf[idx]);
244  /* rewrite MAC source address 1 to primary */
245  ehp->sa1 = oshw_htons(priMAC[1]);
246  /* transmit over primary socket*/
247  rval = ecx_outframe(port, idx, 0);
248  if (port->redstate != ECT_RED_NONE) {
249  ee_port_lock();
250  ehp = (ec_etherheadert *)&(port->txbuf2);
251  /* use dummy frame for secondary socket transmit (BRD) */
252  datagramP = (ec_comt*)&(port->txbuf2[ETH_HEADERSIZE]);
253  /* write index to frame */
254  datagramP->index = idx;
255  /* rewrite MAC source address 1 to secondary */
256  ehp->sa1 = oshw_htons(secMAC[1]);
257  /* transmit over secondary socket */
258  port->redport->rxbufstat[idx] = EC_BUF_TX;
259  eth_send_packet(port->dev_id, &(port->txbuf2), port->txbuflength2, 1);
260  ee_port_unlock();
261  }
262 
263  return rval;
264 }
265 
271 static int ecx_recvpkt(ecx_portt *port, int stacknumber)
272 {
273  int lp, bytesrx;
274  ec_stackT *stack;
275 
276  if (!stacknumber)
277  stack = &(port->stack);
278  else
279  stack = &(port->redport->stack);
280  lp = sizeof(port->tempinbuf);
281  bytesrx = eth_receive_packet(port->dev_id, (*stack->tempbuf), lp, 1, 0);
282  port->tempinbufs = bytesrx;
283 
284  return (bytesrx > 0);
285 }
286 
303 int ecx_inframe(ecx_portt *port, int idx, int stacknumber)
304 {
305  uint16 l;
306  int rval;
307  int idxf;
308  ec_etherheadert *ehp;
309  ec_comt *ecp;
310  ec_stackT *stack;
311  ec_bufT *rxbuf;
312 
313  if (!stacknumber)
314  stack = &(port->stack);
315  else
316  stack = &(port->redport->stack);
317  rval = EC_NOFRAME;
318  rxbuf = &(*stack->rxbuf)[idx];
319  /* check if requested index is already in buffer ? */
320  if ((idx < EC_MAXBUF) && ((*stack->rxbufstat)[idx] == EC_BUF_RCVD)) {
321  l = (*rxbuf)[0] + ((uint16)((*rxbuf)[1] & 0x0f) << 8);
322  /* return WKC */
323  rval = ((*rxbuf)[l] + ((uint16)(*rxbuf)[l + 1] << 8));
324  /* mark as completed */
325  (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
326  } else {
327  ee_port_lock();
328  /* non blocking call to retrieve frame from socket */
329 
330 
331  while (1) {
332  if (ecx_recvpkt(port, stacknumber)) {
333  rval = EC_OTHERFRAME;
334  ehp =(ec_etherheadert*)(stack->tempbuf);
335  /* check if it is an EtherCAT frame */
336  if (ehp->etype == oshw_htons(ETH_P_ECAT)) {
337  ecp =(ec_comt*)(&(*stack->tempbuf)[ETH_HEADERSIZE]);
338  l = etohs(ecp->elength) & 0x0fff;
339  idxf = ecp->index;
340  /* found index equals requested index ? */
341  if (idxf == idx) {
342  /* yes, put it in the buffer array (strip ethernet header) */
343  memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idx] - ETH_HEADERSIZE);
344  /* return WKC */
345  rval = ((*rxbuf)[l] + ((uint16)((*rxbuf)[l + 1]) << 8));
346  /* mark as completed */
347  (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
348  /* store MAC source word 1 for redundant routing info */
349  (*stack->rxsa)[idx] = oshw_ntohs(ehp->sa1);
350  break;
351  } else if (idxf < EC_MAXBUF && (*stack->rxbufstat)[idxf] == EC_BUF_TX) {
352  rxbuf = &(*stack->rxbuf)[idxf];
353  /* put it in the buffer array (strip ethernet header) */
354  memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idxf] - ETH_HEADERSIZE);
355  /* mark as received */
356  (*stack->rxbufstat)[idxf] = EC_BUF_RCVD;
357  (*stack->rxsa)[idxf] = oshw_ntohs(ehp->sa1);
358  break;
359  } else {
360  OSEE_PRINT("ecx_inframe(): WARNING: strange things happened\n");
361  /* strange things happened */
362  }
363  } else {
364  OSEE_PRINT("ecx_inframe(): WARNING it is NOT an EtherCAT frame!\n");
365  }
366  } else {
367  // WARNING: no messages received.
368  break;
369  }
370  }
371 
372  ee_port_unlock();
373 
374  }
375 
376  /* WKC if matching frame found */
377  return rval;
378 }
379 
392 static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert *timer)
393 {
394  osal_timert timer2;
395  int wkc = EC_NOFRAME;
396  int wkc2 = EC_NOFRAME;
397  int primrx, secrx;
398 
399  /* if not in redundant mode then always assume secondary is OK */
400  if (port->redstate == ECT_RED_NONE)
401  wkc2 = 0;
402  do {
403  /* only read frame if not already in */
404  if (wkc <= EC_NOFRAME)
405  wkc = ecx_inframe(port, idx, 0);
406  /* only try secondary if in redundant mode */
407  if (port->redstate != ECT_RED_NONE) {
408  /* only read frame if not already in */
409  if (wkc2 <= EC_NOFRAME)
410  wkc2 = ecx_inframe(port, idx, 1);
411  }
412  /* wait for both frames to arrive or timeout */
413  } while (((wkc <= EC_NOFRAME) || (wkc2 <= EC_NOFRAME)) && !osal_timer_is_expired(timer));
414  /* only do redundant functions when in redundant mode */
415  if (port->redstate != ECT_RED_NONE) {
416  /* primrx if the received MAC source on primary socket */
417  primrx = 0;
418  if (wkc > EC_NOFRAME) primrx = port->rxsa[idx];
419  /* secrx if the received MAC source on psecondary socket */
420  secrx = 0;
421  if (wkc2 > EC_NOFRAME) secrx = port->redport->rxsa[idx];
422 
423  /* primary socket got secondary frame and secondary socket got primary frame */
424  /* normal situation in redundant mode */
425  if ( ((primrx == RX_SEC) && (secrx == RX_PRIM)) ) {
426  /* copy secondary buffer to primary */
427  memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
428  wkc = wkc2;
429  }
430  /* primary socket got nothing or primary frame, and secondary socket got secondary frame */
431  /* we need to resend TX packet */
432  if ( ((primrx == 0) && (secrx == RX_SEC)) ||
433  ((primrx == RX_PRIM) && (secrx == RX_SEC)) ) {
434  /* If both primary and secondary have partial connection retransmit the primary received
435  * frame over the secondary socket. The result from the secondary received frame is a combined
436  * frame that traversed all slaves in standard order. */
437  if ( (primrx == RX_PRIM) && (secrx == RX_SEC) ) {
438  /* copy primary rx to tx buffer */
439  memcpy(&(port->txbuf[idx][ETH_HEADERSIZE]), &(port->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
440  }
441  osal_timer_start (&timer2, EC_TIMEOUTRET);
442  /* resend secondary tx */
443  ecx_outframe(port, idx, 1);
444  do {
445  /* retrieve frame */
446  wkc2 = ecx_inframe(port, idx, 1);
447  } while ((wkc2 <= EC_NOFRAME) && !osal_timer_is_expired(&timer2));
448  if (wkc2 > EC_NOFRAME) {
449  /* copy secondary result to primary rx buffer */
450  memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
451  wkc = wkc2;
452  }
453  }
454  }
455 
456  /* return WKC or EC_NOFRAME */
457  return wkc;
458 }
459 
467 int ecx_waitinframe(ecx_portt *port, int idx, int timeout)
468 {
469  int wkc;
470  osal_timert timer;
471 
472  osal_timer_start (&timer, timeout);
473  wkc = ecx_waitinframe_red(port, idx, &timer);
474 
475  return wkc;
476 }
477 
490 int ecx_srconfirm(ecx_portt *port, int idx, int timeout)
491 {
492  int wkc = EC_NOFRAME;
493  osal_timert timer1, timer2;
494 
495  osal_timer_start (&timer1, timeout);
496  do {
497  /* tx frame on primary and if in redundant mode a dummy on secondary */
498  ecx_outframe_red(port, idx);
499  if (timeout < EC_TIMEOUTRET) {
500  osal_timer_start (&timer2, timeout);
501  } else {
502  /* normally use partial timeout for rx */
503  osal_timer_start (&timer2, EC_TIMEOUTRET);
504  }
505  /* get frame from primary or if in redundant mode possibly
506  from secondary */
507  wkc = ecx_waitinframe_red(port, idx, &timer2);
508  /* wait for answer with WKC>=0 or otherwise retry until timeout */
509  } while ((wkc <= EC_NOFRAME) && !osal_timer_is_expired (&timer1));
510 
511 
512  return wkc;
513 }
514 
515 
516 #ifdef EC_VER1
517 int ec_setupnic(const char *ifname, int secondary)
518 {
519  return ecx_setupnic(&ecx_port, ifname, secondary);
520 }
521 
522 int ec_closenic(void)
523 {
524  return ecx_closenic(&ecx_port);
525 }
526 
527 int ec_getindex(void)
528 {
529  return ecx_getindex(&ecx_port);
530 }
531 
532 void ec_setbufstat(int idx, int bufstat)
533 {
534  ecx_setbufstat(&ecx_port, idx, bufstat);
535 }
536 
537 int ec_outframe(int idx, int stacknumber)
538 {
539  return ecx_outframe(&ecx_port, idx, stacknumber);
540 }
541 
542 int ec_outframe_red(int idx)
543 {
544  return ecx_outframe_red(&ecx_port, idx);
545 }
546 
547 int ec_inframe(int idx, int stacknumber)
548 {
549  return ecx_inframe(&ecx_port, idx, stacknumber);
550 }
551 
552 int ec_waitinframe(int idx, int timeout)
553 {
554  return ecx_waitinframe(&ecx_port, idx, timeout);
555 }
556 
557 int ec_srconfirm(int idx, int timeout)
558 {
559  return ecx_srconfirm(&ecx_port, idx, timeout);
560 }
561 #endif
void ee_port_unlock(void)
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)
#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
ec_bufT * tempbuf
Definition: erika/nicdrv.h:28
static int ecx_recvpkt(ecx_portt *port, int stacknumber)
Definition: erika/nicdrv.c:271
uint16 oshw_ntohs(uint16 network)
Definition: erika/oshw.c:43
int txbuflength2
Definition: erika/nicdrv.h:74
uint16_t uint16
Definition: osal.h:29
int ecx_closenic(ecx_portt *port)
Definition: erika/nicdrv.c:140
static void ecx_clear_rxbufstat(int *rxbufstat)
Definition: erika/nicdrv.c:77
uint16 oshw_htons(uint16 host)
Definition: erika/oshw.c:31
#define etohs(A)
Definition: ethercattype.h:536
static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert *timer)
Definition: erika/nicdrv.c:392
#define ETH_HEADERSIZE
Definition: ethercattype.h:103
int rxbufstat[EC_MAXBUF]
Definition: erika/nicdrv.h:45
int ecx_getindex(ecx_portt *port)
Definition: erika/nicdrv.c:168
int ecx_outframe(ecx_portt *port, int idx, int stacknumber)
Definition: erika/nicdrv.c:215
ec_stackT stack
Definition: erika/nicdrv.h:55
const uint16 priMAC[3]
Definition: erika/nicdrv.c:65
ec_bufT rxbuf[EC_MAXBUF]
Definition: erika/nicdrv.h:58
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
int ec_srconfirm(int idx, int timeout)
#define RX_SEC
Definition: erika/nicdrv.c:72
int tempinbufs
Definition: erika/nicdrv.h:66
ec_bufT(* txbuf)[EC_MAXBUF]
Definition: erika/nicdrv.h:24
int ecx_waitinframe(ecx_portt *port, int idx, int timeout)
Definition: erika/nicdrv.c:467
void ec_setbufstat(int idx, int bufstat)
ecx_redportt * redport
Definition: erika/nicdrv.h:80
PACKED_BEGIN struct PACKED ec_comt
Headerfile for ethercatbase.c.
void ee_port_lock(void)
int ecx_outframe_red(ecx_portt *port, int idx)
Definition: erika/nicdrv.c:237
#define EC_TIMEOUTRET
Definition: ethercattype.h:64
#define EC_OTHERFRAME
Definition: ethercattype.h:43
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 ecx_setupnic(ecx_portt *port, const char *ifname, int secondary)
Definition: erika/nicdrv.c:90
int rxbufstat[EC_MAXBUF]
Definition: erika/nicdrv.h:60
uint8 ec_bufT[EC_BUFSIZE]
Definition: ethercattype.h:87
int ec_closenic(void)
int ec_getindex(void)
int ecx_srconfirm(ecx_portt *port, int idx, int timeout)
Definition: erika/nicdrv.c:490
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
const uint16 secMAC[3]
Definition: erika/nicdrv.c:67
int * sock
Definition: erika/nicdrv.h:22
void ecx_setbufstat(ecx_portt *port, int idx, int bufstat)
Definition: erika/nicdrv.c:202
int ecx_inframe(ecx_portt *port, int idx, int stacknumber)
Definition: erika/nicdrv.c:303
void ec_setupheader(void *p)
Definition: erika/nicdrv.c:151
#define RX_PRIM
Definition: erika/nicdrv.c:70
uint8 rxbuf[1024]
Definition: eoe_test.c:50


soem
Author(s): Arthur Ketels and M.J.G. van den Molengraft
autogenerated on Sat Jun 27 2020 03:48:21