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


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