win32/ebox/ebox.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 
32 #define NSEC_PER_SEC 1000000000
33 
34 typedef struct PACKED
35 {
36  uint8 status;
37  uint8 counter;
38  uint8 din;
39  int32 ain[2];
40  uint32 tsain;
41  int32 enc[2];
42 } in_EBOXt;
43 
44 typedef struct PACKED
45 {
46  uint8 counter;
47  int16 stream[100];
49 
50 typedef struct PACKED
51 {
52  uint8 control;
53  uint8 dout;
54  int16 aout[2];
55  uint16 pwmout[2];
56 } out_EBOXt;
57 
58 typedef struct PACKED
59 {
60  uint8 control;
62 
63 // total samples to capture
64 #define MAXSTREAM 200000
65 // sample interval in ns, here 8us -> 125kHz
66 // maximum data rate for E/BOX v1.0.1 is around 150kHz
67 #define SYNC0TIME 8000
68 
69 struct sched_param schedp;
70 char IOmap[4096];
71 pthread_t thread1;
72 struct timeval tv,t1,t2;
73 int dorun = 0;
74 int deltat, tmax=0;
76 int DCdiff;
77 int os;
81 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
82 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
87 double ain[2];
88 int ainc;
92 
93 int output_cvs(char *fname, int length)
94 {
95  FILE *fp;
96 
97  int i;
98 
99  fp = fopen(fname, "w");
100  if(fp == NULL)
101  return 0;
102  for (i = 0; i < length; i++)
103  {
104  fprintf(fp, "%d %d %d\n", i, stream1[i], stream2[i]);
105  }
106  fclose(fp);
107 
108  return 1;
109 }
110 
111 void eboxtest(char *ifname)
112 {
113  int cnt, i;
114 
115  printf("Starting E/BOX test\n");
116 
117  /* initialise SOEM, bind socket to ifname */
118  if (ec_init(ifname))
119  {
120  printf("ec_init on %s succeeded.\n",ifname);
121  /* find and auto-config slaves */
122  if ( ec_config_init(FALSE) > 0 )
123  {
124  printf("%d slaves found and configured.\n",ec_slavecount);
125 
126  // check if first slave is an E/BOX
127  if (( ec_slavecount >= 1 ) &&
128  (strcmp(ec_slave[1].name,"E/BOX") == 0))
129  {
130  // reprogram PDO mapping to set slave in stream mode
131  // this can only be done in pre-OP state
132  os=sizeof(ob2); ob2 = 0x1601;
133  ec_SDOwrite(1,0x1c12,01,FALSE,os,&ob2,EC_TIMEOUTRXM);
134  os=sizeof(ob2); ob2 = 0x1a01;
135  ec_SDOwrite(1,0x1c13,01,FALSE,os,&ob2,EC_TIMEOUTRXM);
136  }
137 
139 
140  ec_configdc();
141 
142  /* wait for all slaves to reach SAFE_OP state */
144 
145  /* configure DC options for every DC capable slave found in the list */
146  printf("DC capable : %d\n",ec_configdc());
147 
148  /* check configuration */
149  if (( ec_slavecount >= 1 ) &&
150  (strcmp(ec_slave[1].name,"E/BOX") == 0)
151  )
152  {
153  printf("E/BOX found.\n");
154 
155  /* connect struct pointers to slave I/O pointers */
156  in_EBOX = (in_EBOX_streamt*) ec_slave[1].inputs;
157  out_EBOX = (out_EBOX_streamt*) ec_slave[1].outputs;
158 
159  /* read indevidual slave state and store in ec_slave[] */
160  ec_readstate();
161  for(cnt = 1; cnt <= ec_slavecount ; cnt++)
162  {
163  printf("Slave:%d Name:%s Output size:%3dbits Input size:%3dbits State:%2d delay:%d.%d\n",
164  cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits,
165  ec_slave[cnt].state, (int)ec_slave[cnt].pdelay, ec_slave[cnt].hasdc);
166  }
167  printf("Request operational state for all slaves\n");
168 
169  /* send one processdata cycle to init SM in slaves */
172 
174  /* request OP state for all slaves */
175  ec_writestate(0);
176  /* wait for all slaves to reach OP state */
178  if (ec_slave[0].state == EC_STATE_OPERATIONAL )
179  {
180  printf("Operational state reached for all slaves.\n");
181  ain[0] = 0;
182  ain[1] = 0;
183  ainc = 0;
184  dorun = 1;
185  usleep(100000); // wait for linux to sync on DC
186  ec_dcsync0(1, TRUE, SYNC0TIME, 0); // SYNC0 on slave 1
187  /* acyclic loop 20ms */
188  for(i = 1; i <= 200; i++)
189  {
190  /* read DC difference register for slave 2 */
191  // ec_FPRD(ec_slave[1].configadr, ECT_REG_DCSYSDIFF, sizeof(DCdiff), &DCdiff, EC_TIMEOUTRET);
192  // if(DCdiff<0) { DCdiff = - (int32)((uint32)DCdiff & 0x7ffffff); }
193  printf("PD cycle %5d DCtime %12lld Cnt:%3d Data: %6d %6d %6d %6d %6d %6d %6d %6d \n",
194  cyclecount, ec_DCtime, in_EBOX->counter, in_EBOX->stream[0], in_EBOX->stream[1],
195  in_EBOX->stream[2], in_EBOX->stream[3], in_EBOX->stream[4], in_EBOX->stream[5],
196  in_EBOX->stream[98], in_EBOX->stream[99]);
197  usleep(20000);
198  }
199  dorun = 0;
200  // printf("\nCnt %d : Ain0 = %f Ain2 = %f\n", ainc, ain[0] / ainc, ain[1] / ainc);
201  }
202  else
203  {
204  printf("Not all slaves reached operational state.\n");
205  }
206  }
207  else
208  {
209  printf("E/BOX not found in slave configuration.\n");
210  }
211  ec_dcsync0(1, FALSE, 8000, 0); // SYNC0 off
212  printf("Request safe operational state for all slaves\n");
214  /* request SAFE_OP state for all slaves */
215  ec_writestate(0);
216  /* wait for all slaves to reach state */
219  /* request SAFE_OP state for all slaves */
220  ec_writestate(0);
221  /* wait for all slaves to reach state */
223  if (( ec_slavecount >= 1 ) &&
224  (strcmp(ec_slave[1].name,"E/BOX") == 0))
225  {
226  // restore PDO to standard mode
227  // this can only be done is pre-op state
228  os=sizeof(ob2); ob2 = 0x1600;
229  ec_SDOwrite(1,0x1c12,01,FALSE,os,&ob2,EC_TIMEOUTRXM);
230  os=sizeof(ob2); ob2 = 0x1a00;
231  ec_SDOwrite(1,0x1c13,01,FALSE,os,&ob2,EC_TIMEOUTRXM);
232  }
233  printf("Streampos %d\n", streampos);
234  output_cvs("stream.txt", streampos);
235  }
236  else
237  {
238  printf("No slaves found!\n");
239  }
240  printf("End E/BOX, close socket\n");
241  /* stop SOEM, close socket */
242  ec_close();
243  }
244  else
245  {
246  printf("No socket connection on %s\nExcecute as root\n",ifname);
247  }
248 }
249 
250 /* add ns to timespec */
251 void add_timespec(struct timespec *ts, int64 addtime)
252 {
253  int64 sec, nsec;
254 
255  nsec = addtime % NSEC_PER_SEC;
256  sec = (addtime - nsec) / NSEC_PER_SEC;
257  ts->tv_sec += sec;
258  ts->tv_nsec += nsec;
259  if ( ts->tv_nsec > NSEC_PER_SEC )
260  {
261  nsec = ts->tv_nsec % NSEC_PER_SEC;
262  ts->tv_sec += (ts->tv_nsec - nsec) / NSEC_PER_SEC;
263  ts->tv_nsec = nsec;
264  }
265 }
266 
267 /* PI calculation to get linux time synced to DC time */
268 void ec_sync(int64 reftime, int64 cycletime , int64 *offsettime)
269 {
270  int64 delta;
271  /* set linux sync point 50us later than DC sync, just as example */
272  delta = (reftime - 50000) % cycletime;
273  if(delta> (cycletime /2)) { delta= delta - cycletime; }
274  if(delta>0){ integral++; }
275  if(delta<0){ integral--; }
276  *offsettime = -(delta / 100) - (integral /20);
277 }
278 
279 /* RT EtherCAT thread */
280 void ecatthread( void *ptr )
281 {
282  struct timespec ts;
283  struct timeval tp;
284  int rc;
285  int ht;
286  int i;
287  int pcounter = 0;
288  int64 cycletime;
289 
290  rc = pthread_mutex_lock(&mutex);
291  rc = gettimeofday(&tp, NULL);
292 
293  /* Convert from timeval to timespec */
294  ts.tv_sec = tp.tv_sec;
295  ht = (tp.tv_usec / 1000) + 1; /* round to nearest ms */
296  ts.tv_nsec = ht * 1000000;
297  cycletime = *(int*)ptr * 1000; /* cycletime in ns */
298  toff = 0;
299  dorun = 0;
300  while(1)
301  {
302  /* calculate next cycle start */
303  add_timespec(&ts, cycletime + toff);
304  /* wait to cycle start */
305  rc = pthread_cond_timedwait(&cond, &mutex, &ts);
306  if (dorun>0)
307  {
308  rc = gettimeofday(&tp, NULL);
309 
311 
313 
314  cyclecount++;
315 
316 
317  if((in_EBOX->counter != pcounter) && (streampos < (MAXSTREAM - 1)))
318  {
319  // check if we have timing problems in master
320  // if so, overwrite stream data so it shows up clearly in plots.
321  if(in_EBOX->counter > (pcounter + 1))
322  {
323  for(i = 0 ; i < 50 ; i++)
324  {
325  stream1[streampos] = 20000;
326  stream2[streampos++] = -20000;
327  }
328  }
329  else
330  {
331  for(i = 0 ; i < 50 ; i++)
332  {
333  stream1[streampos] = in_EBOX->stream[i * 2];
334  stream2[streampos++] = in_EBOX->stream[(i * 2) + 1];
335  }
336  }
337  pcounter = in_EBOX->counter;
338  }
339 
340  /* calulate toff to get linux time and DC synced */
341  ec_sync(ec_DCtime, cycletime, &toff);
342  }
343  }
344 }
345 
346 int main(int argc, char *argv[])
347 {
348  int iret1;
349  int ctime;
350  struct sched_param param;
351  int policy = SCHED_OTHER;
352 
353  printf("SOEM (Simple Open EtherCAT Master)\nE/BOX test\n");
354 
355  memset(&schedp, 0, sizeof(schedp));
356  /* do not set priority above 49, otherwise sockets are starved */
357  schedp.sched_priority = 30;
358  sched_setscheduler(0, SCHED_FIFO, &schedp);
359 
360  do
361  {
362  usleep(1000);
363  }
364  while (dorun);
365 
366  if (argc > 1)
367  {
368  dorun = 1;
369  if( argc > 2)
370  ctime = atoi(argv[2]);
371  else
372  ctime = 1000; // 1ms cycle time
373  /* create RT thread */
374  iret1 = pthread_create( &thread1, NULL, (void *) &ecatthread, (void*) &ctime);
375  memset(&param, 0, sizeof(param));
376  /* give it higher priority */
377  param.sched_priority = 40;
378  iret1 = pthread_setschedparam(thread1, policy, &param);
379 
380  /* start acyclic part */
381  eboxtest(argv[1]);
382  }
383  else
384  {
385  printf("Usage: ebox ifname [cycletime]\nifname = eth0 for example\ncycletime in us\n");
386  }
387 
388  schedp.sched_priority = 0;
389  sched_setscheduler(0, SCHED_OTHER, &schedp);
390 
391  printf("End program\n");
392 
393  return (0);
394 }
int dorun
Headerfile for ethercatdc.c.
int16 stream2[MAXSTREAM]
int ec_readstate(void)
int16 aout[2]
int ec_send_processdata(void)
#define EC_TIMEOUTSTATE
Definition: ethercattype.h:102
PACKED_END ec_slavet ec_slave[EC_MAXSLAVE]
Definition: ethercatmain.c:104
int DCdiff
uint8 control
void ecatthread(void *ptr)
int ainc
uint8_t uint8
Definition: osal.h:33
#define SYNC0TIME
int16 stream[100]
int ec_receive_processdata(int timeout)
struct timeval tv t1 t2
uint32 cyclecount
int tmax
pthread_cond_t cond
char IOmap[4096]
uint16_t uint16
Definition: osal.h:34
pthread_mutex_t mutex
int64 ec_DCtime
Definition: ethercatmain.c:132
int os
#define EC_TIMEOUTRXM
Definition: ethercattype.h:100
General typedefs and defines for EtherCAT.
Headerfile for ethercatcoe.c.
#define TRUE
Definition: osal.h:28
int ec_config_map(void *pIOmap)
void ec_sync(int64 reftime, int64 cycletime, int64 *offsettime)
void eboxtest(char *ifname)
int32 ain[2]
int64 integral
int deltat
struct PACKED in_EBOXt
uint8 din
uint8 ob3
uint8 counter
uint8 dout
int ec_init(char *ifname)
void ec_dcsync0(uint16 slave, boolean act, uint32 CyclTime, uint32 CyclShift)
Definition: ethercatdc.c:446
int16 ob2
int streampos
pthread_t thread1
int64 toff
struct PACKED in_EBOX_streamt
struct sched_param schedp
int64_t int64
Definition: osal.h:36
#define FALSE
Definition: osal.h:29
int32_t int32
Definition: osal.h:32
in_EBOX_streamt * in_EBOX
#define NSEC_PER_SEC
int output_cvs(char *fname, int length)
uint32 ob
#define EC_TIMEOUTRET
Definition: ethercattype.h:90
struct PACKED out_EBOX_streamt
int ec_writestate(uint16 slave)
Headerfile for ethercatbase.c.
uint16 length
Definition: ethercatmain.h:347
boolean ec_configdc(void)
Definition: ethercatdc.c:456
int main(int argc, char *argv[])
Headerfile for ethercatmain.c.
int16 stream1[MAXSTREAM]
out_EBOX_streamt * out_EBOX
uint32_t uint32
Definition: osal.h:35
int gettimeofday(struct timeval *tp, void *tzp)
Definition: rtk/osal.c:65
int16_t int16
Definition: osal.h:31
uint16 pwmout[2]
uint16 state
Definition: ethercatmain.h:140
void add_timespec(struct timespec *ts, int64 addtime)
int32 enc[2]
char name[EC_SOE_MAXNAME]
Definition: ethercatsoe.h:77
#define MAXSTREAM
void ec_close(void)
uint16 ec_statecheck(uint16 slave, uint16 reqstate, int timeout)
uint32 tsain
int ec_slavecount
Definition: ethercatmain.c:106
Headerfile for ethercatconfig.c.
struct PACKED out_EBOXt
int ec_SDOwrite(uint16 Slave, uint16 Index, uint8 SubIndex, boolean CA, int psize, void *p, int Timeout)
Definition: ethercatcoe.c:1353
uint8 status
int ec_config_init(uint8 usetable)


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