linux/red_test/red_test.c
Go to the documentation of this file.
1 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <sys/time.h>
16 #include <unistd.h>
17 #include <sched.h>
18 #include <string.h>
19 #include <sys/time.h>
20 #include <time.h>
21 #include <pthread.h>
22 #include <math.h>
23 
24 #include "ethercattype.h"
25 #include "nicdrv.h"
26 #include "ethercatbase.h"
27 #include "ethercatmain.h"
28 #include "ethercatcoe.h"
29 #include "ethercatconfig.h"
30 #include "ethercatdc.h"
31 #include "ethercatprint.h"
32 
33 #define NSEC_PER_SEC 1000000000
34 #define EC_TIMEOUTMON 500
35 
36 struct sched_param schedp;
37 char IOmap[4096];
38 pthread_t thread1, thread2;
39 struct timeval tv, t1, t2;
40 int dorun = 0;
41 int deltat, tmax = 0;
43 int DCdiff;
44 int os;
47 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
48 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
51 boolean needlf;
52 volatile int wkc;
53 boolean inOP;
55 
56 
57 void redtest(char *ifname, char *ifname2)
58 {
59  int cnt, i, j, oloop, iloop;
60 
61  printf("Starting Redundant test\n");
62 
63  /* initialise SOEM, bind socket to ifname */
64  if (ec_init_redundant(ifname, ifname2))
65  {
66  printf("ec_init on %s succeeded.\n",ifname);
67  /* find and auto-config slaves */
68  if ( ec_config(FALSE, &IOmap) > 0 )
69  {
70  printf("%d slaves found and configured.\n",ec_slavecount);
71  /* wait for all slaves to reach SAFE_OP state */
73 
74  /* configure DC options for every DC capable slave found in the list */
75  ec_configdc();
76 
77  /* read indevidual slave state and store in ec_slave[] */
78  ec_readstate();
79  for(cnt = 1; cnt <= ec_slavecount ; cnt++)
80  {
81  printf("Slave:%d Name:%s Output size:%3dbits Input size:%3dbits State:%2d delay:%d.%d\n",
82  cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits,
83  ec_slave[cnt].state, (int)ec_slave[cnt].pdelay, ec_slave[cnt].hasdc);
84  printf(" Out:%8.8x,%4d In:%8.8x,%4d\n",
85  (int)ec_slave[cnt].outputs, ec_slave[cnt].Obytes, (int)ec_slave[cnt].inputs, ec_slave[cnt].Ibytes);
86  /* check for EL2004 or EL2008 */
87  if( !digout && ((ec_slave[cnt].eep_id == 0x0af83052) || (ec_slave[cnt].eep_id == 0x07d83052)))
88  {
89  digout = ec_slave[cnt].outputs;
90  }
91  }
92  expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC;
93  printf("Calculated workcounter %d\n", expectedWKC);
94 
95  printf("Request operational state for all slaves\n");
97  /* request OP state for all slaves */
98  ec_writestate(0);
99  /* activate cyclic process data */
100  dorun = 1;
101  /* wait for all slaves to reach OP state */
103  oloop = ec_slave[0].Obytes;
104  if ((oloop == 0) && (ec_slave[0].Obits > 0)) oloop = 1;
105  if (oloop > 8) oloop = 8;
106  iloop = ec_slave[0].Ibytes;
107  if ((iloop == 0) && (ec_slave[0].Ibits > 0)) iloop = 1;
108  if (iloop > 8) iloop = 8;
109  if (ec_slave[0].state == EC_STATE_OPERATIONAL )
110  {
111  printf("Operational state reached for all slaves.\n");
112  inOP = TRUE;
113  /* acyclic loop 5000 x 20ms = 10s */
114  for(i = 1; i <= 5000; i++)
115  {
116  printf("Processdata cycle %5d , Wck %3d, DCtime %12lld, dt %12lld, O:",
118  for(j = 0 ; j < oloop; j++)
119  {
120  printf(" %2.2x", *(ec_slave[0].outputs + j));
121  }
122  printf(" I:");
123  for(j = 0 ; j < iloop; j++)
124  {
125  printf(" %2.2x", *(ec_slave[0].inputs + j));
126  }
127  printf("\r");
128  fflush(stdout);
129  osal_usleep(20000);
130  }
131  dorun = 0;
132  inOP = FALSE;
133  }
134  else
135  {
136  printf("Not all slaves reached operational state.\n");
137  ec_readstate();
138  for(i = 1; i<=ec_slavecount ; i++)
139  {
140  if(ec_slave[i].state != EC_STATE_OPERATIONAL)
141  {
142  printf("Slave %d State=0x%2.2x StatusCode=0x%4.4x : %s\n",
143  i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode));
144  }
145  }
146  }
147  printf("Request safe operational state for all slaves\n");
149  /* request SAFE_OP state for all slaves */
150  ec_writestate(0);
151  }
152  else
153  {
154  printf("No slaves found!\n");
155  }
156  printf("End redundant test, close socket\n");
157  /* stop SOEM, close socket */
158  ec_close();
159  }
160  else
161  {
162  printf("No socket connection on %s\nExcecute as root\n",ifname);
163  }
164 }
165 
166 /* add ns to timespec */
167 void add_timespec(struct timespec *ts, int64 addtime)
168 {
169  int64 sec, nsec;
170 
171  nsec = addtime % NSEC_PER_SEC;
172  sec = (addtime - nsec) / NSEC_PER_SEC;
173  ts->tv_sec += sec;
174  ts->tv_nsec += nsec;
175  if ( ts->tv_nsec > NSEC_PER_SEC )
176  {
177  nsec = ts->tv_nsec % NSEC_PER_SEC;
178  ts->tv_sec += (ts->tv_nsec - nsec) / NSEC_PER_SEC;
179  ts->tv_nsec = nsec;
180  }
181 }
182 
183 /* PI calculation to get linux time synced to DC time */
184 void ec_sync(int64 reftime, int64 cycletime , int64 *offsettime)
185 {
186  static int64 integral = 0;
187  int64 delta;
188  /* set linux sync point 50us later than DC sync, just as example */
189  delta = (reftime - 50000) % cycletime;
190  if(delta> (cycletime / 2)) { delta= delta - cycletime; }
191  if(delta>0){ integral++; }
192  if(delta<0){ integral--; }
193  *offsettime = -(delta / 100) - (integral / 20);
194  gl_delta = delta;
195 }
196 
197 /* RT EtherCAT thread */
198 void ecatthread( void *ptr )
199 {
200  struct timespec ts, tleft;
201  struct timeval tp;
202  int rc;
203  int ht;
204  int64 cycletime;
205 
206  rc = pthread_mutex_lock(&mutex);
207  rc = clock_gettime(CLOCK_MONOTONIC, &ts);
208  ht = (ts.tv_nsec / 1000000) + 1; /* round to nearest ms */
209  ts.tv_nsec = ht * 1000000;
210  cycletime = *(int*)ptr * 1000; /* cycletime in ns */
211  toff = 0;
212  dorun = 0;
214  while(1)
215  {
216  /* calculate next cycle start */
217  add_timespec(&ts, cycletime + toff);
218  /* wait to cycle start */
219  rc = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, &tleft);
220  if (dorun>0)
221  {
223 
224  dorun++;
225  /* if we have some digital output, cycle */
226  if( digout ) *digout = (uint8) ((dorun / 16) & 0xff);
227 
228  if (ec_slave[0].hasdc)
229  {
230  /* calulate toff to get linux time and DC synced */
231  ec_sync(ec_DCtime, cycletime, &toff);
232  }
234  }
235  }
236 }
237 
238 void ecatcheck( void *ptr )
239 {
240  int slave;
241 
242  while(1)
243  {
244  if( inOP && ((wkc < expectedWKC) || ec_group[currentgroup].docheckstate))
245  {
246  if (needlf)
247  {
248  needlf = FALSE;
249  printf("\n");
250  }
251  /* one ore more slaves are not responding */
253  ec_readstate();
254  for (slave = 1; slave <= ec_slavecount; slave++)
255  {
256  if ((ec_slave[slave].group == currentgroup) && (ec_slave[slave].state != EC_STATE_OPERATIONAL))
257  {
259  if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR))
260  {
261  printf("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave);
263  ec_writestate(slave);
264  }
265  else if(ec_slave[slave].state == EC_STATE_SAFE_OP)
266  {
267  printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave);
269  ec_writestate(slave);
270  }
271  else if(ec_slave[slave].state > 0)
272  {
273  if (ec_reconfig_slave(slave, EC_TIMEOUTMON))
274  {
276  printf("MESSAGE : slave %d reconfigured\n",slave);
277  }
278  }
279  else if(!ec_slave[slave].islost)
280  {
281  /* re-check state */
283  if (!ec_slave[slave].state)
284  {
286  printf("ERROR : slave %d lost\n",slave);
287  }
288  }
289  }
290  if (ec_slave[slave].islost)
291  {
292  if(!ec_slave[slave].state)
293  {
294  if (ec_recover_slave(slave, EC_TIMEOUTMON))
295  {
297  printf("MESSAGE : slave %d recovered\n",slave);
298  }
299  }
300  else
301  {
303  printf("MESSAGE : slave %d found\n",slave);
304  }
305  }
306  }
307  if(!ec_group[currentgroup].docheckstate)
308  printf("OK : all slaves resumed OPERATIONAL.\n");
309  }
310  osal_usleep(10000);
311  }
312 }
313 
314 int main(int argc, char *argv[])
315 {
316  int iret1, iret2;
317  int ctime;
318  struct sched_param param;
319  int policy = SCHED_OTHER;
320 
321  printf("SOEM (Simple Open EtherCAT Master)\nRedundancy test\n");
322 
323  memset(&schedp, 0, sizeof(schedp));
324  /* do not set priority above 49, otherwise sockets are starved */
325  schedp.sched_priority = 30;
326  sched_setscheduler(0, SCHED_FIFO, &schedp);
327 
328  if (argc > 3)
329  {
330  dorun = 0;
331  ctime = atoi(argv[3]);
332 
333  /* create RT thread */
334  iret1 = pthread_create( &thread1, NULL, (void *) &ecatthread, (void*) &ctime);
335  memset(&param, 0, sizeof(param));
336  /* give it higher priority */
337  param.sched_priority = 40;
338  iret1 = pthread_setschedparam(thread1, policy, &param);
339 
340  /* create thread to handle slave error handling in OP */
341  iret2 = pthread_create( &thread2, NULL, (void *) &ecatcheck, (void*) &ctime);
342 
343  /* start acyclic part */
344  redtest(argv[1],argv[2]);
345  }
346  else
347  {
348  printf("Usage: red_test ifname1 ifname2 cycletime\nifname = eth0 for example\ncycletime in us\n");
349  }
350 
351  schedp.sched_priority = 0;
352  sched_setscheduler(0, SCHED_OTHER, &schedp);
353 
354  printf("End program\n");
355 
356  return (0);
357 }
ec_groupt ec_group[EC_MAXGROUP]
Definition: ethercatmain.c:108
int ec_reconfig_slave(uint16 slave, int timeout)
char * ec_ALstatuscode2string(uint16 ALstatuscode)
uint32 Obytes
Definition: ethercatmain.h:160
int64 toff
Headerfile for ethercatdc.c.
int ec_readstate(void)
int ec_send_processdata(void)
#define NSEC_PER_SEC
#define EC_TIMEOUTSTATE
Definition: ethercattype.h:102
PACKED_END ec_slavet ec_slave[EC_MAXSLAVE]
Definition: ethercatmain.c:104
uint8 currentgroup
void redtest(char *ifname, char *ifname2)
uint8_t uint8
Definition: osal.h:33
int ec_init_redundant(char *ifname, char *if2name)
int ec_recover_slave(uint16 slave, int timeout)
int ec_receive_processdata(int timeout)
pthread_t thread2
uint16_t uint16
Definition: osal.h:34
uint8 * outputs
Definition: ethercatmain.h:162
void ecatcheck(void *ptr)
int64 ec_DCtime
Definition: ethercatmain.c:132
void ecatthread(void *ptr)
uint16 ob2
General typedefs and defines for EtherCAT.
Headerfile for ethercatcoe.c.
#define TRUE
Definition: osal.h:28
#define EC_TIMEOUTMON
uint8 * digout
boolean islost
Definition: ethercatmain.h:260
boolean docheckstate
Definition: ethercatmain.h:299
int slave
Definition: aliastool.c:51
int64_t int64
Definition: osal.h:36
#define FALSE
Definition: osal.h:29
struct sched_param schedp
char IOmap[4096]
void ec_sync(int64 reftime, int64 cycletime, int64 *offsettime)
int main(int argc, char *argv[])
struct timeval tv t1 t2
void add_timespec(struct timespec *ts, int64 addtime)
#define EC_TIMEOUTRET
Definition: ethercattype.h:90
int ec_writestate(uint16 slave)
int64 integral
Headerfile for ethercatbase.c.
int ec_config(uint8 usetable, void *pIOmap)
uint8 ob
boolean ec_configdc(void)
Definition: ethercatdc.c:456
uint16 outputsWKC
Definition: ethercatmain.h:295
boolean needlf
Headerfile for ethercatmain.c.
uint32 Ibytes
Definition: ethercatmain.h:168
pthread_t thread1
uint16 state
Definition: ethercatmain.h:140
pthread_cond_t cond
int osal_usleep(uint32 usec)
Definition: linux/osal.c:28
void ec_close(void)
boolean inOP
pthread_mutex_t mutex
int expectedWKC
uint16 ec_statecheck(uint16 slave, uint16 reqstate, int timeout)
int ec_slavecount
Definition: ethercatmain.c:106
Headerfile for ethercatconfig.c.
volatile int wkc
int64 gl_delta
Headerfile for ethercatprint.c.


soem
Author(s): Arthur Ketels and M.J.G. van den Molengraft
autogenerated on Sat Jun 8 2019 18:02:17