linux/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 <sys/types.h>
69 #include <sys/ioctl.h>
70 #include <net/if.h>
71 #include <sys/socket.h>
72 #include <unistd.h>
73 #include <sys/time.h>
74 #include <time.h>
75 #include <arpa/inet.h>
76 #include <stdio.h>
77 #include <fcntl.h>
78 #include <string.h>
79 #include <netpacket/packet.h>
80 #include <pthread.h>
81 
82 #include "oshw.h"
83 #include "osal.h"
84 
86 enum
87 {
92 };
93 
94 
101 const uint16 priMAC[3] = { 0x0101, 0x0101, 0x0101 };
103 const uint16 secMAC[3] = { 0x0404, 0x0404, 0x0404 };
104 
106 #define RX_PRIM priMAC[1]
107 
108 #define RX_SEC secMAC[1]
109 
116 int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary)
117 {
118  int i;
119  int r, rval, ifindex;
120  struct timeval timeout;
121  struct ifreq ifr;
122  struct sockaddr_ll sll;
123  int *psock;
124 
125  rval = 0;
126  if (secondary)
127  {
128  /* secondary port stuct available? */
129  if (port->redport)
130  {
131  /* when using secondary socket it is automatically a redundant setup */
132  psock = &(port->redport->sockhandle);
133  *psock = -1;
134  port->redstate = ECT_RED_DOUBLE;
135  port->redport->stack.sock = &(port->redport->sockhandle);
136  port->redport->stack.txbuf = &(port->txbuf);
137  port->redport->stack.txbuflength = &(port->txbuflength);
138  port->redport->stack.tempbuf = &(port->redport->tempinbuf);
139  port->redport->stack.rxbuf = &(port->redport->rxbuf);
140  port->redport->stack.rxbufstat = &(port->redport->rxbufstat);
141  port->redport->stack.rxsa = &(port->redport->rxsa);
142  }
143  else
144  {
145  /* fail */
146  return 0;
147  }
148  }
149  else
150  {
151  pthread_mutex_init(&(port->getindex_mutex), NULL);
152  pthread_mutex_init(&(port->tx_mutex) , NULL);
153  pthread_mutex_init(&(port->rx_mutex) , NULL);
154  port->sockhandle = -1;
155  port->lastidx = 0;
156  port->redstate = ECT_RED_NONE;
157  port->stack.sock = &(port->sockhandle);
158  port->stack.txbuf = &(port->txbuf);
159  port->stack.txbuflength = &(port->txbuflength);
160  port->stack.tempbuf = &(port->tempinbuf);
161  port->stack.rxbuf = &(port->rxbuf);
162  port->stack.rxbufstat = &(port->rxbufstat);
163  port->stack.rxsa = &(port->rxsa);
164  psock = &(port->sockhandle);
165  }
166  /* we use RAW packet socket, with packet type ETH_P_ECAT */
167  *psock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ECAT));
168 
169  timeout.tv_sec = 0;
170  timeout.tv_usec = 1;
171  r = setsockopt(*psock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
172  r = setsockopt(*psock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
173  i = 1;
174  r = setsockopt(*psock, SOL_SOCKET, SO_DONTROUTE, &i, sizeof(i));
175  /* connect socket to NIC by name */
176  strcpy(ifr.ifr_name, ifname);
177  r = ioctl(*psock, SIOCGIFINDEX, &ifr);
178  ifindex = ifr.ifr_ifindex;
179  strcpy(ifr.ifr_name, ifname);
180  ifr.ifr_flags = 0;
181  /* reset flags of NIC interface */
182  r = ioctl(*psock, SIOCGIFFLAGS, &ifr);
183  /* set flags of NIC interface, here promiscuous and broadcast */
184  ifr.ifr_flags = ifr.ifr_flags || IFF_PROMISC || IFF_BROADCAST;
185  r = ioctl(*psock, SIOCGIFFLAGS, &ifr);
186  /* bind socket to protocol, in this case RAW EtherCAT */
187  sll.sll_family = AF_PACKET;
188  sll.sll_ifindex = ifindex;
189  sll.sll_protocol = htons(ETH_P_ECAT);
190  r = bind(*psock, (struct sockaddr *)&sll, sizeof(sll));
191  /* setup ethernet headers in tx buffers so we don't have to repeat it */
192  for (i = 0; i < EC_MAXBUF; i++)
193  {
194  ec_setupheader(&(port->txbuf[i]));
195  port->rxbufstat[i] = EC_BUF_EMPTY;
196  }
197  ec_setupheader(&(port->txbuf2));
198  if (r == 0) rval = 1;
199 
200  return rval;
201 }
202 
208 {
209  if (port->sockhandle >= 0)
210  close(port->sockhandle);
211  if ((port->redport) && (port->redport->sockhandle >= 0))
212  close(port->redport->sockhandle);
213 
214  return 0;
215 }
216 
222 void ec_setupheader(void *p)
223 {
224  ec_etherheadert *bp;
225  bp = p;
226  bp->da0 = htons(0xffff);
227  bp->da1 = htons(0xffff);
228  bp->da2 = htons(0xffff);
229  bp->sa0 = htons(priMAC[0]);
230  bp->sa1 = htons(priMAC[1]);
231  bp->sa2 = htons(priMAC[2]);
232  bp->etype = htons(ETH_P_ECAT);
233 }
234 
240 {
241  int idx;
242  int cnt;
243 
244  pthread_mutex_lock( &(port->getindex_mutex) );
245 
246  idx = port->lastidx + 1;
247  /* index can't be larger than buffer array */
248  if (idx >= EC_MAXBUF)
249  {
250  idx = 0;
251  }
252  cnt = 0;
253  /* try to find unused index */
254  while ((port->rxbufstat[idx] != EC_BUF_EMPTY) && (cnt < EC_MAXBUF))
255  {
256  idx++;
257  cnt++;
258  if (idx >= EC_MAXBUF)
259  {
260  idx = 0;
261  }
262  }
263  port->rxbufstat[idx] = EC_BUF_ALLOC;
264  if (port->redstate != ECT_RED_NONE)
265  port->redport->rxbufstat[idx] = EC_BUF_ALLOC;
266  port->lastidx = idx;
267 
268  pthread_mutex_unlock( &(port->getindex_mutex) );
269 
270  return idx;
271 }
272 
278 void ecx_setbufstat(ecx_portt *port, int idx, int bufstat)
279 {
280  port->rxbufstat[idx] = bufstat;
281  if (port->redstate != ECT_RED_NONE)
282  port->redport->rxbufstat[idx] = bufstat;
283 }
284 
291 int ecx_outframe(ecx_portt *port, int idx, int stacknumber)
292 {
293  int lp, rval;
294  ec_stackT *stack;
295 
296  if (!stacknumber)
297  {
298  stack = &(port->stack);
299  }
300  else
301  {
302  stack = &(port->redport->stack);
303  }
304  lp = (*stack->txbuflength)[idx];
305  rval = send(*stack->sock, (*stack->txbuf)[idx], lp, 0);
306  (*stack->rxbufstat)[idx] = EC_BUF_TX;
307 
308  return rval;
309 }
310 
316 int ecx_outframe_red(ecx_portt *port, int idx)
317 {
318  ec_comt *datagramP;
319  ec_etherheadert *ehp;
320  int rval;
321 
322  ehp = (ec_etherheadert *)&(port->txbuf[idx]);
323  /* rewrite MAC source address 1 to primary */
324  ehp->sa1 = htons(priMAC[1]);
325  /* transmit over primary socket*/
326  rval = ecx_outframe(port, idx, 0);
327  if (port->redstate != ECT_RED_NONE)
328  {
329  pthread_mutex_lock( &(port->tx_mutex) );
330  ehp = (ec_etherheadert *)&(port->txbuf2);
331  /* use dummy frame for secondary socket transmit (BRD) */
332  datagramP = (ec_comt*)&(port->txbuf2[ETH_HEADERSIZE]);
333  /* write index to frame */
334  datagramP->index = idx;
335  /* rewrite MAC source address 1 to secondary */
336  ehp->sa1 = htons(secMAC[1]);
337  /* transmit over secondary socket */
338  send(port->redport->sockhandle, &(port->txbuf2), port->txbuflength2 , 0);
339  pthread_mutex_unlock( &(port->tx_mutex) );
340  port->redport->rxbufstat[idx] = EC_BUF_TX;
341  }
342 
343  return rval;
344 }
345 
351 static int ecx_recvpkt(ecx_portt *port, int stacknumber)
352 {
353  int lp, bytesrx;
354  ec_stackT *stack;
355 
356  if (!stacknumber)
357  {
358  stack = &(port->stack);
359  }
360  else
361  {
362  stack = &(port->redport->stack);
363  }
364  lp = sizeof(port->tempinbuf);
365  bytesrx = recv(*stack->sock, (*stack->tempbuf), lp, 0);
366  port->tempinbufs = bytesrx;
367 
368  return (bytesrx > 0);
369 }
370 
387 int ecx_inframe(ecx_portt *port, int idx, int stacknumber)
388 {
389  uint16 l;
390  int rval;
391  int idxf;
392  ec_etherheadert *ehp;
393  ec_comt *ecp;
394  ec_stackT *stack;
395  ec_bufT *rxbuf;
396 
397  if (!stacknumber)
398  {
399  stack = &(port->stack);
400  }
401  else
402  {
403  stack = &(port->redport->stack);
404  }
405  rval = EC_NOFRAME;
406  rxbuf = &(*stack->rxbuf)[idx];
407  /* check if requested index is already in buffer ? */
408  if ((idx < EC_MAXBUF) && ((*stack->rxbufstat)[idx] == EC_BUF_RCVD))
409  {
410  l = (*rxbuf)[0] + ((uint16)((*rxbuf)[1] & 0x0f) << 8);
411  /* return WKC */
412  rval = ((*rxbuf)[l] + ((uint16)(*rxbuf)[l + 1] << 8));
413  /* mark as completed */
414  (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
415  }
416  else
417  {
418  pthread_mutex_lock(&(port->rx_mutex));
419  /* non blocking call to retrieve frame from socket */
420  if (ecx_recvpkt(port, stacknumber))
421  {
422  rval = EC_OTHERFRAME;
423  ehp =(ec_etherheadert*)(stack->tempbuf);
424  /* check if it is an EtherCAT frame */
425  if (ehp->etype == htons(ETH_P_ECAT))
426  {
427  ecp =(ec_comt*)(&(*stack->tempbuf)[ETH_HEADERSIZE]);
428  l = etohs(ecp->elength) & 0x0fff;
429  idxf = ecp->index;
430  /* found index equals reqested index ? */
431  if (idxf == idx)
432  {
433  /* yes, put it in the buffer array (strip ethernet header) */
434  memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idx] - ETH_HEADERSIZE);
435  /* return WKC */
436  rval = ((*rxbuf)[l] + ((uint16)((*rxbuf)[l + 1]) << 8));
437  /* mark as completed */
438  (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE;
439  /* store MAC source word 1 for redundant routing info */
440  (*stack->rxsa)[idx] = ntohs(ehp->sa1);
441  }
442  else
443  {
444  /* check if index exist? */
445  if (idxf < EC_MAXBUF)
446  {
447  rxbuf = &(*stack->rxbuf)[idxf];
448  /* put it in the buffer array (strip ethernet header) */
449  memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idxf] - ETH_HEADERSIZE);
450  /* mark as received */
451  (*stack->rxbufstat)[idxf] = EC_BUF_RCVD;
452  (*stack->rxsa)[idxf] = ntohs(ehp->sa1);
453  }
454  else
455  {
456  /* strange things happend */
457  }
458  }
459  }
460  }
461  pthread_mutex_unlock( &(port->rx_mutex) );
462 
463  }
464 
465  /* WKC if mathing frame found */
466  return rval;
467 }
468 
481 static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert *timer)
482 {
483  osal_timert timer2;
484  int wkc = EC_NOFRAME;
485  int wkc2 = EC_NOFRAME;
486  int primrx, secrx;
487 
488  /* if not in redundant mode then always assume secondary is OK */
489  if (port->redstate == ECT_RED_NONE)
490  wkc2 = 0;
491  do
492  {
493  /* only read frame if not already in */
494  if (wkc <= EC_NOFRAME)
495  wkc = ecx_inframe(port, idx, 0);
496  /* only try secondary if in redundant mode */
497  if (port->redstate != ECT_RED_NONE)
498  {
499  /* only read frame if not already in */
500  if (wkc2 <= EC_NOFRAME)
501  wkc2 = ecx_inframe(port, idx, 1);
502  }
503  /* wait for both frames to arrive or timeout */
504  } while (((wkc <= EC_NOFRAME) || (wkc2 <= EC_NOFRAME)) && !osal_timer_is_expired(timer));
505  /* only do redundant functions when in redundant mode */
506  if (port->redstate != ECT_RED_NONE)
507  {
508  /* primrx if the reveived MAC source on primary socket */
509  primrx = 0;
510  if (wkc > EC_NOFRAME) primrx = port->rxsa[idx];
511  /* secrx if the reveived MAC source on psecondary socket */
512  secrx = 0;
513  if (wkc2 > EC_NOFRAME) secrx = port->redport->rxsa[idx];
514 
515  /* primary socket got secondary frame and secondary socket got primary frame */
516  /* normal situation in redundant mode */
517  if ( ((primrx == RX_SEC) && (secrx == RX_PRIM)) )
518  {
519  /* copy secondary buffer to primary */
520  memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
521  wkc = wkc2;
522  }
523  /* primary socket got nothing or primary frame, and secondary socket got secondary frame */
524  /* we need to resend TX packet */
525  if ( ((primrx == 0) && (secrx == RX_SEC)) ||
526  ((primrx == RX_PRIM) && (secrx == RX_SEC)) )
527  {
528  /* If both primary and secondary have partial connection retransmit the primary received
529  * frame over the secondary socket. The result from the secondary received frame is a combined
530  * frame that traversed all slaves in standard order. */
531  if ( (primrx == RX_PRIM) && (secrx == RX_SEC) )
532  {
533  /* copy primary rx to tx buffer */
534  memcpy(&(port->txbuf[idx][ETH_HEADERSIZE]), &(port->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
535  }
536  osal_timer_start (&timer2, EC_TIMEOUTRET);
537  /* resend secondary tx */
538  ecx_outframe(port, idx, 1);
539  do
540  {
541  /* retrieve frame */
542  wkc2 = ecx_inframe(port, idx, 1);
543  } while ((wkc2 <= EC_NOFRAME) && !osal_timer_is_expired(&timer2));
544  if (wkc2 > EC_NOFRAME)
545  {
546  /* copy secondary result to primary rx buffer */
547  memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE);
548  wkc = wkc2;
549  }
550  }
551  }
552 
553  /* return WKC or EC_NOFRAME */
554  return wkc;
555 }
556 
564 int ecx_waitinframe(ecx_portt *port, int idx, int timeout)
565 {
566  int wkc;
567  osal_timert timer;
568 
569  osal_timer_start (&timer, timeout);
570  wkc = ecx_waitinframe_red(port, idx, &timer);
571  /* if nothing received, clear buffer index status so it can be used again */
572  if (wkc <= EC_NOFRAME)
573  {
574  ecx_setbufstat(port, idx, EC_BUF_EMPTY);
575  }
576 
577  return wkc;
578 }
579 
592 int ecx_srconfirm(ecx_portt *port, int idx, int timeout)
593 {
594  int wkc = EC_NOFRAME;
595  osal_timert timer1, timer2;
596 
597  osal_timer_start (&timer1, timeout);
598  do
599  {
600  /* tx frame on primary and if in redundant mode a dummy on secondary */
601  ecx_outframe_red(port, idx);
602  if (timeout < EC_TIMEOUTRET)
603  {
604  osal_timer_start (&timer2, timeout);
605  }
606  else
607  {
608  /* normally use partial timout for rx */
609  osal_timer_start (&timer2, EC_TIMEOUTRET);
610  }
611  /* get frame from primary or if in redundant mode possibly from secondary */
612  wkc = ecx_waitinframe_red(port, idx, &timer2);
613  /* wait for answer with WKC>=0 or otherwise retry until timeout */
614  } while ((wkc <= EC_NOFRAME) && !osal_timer_is_expired (&timer1));
615  /* if nothing received, clear buffer index status so it can be used again */
616  if (wkc <= EC_NOFRAME)
617  {
618  ecx_setbufstat(port, idx, EC_BUF_EMPTY);
619  }
620 
621  return wkc;
622 }
623 
624 #ifdef EC_VER1
625 int ec_setupnic(const char *ifname, int secondary)
626 {
627  return ecx_setupnic(&ecx_port, ifname, secondary);
628 }
629 
630 int ec_closenic(void)
631 {
632  return ecx_closenic(&ecx_port);
633 }
634 
635 int ec_getindex(void)
636 {
637  return ecx_getindex(&ecx_port);
638 }
639 
640 void ec_setbufstat(int idx, int bufstat)
641 {
642  ecx_setbufstat(&ecx_port, idx, bufstat);
643 }
644 
645 int ec_outframe(int idx, int stacknumber)
646 {
647  return ecx_outframe(&ecx_port, idx, stacknumber);
648 }
649 
650 int ec_outframe_red(int idx)
651 {
652  return ecx_outframe_red(&ecx_port, idx);
653 }
654 
655 int ec_inframe(int idx, int stacknumber)
656 {
657  return ecx_inframe(&ecx_port, idx, stacknumber);
658 }
659 
660 int ec_waitinframe(int idx, int timeout)
661 {
662  return ecx_waitinframe(&ecx_port, idx, timeout);
663 }
664 
665 int ec_srconfirm(int idx, int timeout)
666 {
667  return ecx_srconfirm(&ecx_port, idx, timeout);
668 }
669 #endif
int ecx_getindex(ecx_portt *port)
Definition: linux/nicdrv.c:239
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_setupnic(ecx_portt *port, const char *ifname, int secondary)
Definition: linux/nicdrv.c:116
#define EC_MAXBUF
Definition: ethercattype.h:88
#define RX_SEC
Definition: linux/nicdrv.c:108
ec_bufT txbuf2
Definition: linux/nicdrv.h:110
int rxsa[EC_MAXBUF]
Definition: linux/nicdrv.h:100
static int ecx_recvpkt(ecx_portt *port, int stacknumber)
Definition: linux/nicdrv.c:351
int ecx_inframe(ecx_portt *port, int idx, int stacknumber)
Definition: linux/nicdrv.c:387
int(* txbuflength)[EC_MAXBUF]
Definition: linux/nicdrv.h:64
PACKED_BEGIN struct PACKED ec_etherheadert
ec_bufT * tempbuf
Definition: linux/nicdrv.h:66
int txbuflength2
Definition: linux/nicdrv.h:112
uint16_t uint16
Definition: osal.h:34
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
ec_stackT stack
Definition: linux/nicdrv.h:93
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
#define RX_PRIM
Definition: linux/nicdrv.c:106
int tempinbufs
Definition: linux/nicdrv.h:104
const uint16 secMAC[3]
Definition: linux/nicdrv.c:103
ec_bufT(* txbuf)[EC_MAXBUF]
Definition: linux/nicdrv.h:62
ecx_redportt * redport
Definition: linux/nicdrv.h:118
int ecx_waitinframe(ecx_portt *port, int idx, int timeout)
Definition: linux/nicdrv.c:564
PACKED_BEGIN struct PACKED ec_comt
int sockhandle
Definition: linux/nicdrv.h:94
int ecx_outframe(ecx_portt *port, int idx, int stacknumber)
Definition: linux/nicdrv.c:291
void osal_timer_start(osal_timert *self, uint32 timeout_us)
Definition: linux/osal.c:63
static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert *timer)
Definition: linux/nicdrv.c:481
#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
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
const uint16 priMAC[3]
Definition: linux/nicdrv.c:101
int ecx_closenic(ecx_portt *port)
Definition: linux/nicdrv.c:207
int ecx_outframe_red(ecx_portt *port, int idx)
Definition: linux/nicdrv.c:316
int(* rxbufstat)[EC_MAXBUF]
Definition: linux/nicdrv.h:70
#define EC_NOFRAME
Definition: ethercattype.h:73
void ec_setupheader(void *p)
Definition: linux/nicdrv.c:222
int * sock
Definition: linux/nicdrv.h:60
void ecx_setbufstat(ecx_portt *port, int idx, int bufstat)
Definition: linux/nicdrv.c:278
pthread_mutex_t rx_mutex
Definition: linux/nicdrv.h:121
int ecx_srconfirm(ecx_portt *port, int idx, int timeout)
Definition: linux/nicdrv.c:592


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