]> rtime.felk.cvut.cz Git - eurobot/public.git/blob - src/odometry/brushless.c
Update to a new version of PXMC kindly provided by P. Pisa
[eurobot/public.git] / src / odometry / brushless.c
1 /*
2  *  Copyright (C) 2006-2011 Department of Control Engineering, FEE,
3  *  Czech Technical University in Prague, Czech Republic,
4  *  http://dce.fel.cvut.cz/
5  *                                                                    
6  *  Copyright (C) 2006-2011 Michal Sojka <sojkam1@fel.cvut.cz>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *  
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  */
18
19 /* procesor H8S/2638 ver 1.1  */
20 #include <types.h>
21 #include <cpu_def.h>
22 #include <mcu_regs.h>
23 #include <system_def.h>
24 #include <string.h>
25 #include <boot_fn.h>
26 #include <pxmc.h>
27 //#include <pxmc_internal.h>
28 #include <pxmcbsp.h>
29
30 #include <ctype.h>
31 #include <stdlib.h>
32 #include <utils.h>
33 #include <periph/sci_rs232.h>
34 #include <periph/sci_channels.h>
35 #include <stdio.h>
36 #include <stdbool.h>
37
38 #include <cmd_proc.h>
39
40 #include "cmd_pxmc.h"
41 //#include <math.h>
42 #include <cmd_proc.h>
43 #include <candriver.h>
44 #include <canOpenDriver.h>
45 #include <can_ids.h>
46
47 #define INLINE /* Empty */
48
49 /**
50  * @addtogroup leds
51  * @{
52  * @name Odometry (IRC2010)
53  * @{
54  */
55 /* #define LED_MAIN_LOOP 0 */
56 /* #define LED_CORR_TRIG 2 */
57 /* #define LED_ODO_SEND 3 */
58 #define LED_LIVE   0            /**< D1: Blinks once per second when software is alive */
59 #define LED_CAN_REC 1           /**< D2: Blinks when a CAN message is received:
60                                  * - 50ms for motion message
61                                  * - 5ms for other message (corr_trig) */
62 #define LED_ERROR  2            /**< D3: Light = Unhandled exception, Slow blink (4s) = motor error */
63 #define LED_RESET  3            /**< D4: Blinks for 1 s after reset */
64 /** @} */
65 /** @} */
66
67 #define MAX(a,b) ((a)>(b)?(a):(b))
68
69 bool odometry_triggered = false;
70 unsigned char trig_seq;
71
72 int cmd_do_quit(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
73 {
74     printf("Good bye!\n");
75     *HCAN1_MCR=1;       // software reset
76     //exit(0);
77     return 0;
78 }
79
80 int cmd_do_canst(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
81 {
82         canPrintStatus(0);
83         return 0;
84 }
85
86 int cmd_do_setflags(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
87 {
88     pxmc_state_t *mcs;
89
90     if((mcs=cmd_opchar_getreg(cmd_io,des,param))==NULL) return -CMDERR_BADREG;
91
92     pxmc_set_flag(mcs,PXMS_PTI_b);      // start to updating index pointing to the phase table (ptindx)
93     pxmc_set_flag(mcs,PXMS_PHA_b);      // FIXME: is it really need here
94     printf("Flags were set!\n");
95     return 0;
96 }
97 /** 
98  * Rotates motor slowly four turns forward and than two turns backward
99  * (in a feedforward manner). During movement it displays values read
100  * from HAL sensors and tries to detect correct index mark position.
101  */
102 int cmd_do_haltest(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
103 {
104     pxmc_state_t *mcs;
105     int i, vang, ptindx, ang_deg, dir, rot;
106     char hal;
107     int ptmark_errors[10];
108     int err_idx=-1;             /* Ignore the first change because */
109     short ptofs = 1;            /* it is unlikely that initial offset is 1 (after reset it will be zero) */
110     unsigned last_time = 0;
111
112     if((mcs=cmd_opchar_getreg(cmd_io,des,param))==NULL) return -CMDERR_BADREG;
113
114     vang = mcs->pxms_ptvang;    /* Remember vang */
115     
116     mcs->pxms_ptvang=0;
117     mcs->pxms_ene=mcs->pxms_me/3;
118     printf("ptindx hal ap ptofs\n");
119
120     /* Move motor to the initial position */
121     mcs->pxms_flg = PXMS_PHA_m | PXMS_PTI_m; /* Do not update ptindex acording to HALs */
122     mcs->pxms_ptindx=0;         /* Set fixed index to phase tables*/
123     motor_do_output(mcs); /* Apply mag. field accoring to our index */
124     last_time = pxmc_msec_counter;
125     while (pxmc_msec_counter < last_time + 1000) /* Wait for motor to move */
126             wdg_clear(); 
127
128     ang_deg=0;
129     for (dir=0; dir<2; dir++) {
130         for (rot=0; rot<4; rot++) {
131             pxmc_initialize(); // reset index mark detection
132             if ((dir&1) == 0) ang_deg=0;
133             else ang_deg=360;
134             while (((dir&1) == 0 && ang_deg < 360) ||
135                    ((dir&1) != 0 && ang_deg >= 0)) {
136                 wdg_clear();
137                 ptindx = ((long)ang_deg*mcs->pxms_ptirc/360) % mcs->pxms_ptirc;
138
139                 mcs->pxms_flg = 0;
140                 pxmc_call(mcs, mcs->pxms_do_inp); /* Read IRCs */
141                 mcs->pxms_ptindx=ptindx;/* Set fixed index to phase tables*/
142                 mcs->pxms_flg = PXMS_PHA_m | PXMS_PTI_m; /* Do not update ptindex acording to HALs */
143                 motor_do_output(mcs);   /* Apply mag. field accoring to our index */
144                 last_time = pxmc_msec_counter;
145                 while (pxmc_msec_counter < last_time + 4); /* Wait for motor to move */
146                 hal = hal_read(mcs);    /* read HAL sensors */
147                 printf("%d %d %ld %d\n", mcs->pxms_ptindx, hal,
148                        mcs->pxms_ap>>PXMC_SUBDIV(mcs), mcs->pxms_ptofs);
149                 if (mcs->pxms_ptofs != ptofs) { /* index mark was detected */
150                     ptofs = mcs->pxms_ptofs;
151                     if ((int)err_idx < (int)(sizeof(ptmark_errors)/sizeof(*ptmark_errors))) {
152                         if (err_idx >= 0) {
153                             ptmark_errors[err_idx] =
154                                 mcs->pxms_ptofs + mcs->pxms_ptindx - (mcs->pxms_ap>>PXMC_SUBDIV(mcs));
155                         }
156                         err_idx++;
157                     }
158                 }
159                 if ((dir&1) == 0) ang_deg++;
160                 else ang_deg--;
161             }
162         }
163     }
164     mcs->pxms_ene=0;
165     mcs->pxms_ptvang = vang;
166     motor_do_output(mcs);
167     mcs->pxms_flg = PXMS_ENI_m;
168
169     long int avg = 0;
170     for (i=0; i<err_idx; i++) {
171             wdg_clear();
172             printf("ptmark error %d\n", ptmark_errors[i]);
173             avg+=ptmark_errors[i];
174     }
175     mcs->pxms_ptmark = (mcs->pxms_ptmark + avg/err_idx) % mcs->pxms_ptirc;
176     printf("pxms_ptmark increased by %ld to %d\n", avg/err_idx, mcs->pxms_ptmark);
177
178     return 0;
179 }
180
181 int cmd_do_setindex(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
182 {
183     pxmc_state_t *mcs;
184     if((mcs=cmd_opchar_getreg(cmd_io,des,param))==NULL) return -CMDERR_BADREG;
185     int index=atol(param[2]);
186     printf("index=%d\n", index);
187     //printf("No errors detected.\n", index);
188     mcs->pxms_ptindx=index;
189     return 0;
190 }
191
192 int cmd_do_setvang(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
193 {
194     pxmc_state_t *mcs;
195     if((mcs=cmd_opchar_getreg(cmd_io,des,param))==NULL) return -CMDERR_BADREG;
196     int index=atol(param[2]);
197     printf("ptvang=%d\n", index);
198     //printf("No errors detected.\n", index);
199     mcs->pxms_ptvang=index;
200     return 0;
201 }
202
203
204 int cmd_do_setshift(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
205 {
206     pxmc_state_t *mcs;
207     if((mcs=cmd_opchar_getreg(cmd_io,des,param))==NULL) return -CMDERR_BADREG;
208     int index=atol(param[2]);
209     printf("ptshift=%d\n", index);
210     //printf("No errors detected.\n", index);
211     mcs->pxms_ptshift=index;
212     return 0;
213 }
214
215 int cmd_do_showene(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
216 {
217     pxmc_state_t *mcs;
218     if((mcs=cmd_opchar_getreg(cmd_io,des,param))==NULL) return -CMDERR_BADREG;
219 //      if((mcs=cmd_opchar_getreg(cmd_io,des,param))==NULL) return -CMDERR_BADREG;
220     printf("Current ene is: %d\n",mcs->pxms_ene);
221     printf("Current ptindx is: %d\n",mcs->pxms_ptindx);
222     printf("Current ptvang is: %d\n",mcs->pxms_ptvang);
223
224     printf("Current ptshift is: %d\n",mcs->pxms_ptshift);
225     printf("Current ptofs is: %d\n",mcs->pxms_ptofs);
226
227
228     printf("Actual pos is: %ld\n",mcs->pxms_ap>>PXMC_SUBDIV(mcs));
229     printf("Request pos is: %ld\n",mcs->pxms_rp>>PXMC_SUBDIV(mcs));
230
231     printf("inp_info is: %d\n",*(volatile short*)mcs->pxms_inp_info);
232
233     //printf("hal is: %d\n", hal_read(mcs) );
234
235     if((mcs->pxms_flg&PXMS_PTI_m)) printf("PXMS_PTI_m is: enabled\n"); else printf("PXMS_PTI_m is: disabled\n");
236     if((mcs->pxms_flg&PXMS_PHA_m)) printf("PXMS_PHA_m is: enabled\n"); else printf("PXMS_PHA_m is: disabled\n");
237     return 0;
238 }
239
240 int cmd_do_nopxmc(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
241 {
242     pxmc_state_t *mcs;
243     if((mcs=cmd_opchar_getreg(cmd_io,des,param))==NULL) return -CMDERR_BADREG;
244     pxmc_clear_flag(mcs,PXMS_ENR_b);
245     pxmc_clear_flag(mcs,PXMS_ENO_b);
246     *PWM_PWBFR1A=0;
247     *PWM_PWBFR1C=0;
248     *PWM_PWBFR1E=0;
249     return 0;
250 }
251
252 int cmd_do_mypwm(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
253 {
254     int r;
255     int val;
256 #define _PXMC_MAX_OUT_ 0x6f
257     const unsigned long ph1[6]={2, 1, 1, 0, 1, 1};
258     const unsigned long ph2[6]={1, 0, 1, 1, 2, 1};
259     const unsigned long ph3[6]={1, 1, 2, 1, 1, 0};
260 #undef _PMXC_MAX_OUT_
261
262     r=atol(param[1]);
263     val=atol(param[2])/2;
264     if (val==0) val = 0;
265     printf("r=%d val=%d\n", r, val);
266
267     unsigned pwm1=val*ph1[r];
268     unsigned pwm2=val*ph2[r];
269     unsigned pwm3=val*ph3[r];
270     *PWM_PWBFR1A=(pwm1&0x3ff);
271     *PWM_PWBFR1C=(pwm2&0x3ff);
272     *PWM_PWBFR1E=(pwm3&0x3ff);
273     return 0;
274 }
275
276 /**
277  * Implementation of help command with watchdog
278  */
279 static INLINE char *skip_white(char *p)
280 {
281   while(isspace((__u8)*p)) p++;
282   return p;
283 }
284
285
286 #define CMD_ARR_STACK_SIZE 4    
287 int cmd_do_help_wd(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
288 {
289   char *help;
290   char *filt=param[1];
291   const cmd_des_t **des_arr=*(const cmd_des_t ***)des->info[0];
292   cmd_des_t const **arr_stack[CMD_ARR_STACK_SIZE];
293   int arr_stack_sp=0;
294
295   if (cmd_io->priv.ed_line.io_stack)
296     cmd_io = cmd_io->priv.ed_line.io_stack;
297   
298   if(filt) {
299     filt=skip_white(filt);
300     if(!*filt) filt=NULL;
301   }
302   cmd_io_puts(cmd_io,"Help for commands\n");
303   while(1){
304     wdg_clear();                /* Added to avoid reseting while listing commands */
305     des=*(des_arr++);
306     if(!des){
307       if(!arr_stack_sp) break;
308       des_arr=arr_stack[--arr_stack_sp];
309       continue;
310     }
311     if(des==CMD_DES_CONTINUE_AT_ID){
312       /* list continues at new address */
313       des_arr=(const cmd_des_t **)*des_arr;
314       continue;
315     }
316     if(des==CMD_DES_INCLUDE_SUBLIST_ID){
317       /* list includes commands from sublists */
318       if(arr_stack_sp>=CMD_ARR_STACK_SIZE){
319         des_arr++;
320       }else{
321         arr_stack[arr_stack_sp++]=des_arr+1;
322         des_arr=(const cmd_des_t **)*des_arr;
323         continue;
324       }
325     }
326     if(des->name){
327       if(!filt || !strncmp(des->name,filt,strlen(filt))) {
328         help=des->help;
329         if(!help) help="?";
330         cmd_io_puts(cmd_io,des->name);
331         cmd_io_puts(cmd_io," - ");
332         cmd_io_puts(cmd_io,help);
333         cmd_io_puts(cmd_io, "\r\n");
334       }
335     }
336   }
337   return 0;
338 }
339
340 int runtime_display = 0;
341 int slowgo = 0;
342
343 cmd_des_t const **cmd_list;
344
345 /* command descriptions */
346 cmd_des_t const cmd_des_help={0, 0,"HELP","prints help for commands",
347                               cmd_do_help_wd,{(char*)&cmd_list}};
348 cmd_des_t const cmd_des_showene={0, 0,"SHOWENE?","shows ene and couple others parameters",
349                                  cmd_do_showene};
350
351 cmd_des_t const cmd_des_mypwm={0, 0,"x#","test",
352                                cmd_do_mypwm};
353 cmd_des_t const cmd_des_nopxmc={0, 0,"NOPXMC?","switch of pxmc controller and output",
354                                 cmd_do_nopxmc};
355 cmd_des_t const cmd_des_disp={0, CDESM_OPCHR|CDESM_RW,"DISP","switch on/off runtime display of variables",
356                               cmd_do_rw_int, {(char*)&runtime_display}};
357 cmd_des_t const cmd_des_slowgo={0, CDESM_OPCHR|CDESM_RW,"SLOWGO","program controlled movement",
358                                 cmd_do_rw_int, {(char*)&slowgo}};
359 cmd_des_t const cmd_des_setindex={0, 0,"SETINDEX?","changes pxms_ptindx",
360                                   cmd_do_setindex};
361 cmd_des_t const cmd_des_setvang={0, 0,"SETVANG?","changes pxms_ptvang",
362                                  cmd_do_setvang};
363 cmd_des_t const cmd_des_halindex={0, 0,"HALTEST?","show hal state with respect to ptindex",
364                                   cmd_do_haltest};
365 cmd_des_t const cmd_des_setshift={0, 0,"SETSHIFT?","changes pxms_ptshift",
366                                   cmd_do_setshift};
367 cmd_des_t const cmd_des_quit={0, 0,"QUIT","exit",
368                               cmd_do_quit};
369 cmd_des_t const cmd_des_canst={0, 0,"CANST","Print CAN controller status",
370                               cmd_do_canst};
371
372 cmd_des_t const cmd_des_setflags={0, 0,"setflags","set some flags",
373                                   cmd_do_setflags};
374
375
376 extern cmd_io_t cmd_io_rs232_line;
377 cmd_des_t const *cmd_list_default[]={
378
379     &cmd_des_help,
380     &cmd_des_quit,
381     &cmd_des_setflags,
382     &cmd_des_mypwm,
383     &cmd_des_setindex,
384     &cmd_des_setvang,
385     &cmd_des_halindex,
386     &cmd_des_setshift,
387     &cmd_des_showene,
388     &cmd_des_nopxmc,
389     &cmd_des_disp,
390     &cmd_des_slowgo,
391     &cmd_des_canst,
392     (cmd_des_t*)1,
393     (cmd_des_t*)cmd_stm_default,
394     NULL
395 };
396
397 cmd_des_t const **cmd_list=cmd_list_default;     /*cmd prikazy pro PC*/
398
399 //Interrupt routines
400 void  unhandled_exception(void) __attribute__ ((interrupt_handler));
401 void  unhandled_exception(void)
402 {
403 #ifdef LED_ERROR
404     DEB_LED_ON(LED_ERROR);
405     FlWait(20000);
406     DEB_LED_OFF(LED_ERROR);
407     FlWait(20000);
408 #endif
409 }
410
411 void print_mcs_err(pxmc_state_t *mcs, char *name)
412 {
413     const char *errmsg[] = {
414         [PXMS_E_COMM&0xff] = "COMM",
415         [PXMS_E_MAXPD&0xff] = "MAXPD",
416         [PXMS_E_OVERL&0xff] = "OVERL",
417         [PXMS_E_HAL&0xff] = "HAL",
418         [PXMS_E_POWER_STAGE&0xff] = "POWER"};
419         printf("PXMC ERROR: %s - %s\n", name, errmsg[mcs->pxms_errno&0xff]);
420 }
421
422 short idxRecive =0;
423 short idxStore=0;
424 #define ODOMETRY_TABLE_SIZE 10
425 struct odometryData_t
426 {
427     short dx,dy;
428     long angle;
429 } oddata[ODOMETRY_TABLE_SIZE];
430
431 #if 0
432 static INLINE short sendOdometry()
433 {
434         static short idxSend=0;
435         static short prevIdxRecive=0xff;
436
437         if(prevIdxRecive==idxRecive)
438         {
439                 // Re-send can frames.
440         }
441         else
442         {
443                 prevIdxRecive=idxRecive;
444                 // Here should be function to send.
445         }
446
447         return 0;
448 }
449 #endif
450
451
452 static INLINE void blink_odo_send(void)
453 {
454 #ifdef LED_ODO_SEND
455     static bool led;
456     if (led) DEB_LED_ON(LED_ODO_SEND);
457     else DEB_LED_OFF(LED_ODO_SEND);
458     led = !led;
459 #endif
460 }
461
462 /** 
463  * Sends only pxms_ap. Odometry is calculated elsewhere and since we
464  * don't send differences, sequence numbers are not necessary.
465  */
466 static INLINE void sendOdometrySimple()
467 {
468     /* If the variable is static, it is initialized to zero, so we don't have to initialize it all the time again. */
469     static Message m;           
470     int32_t lap, rap;
471
472     lap = mcs_left.pxms_ap;
473     rap = mcs_right.pxms_ap;
474
475     blink_odo_send();
476
477     m.cob_id.w = CAN_ODO_DATA;
478     m.len = 6;
479     /* Data in big-endian, the least significant byte is always zero -
480      * we don't send it */
481     memcpy(&m.data[0], &lap, sizeof(lap)-1);
482     memcpy(&m.data[3], &rap, sizeof(rap)-1);
483     canMsgTransmit(0, m);
484 }
485
486 #if 0
487 static INLINE short storeOdometryInTable()
488 {
489         /*FIXME: add detection of error when idxStore>idxRecive.*/
490         oddata[idxStore].dx=x;
491         oddata[idxStore].dy=y;
492         oddata[idxStore].angle=alfa;
493         // Start to count from zero ;)
494         x=0;    y=0;    alfa=0;
495         idxStore++;
496         idxStore%=ODOMETRY_TABLE_SIZE;
497
498         return 0;
499 }
500 #endif
501
502
503 static INLINE void blink_err_led(void)
504 {
505 #ifdef LED_ERROR
506         static bool err_led = false;
507         err_led = !err_led;
508         if (err_led) DEB_LED_ON(LED_ERROR);
509         else DEB_LED_OFF(LED_ERROR);
510 #endif
511 }
512
513 static INLINE void handle_motor_errors() {
514     static unsigned last_msg_time=0;
515     int i;
516     pxmc_state_t *mcs;
517     
518     if (mcs_left.pxms_flg&PXMS_ERR_m||mcs_right.pxms_flg&PXMS_ERR_m) {
519         pxmc_stop(&mcs_left, 0);
520         pxmc_stop(&mcs_right, 0);
521         if (pxmc_msec_counter - last_msg_time >= 2000) {
522                 blink_err_led();
523             last_msg_time = pxmc_msec_counter;
524             if (mcs_left.pxms_flg&PXMS_ERR_m) print_mcs_err(&mcs_left, "L");
525             if (mcs_right.pxms_flg&PXMS_ERR_m) print_mcs_err(&mcs_right, "R");
526         }
527
528         /* In case of PXMS_E_MAXPD, we wait 3 seconds and then purge the error. */
529         if (( mcs_left.pxms_flg&PXMS_ERR_m &&  mcs_left.pxms_errno == PXMS_E_MAXPD) ||
530             (mcs_right.pxms_flg&PXMS_ERR_m && mcs_right.pxms_errno == PXMS_E_MAXPD)) {
531             static unsigned last_err_time=0;
532             if (last_err_time == 0)
533                 last_err_time = pxmc_msec_counter;
534             if (last_err_time != 0 && (pxmc_msec_counter - last_err_time > 3000)) {
535                 pxmc_for_each_mcs(i, mcs) {
536                     if (mcs->pxms_flg&PXMS_ERR_m &&  mcs->pxms_errno == PXMS_E_MAXPD) {
537                         pxmc_set_const_out(mcs,0);
538                         pxmc_clear_flag(mcs,PXMS_ERR_b);
539                     }
540                 }
541             }
542         }
543     }
544 }
545
546 void led_can_rec(unsigned duration_msec)
547 {
548 #ifdef LED_CAN_REC
549         static unsigned last_rec;
550         static unsigned duration;
551         if (duration_msec) {
552                 last_rec = pxmc_msec_counter;
553                 duration = MAX(duration_msec, duration);
554                 DEB_LED_ON(LED_CAN_REC);
555         } else {
556                 if (pxmc_msec_counter - last_rec > duration) {
557                         duration = 0;
558                         DEB_LED_OFF(LED_CAN_REC);
559                 }
560         }
561 #endif
562 }
563
564 static INLINE void handle_can_receive(void) 
565 {
566     Message msg_rcv;
567
568     while (f_can_receive(0, &msg_rcv)) {
569         switch (msg_rcv.cob_id.w) {
570             case CAN_ODO_RESET: {
571                 unsigned now = pxmc_msec_counter;
572                 wdg_enable(0);              /* 25 us */
573                 while (pxmc_msec_counter - now < 10);
574                 /* Hopefully, we are reset now. */
575                 break;
576             }
577         }
578
579         led_can_rec(5);
580
581 /*         int i; */
582 /*         printf("Received message: id=%lx\n", msg_rcv.cob_id.w); */
583 /*         for (i = 0 ; i < 8; i++) printf("%02x ", msg_rcv.data[i]); */
584 /*         printf("\n"); */
585     }
586     led_can_rec(0);
587 }
588
589 static INLINE void handle_odometry_send()
590 {
591 #define ODOMETRY_PERIOD  50
592 #define ODOMETRY_TIMEOUT (3*ODOMETRY_PERIOD)
593     static unsigned
594         timeout = ODOMETRY_TIMEOUT,
595         last_send_time = 0;
596
597     if (odometry_triggered) {
598         odometry_triggered = false;
599         last_send_time = pxmc_msec_counter;
600         sendOdometrySimple();
601         timeout = ODOMETRY_TIMEOUT;
602     }
603
604     if (pxmc_msec_counter - last_send_time >= timeout) {
605         last_send_time = pxmc_msec_counter;
606         sendOdometrySimple();
607         timeout = ODOMETRY_PERIOD;
608     }
609 }
610
611 static INLINE void blink_main_loop()
612 {
613 #ifdef LED_MAIN_LOOP
614         static bool led = false;
615         led = !led;
616         if (led) DEB_LED_ON(LED_MAIN_LOOP);
617         else DEB_LED_OFF(LED_MAIN_LOOP);
618 #endif
619
620 }
621
622 static INLINE void handle_leds()
623 {
624 #define PERIOD 1000
625         static unsigned last=0;
626         static bool on=false;
627         if (pxmc_msec_counter-last >= PERIOD/2) {
628                 last += PERIOD/2;
629                 on = !on;
630                 if (on) {
631 #ifdef LED_LIVE
632                         DEB_LED_ON(LED_LIVE);
633 #endif                  
634                 } else {
635 #ifdef LED_LIVE
636                         DEB_LED_OFF(LED_LIVE);
637 #endif
638 #ifdef LED_RESET
639                         DEB_LED_OFF(LED_RESET);
640 #endif
641                 }
642         }
643         
644 #undef PERIOD
645
646         blink_main_loop();
647 }
648
649 void _print(char *ptr);
650 int main()
651 {
652     cli();
653     excptvec_initfill(unhandled_exception, 0);
654     sci_rs232_setmode(19200, 0, 0, sci_rs232_chan_default); //PC
655     DEB_LED_ON(LED_RESET);
656     wdg_enable(6);              /* 420 ms */
657     sti();
658     _print("CPU initialized\r\n\r\n");
659
660     printf("Eurobot odometry application.\n"
661            "Copyright (C) 2005-2011 PiKRON s.r.o., P. Pisa, M. Sojka and others.\n"
662            "This is free software; see the source code for copying conditions.\n"
663            "There is ABSOLUTELY NO WARRANTY; not even for MERCHANTABILITY or\n"
664            "FITNESS FOR A PARTICULAR PURPOSE.\n\n");
665     
666     pxmc_initialize();
667     printf("PXMC odometry initialized (motor: %s)", pxmc_variant);
668     printf("\n");
669
670     int32_t receive_id[] = { CAN_ODO_RESET, -1 };
671     canInit(0, 1000000, receive_id);
672     printf("CAN initialized\n");
673
674     do {
675         wdg_clear();
676         handle_can_receive();
677         handle_odometry_send();
678         handle_motor_errors();
679
680         cmd_processor_run(&cmd_io_rs232_line, cmd_list_default);  // run command processor on serial line
681
682         handle_leds();
683
684         if (runtime_display) {
685             //printf("c=%d idx=%d\n", test_counter, test_index);
686             //printf("ene=%d\n", mcs_left.pxms_ene);
687             //printf("rs=%ld as=%ld\n", mcs_left.pxms_rs,  mcs_left.pxms_as);
688         }
689     } while (1);
690
691     return 0;
692 };