rtk/nicdrv.c
Go to the documentation of this file.
1 /*
2  * Simple Open EtherCAT Master Library
3  *
4  * File : nicdrv.c
5  * Version : 1.3.0
6  * Date : 24-02-2013
7  * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f.
8  * Copyright (C) 2005-2013 Arthur Ketels
9  * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven
10  *
11  * SOEM is free software; you can redistribute it and/or modify it under
12  * the terms of the GNU General Public License version 2 as published by the Free
13  * Software Foundation.
14  *
15  * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18  * for more details.
19  *
20  * As a special exception, if other files instantiate templates or use macros
21  * or inline functions from this file, or you compile this file and link it
22  * with other works to produce a work based on this file, this file does not
23  * by itself cause the resulting work to be covered by the GNU General Public
24  * License. However the source code for this file must still be made available
25  * in accordance with section (3) of the GNU General Public License.
26  *
27  * This exception does not invalidate any other reasons why a work based on
28  * this file might be covered by the GNU General Public License.
29  *
30  * The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual
31  * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for
32  * the sole purpose of creating, using and/or selling or otherwise distributing
33  * an EtherCAT network master provided that an EtherCAT Master License is obtained
34  * from Beckhoff Automation GmbH.
35  *
36  * In case you did not receive a copy of the EtherCAT Master License along with
37  * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany
38  * (www.beckhoff.com).
39  */
40 
68 #include <kern.h>
69 #include <ioctl.h>
70 #include <stdio.h>
71 #include <string.h>
72 
73 #include "osal.h"
74 #include "oshw.h"
75 
76 
77 #include "lw_mac/lw_emac.h"
78 
79 #ifndef MAX
80 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
81 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
82 #endif
83 
85 enum
86 {
91 };
92 
99 const uint16 priMAC[3] = { 0x0101, 0x0101, 0x0101 };
101 const uint16 secMAC[3] = { 0x0404, 0x0404, 0x0404 };
102 
104 #define RX_PRIM priMAC[1]
105 
106 #define RX_SEC secMAC[1]
107 
108 
115 int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary)
116 {
117  int i;
118  int rVal;
119  int *psock;
120 
121  port->getindex_mutex = mtx_create();
122  port->tx_mutex = mtx_create();
123  port->rx_mutex = mtx_create();
124 
125  rVal = bfin_EMAC_init((uint8_t *)priMAC);
126  if (rVal != 0)
127  return 0;
128 
129  if (secondary)
130  {
131  /* secondary port stuct available? */
132  if (port->redport)
133  {
134  /* when using secondary socket it is automatically a redundant setup */
135  psock = &(port->redport->sockhandle);
136  *psock = -1;
137  port->redstate = ECT_RED_DOUBLE;
138  port->redport->stack.sock = &(port->redport->sockhandle);
139  port->redport->stack.txbuf = &(port->txbuf);
140  port->redport->stack.txbuflength = &(port->txbuflength);
141  port->redport->stack.tempbuf = &(port->redport->tempinbuf);
142  port->redport->stack.rxbuf = &(port->redport->rxbuf);
143  port->redport->stack.rxbufstat = &(port->redport->rxbufstat);
144  port->redport->stack.rxsa = &(port->redport->rxsa);
145  }
146  else
147  {
148  /* fail */
149  return 0;
150  }
151  }
152  else
153  {
154  port->getindex_mutex = mtx_create();
155  port->tx_mutex = mtx_create();
156  port->rx_mutex = mtx_create();
157  port->sockhandle = -1;
158  port->lastidx = 0;
159  port->redstate = ECT_RED_NONE;
160  port->stack.sock = &(port->sockhandle);
161  port->stack.txbuf = &(port->txbuf);
162  port->stack.txbuflength = &(port->txbuflength);
163  port->stack.tempbuf = &(port->tempinbuf);
164  port->stack.rxbuf = &(port->rxbuf);
165  port->stack.rxbufstat = &(port->rxbufstat);
166  port->stack.rxsa = &(port->rxsa);
167  psock = &(port->sockhandle);
168  }
169 
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 
178  return 1;
179 }
180 
186 {
187  if (port->sockhandle >= 0)
188  {
189  close(port->sockhandle);
190  }
191  if ((port->redport) && (port->redport->sockhandle >= 0))
192  {
193  close(port->redport->sockhandle);
194  }
195  return 0;
196 }
197 
203 void ec_setupheader(void *p)
204 {
205  ec_etherheadert *bp;
206  bp = p;
207  bp->da0 = oshw_htons(0xffff);
208  bp->da1 = oshw_htons(0xffff);
209  bp->da2 = oshw_htons(0xffff);
210  bp->sa0 = oshw_htons(priMAC[0]);
211  bp->sa1 = oshw_htons(priMAC[1]);
212  bp->sa2 = oshw_htons(priMAC[2]);
213  bp->etype = oshw_htons(ETH_P_ECAT);
214 }
215 
221 {
222  int idx;
223  int cnt;
224 
225  mtx_lock (port->getindex_mutex);
226 
227  idx = port->lastidx + 1;
228  /* index can't be larger than buffer array */
229  if (idx >= EC_MAXBUF)
230  {
231  idx = 0;
232  }
233  cnt = 0;
234  /* try to find unused index */
235  while ((port->rxbufstat[idx] != EC_BUF_EMPTY) && (cnt < EC_MAXBUF))
236  {
237  idx++;
238  cnt++;
239  if (idx >= EC_MAXBUF)
240  {
241  idx = 0;
242  }
243  }
244  port->rxbufstat[idx] = EC_BUF_ALLOC;
245  if (port->redstate != ECT_RED_NONE)
246  {
247  port->redport->rxbufstat[idx] = EC_BUF_ALLOC;
248  }
249  port->lastidx = idx;
250 
251  mtx_unlock (port->getindex_mutex);
252 
253  return idx;
254 }
255 
261 void ecx_setbufstat(ecx_portt *port, int idx, int bufstat)
262 {
263  port->rxbufstat[idx] = bufstat;
264  if (port->redstate != ECT_RED_NONE)
265  {
266  port->redport->rxbufstat[idx] = bufstat;
267  }
268 }
269 
276 int ecx_outframe(ecx_portt *port, int idx, int stacknumber)
277 {
278  int lp, rval;
279  ec_stackT *stack;
280 
281  if (!stacknumber)
282  {
283  stack = &(port->stack);
284  }
285  else
286  {
287  stack = &(port->redport->stack);
288  }
289  lp = (*stack->txbuflength)[idx];
290  rval = bfin_EMAC_send((*stack->txbuf)[idx], lp);
291  (*stack->rxbufstat)[idx] = EC_BUF_TX;
292 
293  return rval;
294 }
295 
301 int ecx_outframe_red(ecx_portt *port, int idx)
302 {
303  ec_comt *datagramP;
304  ec_etherheadert *ehp;
305  int rval;
306 
307  ehp = (ec_etherheadert *)&(port->txbuf[idx]);
308  /* rewrite MAC source address 1 to primary */
309  ehp->sa1 = oshw_htons(priMAC[1]);
310  /* transmit over primary socket*/
311  rval = ecx_outframe(port, idx, 0);
312  if (port->redstate != ECT_RED_NONE)
313  {
314  mtx_lock (port->tx_mutex);
315  ehp = (ec_etherheadert *)&(port->txbuf2);
316  /* use dummy frame for secondary socket transmit (BRD) */
317  datagramP = (ec_comt*)&(port->txbuf2[ETH_HEADERSIZE]);
318  /* write index to frame */
319  datagramP->index = idx;
320  /* rewrite MAC source address 1 to secondary */
321  ehp->sa1 = oshw_htons(secMAC[1]);
322  /* transmit over secondary socket */
323  //send(sockhandle2, &ec_txbuf2, ec_txbuflength2 , 0);
324  // OBS! redundant not ACTIVE for BFIN, just added to compile
325  ASSERT (0);
326  bfin_EMAC_send(&(port->txbuf2), port->txbuflength2);
327  mtx_unlock (port->tx_mutex);
328  port->redport->rxbufstat[idx] = EC_BUF_TX;
329  }
330 
331  return rval;
332 }
333 
339 static int ecx_recvpkt(ecx_portt *port, int stacknumber)
340 {
341  int lp, bytesrx;
342  ec_stackT *stack;
343 
344  if (!stacknumber)
345  {
346  stack = &(port->stack);
347  }
348  else
349  {
350  stack = &(port->redport->stack);
351  }
352  lp = sizeof(port->tempinbuf);
353  bytesrx = bfin_EMAC_recv((*stack->tempbuf), lp);
354  port->tempinbufs = bytesrx;
355 
356  return (bytesrx > 0);
357 }
358 
375 int ecx_inframe(ecx_portt *port, int idx, int stacknumber)
376 {
377  uint16 l;
378  int rval;
379  uint8 idxf;
380  ec_etherheadert *ehp;
381  ec_comt *ecp;
382  ec_stackT *stack;
383  ec_bufT *rxbuf;
384 
385  if (!stacknumber)
386  {
387  stack = &(port->stack);
388  }
389  else
390  {
391  stack = &(port->redport->stack);
392  }
393  rval = EC_NOFRAME;
394  rxbuf = &(*stack->rxbuf)[idx];
395  /* check if requested index is already in buffer ? */
396  if ((idx < EC_MAXBUF) && ( (*stack->rxbufstat)[idx] == EC_BUF_RCVD))
397  {
398  l = (*rxbuf)[0] + ((uint16)((*rxbuf)[1] & 0x0f) << 8);
399  /* return WKC */
400  rval = ((*rxbuf)[l] + ((uint16)(*rxbuf)[l + 1] << 8));
401  /* mark as completed */
402  (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
403  }
404  else
405  {
406  mtx_lock (port->rx_mutex);
407  /* non blocking call to retrieve frame from socket */
408  if (ecx_recvpkt(port, stacknumber))
409  {
410  rval = EC_OTHERFRAME;
411  ehp =(ec_etherheadert*)(stack->tempbuf);
412  /* check if it is an EtherCAT frame */
413  if (ehp->etype == oshw_htons(ETH_P_ECAT))
414  {
415  ecp =(ec_comt*)(&(*stack->tempbuf)[ETH_HEADERSIZE]);
416  l = etohs(ecp->elength) & 0x0fff;
417  idxf = ecp->index;
418  /* found index equals reqested index ? */
419  if (idxf == idx)
420  {
421  /* yes, put it in the buffer array (strip ethernet header) */
422  memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idx] - ETH_HEADERSIZE);
423  /* return WKC */
424  rval = ((*rxbuf)[l] + ((uint16)((*rxbuf)[l + 1]) << 8));
425  /* mark as completed */
426  (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
427  /* store MAC source word 1 for redundant routing info */
428  (*stack->rxsa)[idx] = oshw_ntohs(ehp->sa1);
429  }
430  else
431  {
432  /* check if index exist? */
433  if (idxf < EC_MAXBUF)
434  {
435  rxbuf = &(*stack->rxbuf)[idxf];
436  /* put it in the buffer array (strip ethernet header) */
437  memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idxf] - ETH_HEADERSIZE);
438  /* mark as received */
439  (*stack->rxbufstat)[idxf] = EC_BUF_RCVD;
440  (*stack->rxsa)[idxf] = oshw_ntohs(ehp->sa1);
441  }
442  else
443  {
444  /* strange things happend */
445  }
446  }
447  }
448  }
449  mtx_unlock (port->rx_mutex);
450 
451  }
452 
453  /* WKC if mathing frame found */
454  return rval;
455 }
456 
469 static int ecx_waitinframe_red(ecx_portt *port, int idx, const osal_timert timer)
470 {
471  int wkc = EC_NOFRAME;
472  int wkc2 = EC_NOFRAME;
473  int primrx, secrx;
474 
475  /* if not in redundant mode then always assume secondary is OK */
476  if (port->redstate == ECT_RED_NONE)
477  {
478  wkc2 = 0;
479  }
480  do
481  {
482  /* only read frame if not already in */
483  if (wkc <= EC_NOFRAME)
484  {
485  wkc = ecx_inframe(port, idx, 0);
486  }
487  /* only try secondary if in redundant mode */
488  if (port->redstate != ECT_RED_NONE)
489  {
490  /* only read frame if not already in */
491  if (wkc2 <= EC_NOFRAME)
492  wkc2 = ecx_inframe(port, idx, 1);
493  }
494  /* wait for both frames to arrive or timeout */
495  } while (((wkc <= EC_NOFRAME) || (wkc2 <= EC_NOFRAME)) && (osal_timer_is_expired(&timer) == FALSE));
496  /* only do redundant functions when in redundant mode */
497  if (port->redstate != ECT_RED_NONE)
498  {
499  /* primrx if the reveived MAC source on primary socket */
500  primrx = 0;
501  if (wkc > EC_NOFRAME)
502  {
503  primrx = port->rxsa[idx];
504  }
505  /* secrx if the reveived MAC source on psecondary socket */
506  secrx = 0;
507  if (wkc2 > EC_NOFRAME)
508  {
509  secrx = port->redport->rxsa[idx];
510  }
511  /* primary socket got secondary frame and secondary socket got primary frame */
512  /* normal situation in redundant mode */
513  if ( ((primrx == RX_SEC) && (secrx == RX_PRIM)) )
514  {
515  /* copy secondary buffer to primary */
516  memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
517  wkc = wkc2;
518  }
519  /* primary socket got nothing or primary frame, and secondary socket got secondary frame */
520  /* we need to resend TX packet */
521  if ( ((primrx == 0) && (secrx == RX_SEC)) ||
522  ((primrx == RX_PRIM) && (secrx == RX_SEC)) )
523  {
524  osal_timert read_timer;
525 
526  /* If both primary and secondary have partial connection retransmit the primary received
527  * frame over the secondary socket. The result from the secondary received frame is a combined
528  * frame that traversed all slaves in standard order. */
529  if ( (primrx == RX_PRIM) && (secrx == RX_SEC) )
530  {
531  /* copy primary rx to tx buffer */
532  memcpy(&(port->txbuf[idx][ETH_HEADERSIZE]), &(port->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
533  }
534  osal_timer_start(&read_timer, EC_TIMEOUTRET);
535  /* resend secondary tx */
536  ecx_outframe(port, idx, 1);
537  do
538  {
539  /* retrieve frame */
540  wkc2 = ecx_inframe(port, idx, 1);
541  } while ((wkc2 <= EC_NOFRAME) && (osal_timer_is_expired(&read_timer) == FALSE));
542  if (wkc2 > EC_NOFRAME)
543  {
544  /* copy secondary result to primary rx buffer */
545  memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
546  wkc = wkc2;
547  }
548  }
549  }
550 
551  /* return WKC or EC_NOFRAME */
552  return wkc;
553 }
554 
562 int ecx_waitinframe(ecx_portt *port, int idx, int timeout)
563 {
564  int wkc;
565  osal_timert timer;
566 
567  osal_timer_start (&timer, timeout);
568  wkc = ecx_waitinframe_red(port, idx, timer);
569  /* if nothing received, clear buffer index status so it can be used again */
570  if (wkc <= EC_NOFRAME)
571  {
572  ecx_setbufstat(port, idx, EC_BUF_EMPTY);
573  }
574 
575  return wkc;
576 }
577 
590 int ecx_srconfirm(ecx_portt *port, int idx, int timeout)
591 {
592  int wkc = EC_NOFRAME;
593  osal_timert timer;
594 
595  osal_timer_start(&timer, timeout);
596  do
597  {
598  osal_timert read_timer;
599 
600  /* tx frame on primary and if in redundant mode a dummy on secondary */
601  ecx_outframe_red(port, idx);
602  osal_timer_start(&read_timer, MIN(timeout, EC_TIMEOUTRET));
603  /* get frame from primary or if in redundant mode possibly from secondary */
604  wkc = ecx_waitinframe_red(port, idx, read_timer);
605  /* wait for answer with WKC>0 or otherwise retry until timeout */
606  } while ((wkc <= EC_NOFRAME) && (osal_timer_is_expired(&timer) == FALSE));
607  /* if nothing received, clear buffer index status so it can be used again */
608  if (wkc <= EC_NOFRAME)
609  {
610  ecx_setbufstat(port, idx, EC_BUF_EMPTY);
611  }
612 
613  return wkc;
614 }
615 
616 
617 #ifdef EC_VER1
618 int ec_setupnic(const char *ifname, int secondary)
619 {
620  return ecx_setupnic(&ecx_port, ifname, secondary);
621 }
622 
623 int ec_closenic(void)
624 {
625  return ecx_closenic(&ecx_port);
626 }
627 
628 int ec_getindex(void)
629 {
630  return ecx_getindex(&ecx_port);
631 }
632 
633 void ec_setbufstat(int idx, int bufstat)
634 {
635  ecx_setbufstat(&ecx_port, idx, bufstat);
636 }
637 
638 int ec_outframe(int idx, int stacknumber)
639 {
640  return ecx_outframe(&ecx_port, idx, stacknumber);
641 }
642 
643 int ec_outframe_red(int idx)
644 {
645  return ecx_outframe_red(&ecx_port, idx);
646 }
647 
648 int ec_inframe(int idx, int stacknumber)
649 {
650  return ecx_inframe(&ecx_port, idx, stacknumber);
651 }
652 
653 int ec_waitinframe(int idx, int timeout)
654 {
655  return ecx_waitinframe(&ecx_port, idx, timeout);
656 }
657 
658 int ec_srconfirm(int idx, int timeout)
659 {
660  return ecx_srconfirm(&ecx_port, idx, timeout);
661 }
662 #endif
663 
ec_bufT rxbuf[EC_MAXBUF]
Definition: linux/nicdrv.h:81
int rxsa[EC_MAXBUF]
Definition: linux/nicdrv.h:85
ec_bufT txbuf[EC_MAXBUF]
Definition: linux/nicdrv.h:106
int(* rxsa)[EC_MAXBUF]
Definition: linux/nicdrv.h:72
int txbuflength[EC_MAXBUF]
Definition: linux/nicdrv.h:108
int ecx_outframe_red(ecx_portt *port, int idx)
Definition: rtk/nicdrv.c:301
void ecx_setbufstat(ecx_portt *port, int idx, int bufstat)
Definition: rtk/nicdrv.c:261
int bfin_EMAC_recv(uint8_t *packet, size_t size)
Definition: lw_emac.c:384
#define EC_MAXBUF
Definition: ethercattype.h:88
uint8_t uint8
Definition: osal.h:33
const uint16 secMAC[3]
Definition: rtk/nicdrv.c:101
ec_bufT txbuf2
Definition: linux/nicdrv.h:110
int rxsa[EC_MAXBUF]
Definition: linux/nicdrv.h:100
int(* txbuflength)[EC_MAXBUF]
Definition: linux/nicdrv.h:64
uint16 oshw_ntohs(uint16 networkshort)
Definition: linux/oshw.c:48
PACKED_BEGIN struct PACKED ec_etherheadert
void ec_setupheader(void *p)
Definition: rtk/nicdrv.c:203
ec_bufT * tempbuf
Definition: linux/nicdrv.h:66
int txbuflength2
Definition: linux/nicdrv.h:112
uint16_t uint16
Definition: osal.h:34
static int ecx_recvpkt(ecx_portt *port, int stacknumber)
Definition: rtk/nicdrv.c:339
unsigned char uint8_t
Definition: stdint.h:78
int ecx_outframe(ecx_portt *port, int idx, int stacknumber)
Definition: rtk/nicdrv.c:276
int ecx_inframe(ecx_portt *port, int idx, int stacknumber)
Definition: rtk/nicdrv.c:375
boolean osal_timer_is_expired(osal_timert *self)
Definition: linux/osal.c:78
#define etohs(A)
Definition: ethercattype.h:550
#define ETH_HEADERSIZE
Definition: ethercattype.h:127
int rxbufstat[EC_MAXBUF]
Definition: linux/nicdrv.h:83
int bfin_EMAC_init(uint8_t *enetaddr)
Definition: lw_emac.c:288
ec_stackT stack
Definition: linux/nicdrv.h:93
int bfin_EMAC_send(void *packet, int length)
Definition: lw_emac.c:354
ec_bufT rxbuf[EC_MAXBUF]
Definition: linux/nicdrv.h:96
pthread_mutex_t tx_mutex
Definition: linux/nicdrv.h:120
ec_stackT stack
Definition: linux/nicdrv.h:78
ec_bufT tempinbuf
Definition: linux/nicdrv.h:102
ec_bufT(* rxbuf)[EC_MAXBUF]
Definition: linux/nicdrv.h:68
int ecx_closenic(ecx_portt *port)
Definition: rtk/nicdrv.c:185
int tempinbufs
Definition: linux/nicdrv.h:104
#define FALSE
Definition: osal.h:29
ec_bufT(* txbuf)[EC_MAXBUF]
Definition: linux/nicdrv.h:62
ecx_redportt * redport
Definition: linux/nicdrv.h:118
int ecx_srconfirm(ecx_portt *port, int idx, int timeout)
Definition: rtk/nicdrv.c:590
PACKED_BEGIN struct PACKED ec_comt
int sockhandle
Definition: linux/nicdrv.h:94
int ecx_getindex(ecx_portt *port)
Definition: rtk/nicdrv.c:220
void osal_timer_start(osal_timert *self, uint32 timeout_us)
Definition: linux/osal.c:63
int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary)
Definition: rtk/nicdrv.c:115
#define EC_TIMEOUTRET
Definition: ethercattype.h:90
#define EC_OTHERFRAME
Definition: ethercattype.h:75
pthread_mutex_t getindex_mutex
Definition: linux/nicdrv.h:119
#define ETH_P_ECAT
Definition: ethercattype.h:475
#define RX_SEC
Definition: rtk/nicdrv.c:106
int rxbufstat[EC_MAXBUF]
Definition: linux/nicdrv.h:98
uint8 ec_bufT[EC_BUFSIZE]
Definition: ethercattype.h:111
ec_bufT tempinbuf
Definition: linux/nicdrv.h:87
#define RX_PRIM
Definition: rtk/nicdrv.c:104
static int ecx_waitinframe_red(ecx_portt *port, int idx, const osal_timert timer)
Definition: rtk/nicdrv.c:469
const uint16 priMAC[3]
Definition: rtk/nicdrv.c:99
int(* rxbufstat)[EC_MAXBUF]
Definition: linux/nicdrv.h:70
#define EC_NOFRAME
Definition: ethercattype.h:73
int * sock
Definition: linux/nicdrv.h:60
int ecx_waitinframe(ecx_portt *port, int idx, int timeout)
Definition: rtk/nicdrv.c:562
uint16 oshw_htons(uint16 hostshort)
Definition: linux/oshw.c:36
pthread_mutex_t rx_mutex
Definition: linux/nicdrv.h:121
#define MIN(a, b)
Definition: rtk/nicdrv.c:81


youbot_driver
Author(s): Jan Paulus
autogenerated on Mon Jun 10 2019 15:46:24