]> rtime.felk.cvut.cz Git - eurobot/public.git/blob - src/cand/cand.cc
Update Makefile.rules to support .cpp extension of C++ sources
[eurobot/public.git] / src / cand / cand.cc
1 /**
2  * @file   cand.cc
3  * @date   08/04/08
4  * 
5  * @brief  CAN-ORTE bridge
6  * 
7  * Copyright: (c) 2008 CTU Dragons
8  *            CTU FEE - Department of Control Engineering
9  * License: GNU GPL v.2
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #include <config.h>
14 #endif
15
16 #include <cstring>
17 #include <iostream>
18 #include <cstdlib>
19 #include <sys/socket.h>
20 #include <sys/ioctl.h>
21 #include <fcntl.h>
22 #include <poll.h>
23
24 #include <af_can.h>
25 #include <canutils.h>
26
27 #include <can_ids.h>
28 #include <can_msg_masks.h>
29 #include <can_msg_def.h>
30 #include <sharp.h>
31 #include <orte.h>
32 #include <roboorte_robottype.h>
33 #include <can_msg_masks.h>
34 #include "cand.h"
35
36 int cand_init()
37 {
38         if ((sock = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
39                 perror("cand: unable to create a socket");
40                 return -1;
41         }
42
43         can_addr.can_family = AF_CAN;
44         std::strcpy(can_ifreq.ifr_name, "can0");
45
46         if (ioctl(sock, SIOCGIFINDEX, &can_ifreq) < 0) {
47                 perror("cand: SIOCGIFINDEX");
48                 return -2;
49         }
50
51         can_addr.can_ifindex = can_ifreq.ifr_ifindex;
52                 
53         if (!can_addr.can_ifindex) {
54                 perror("cand: invalid socket interface");
55                 return -3;
56         }
57
58         if (bind(sock, (struct sockaddr *)&can_addr, sizeof(can_addr)) < 0) {
59                 perror("cand: unable to bind");
60                 return -4;
61         }
62
63         return 0;
64 }
65
66 int set_pwr_ctrl(struct robottype_orte_data *orte_data)
67 {
68         unsigned char data=0;
69         if(orte_data->pwr_ctrl.voltage33)
70                 data |= CAN_PWR_CTRL_33_ON;
71         else
72                 data |= CAN_PWR_CTRL_33_OFF;
73
74         if(orte_data->pwr_ctrl.voltage50)
75                 data |= CAN_PWR_CTRL_50_ON;
76         else
77                 data |= CAN_PWR_CTRL_50_OFF;
78
79         if(orte_data->pwr_ctrl.voltage80)
80                 data |= CAN_PWR_CTRL_80_ON;
81         else
82                 data |= CAN_PWR_CTRL_80_OFF;
83
84         can_send(CAN_PWR, 1, &data);
85
86         return 0;
87 }
88
89 int send_can_msg(struct robottype_orte_data *orte_data)
90 {
91         return can_send(orte_data->can_msg.id, orte_data->can_msg.len, orte_data->can_msg.data);
92 }
93
94 int set_motor_speed(struct robottype_orte_data *orte_data)
95 {
96         unsigned char data[4];
97
98         data[0] = orte_data->motion_speed.right >> 8;
99         data[1] = orte_data->motion_speed.right & 0xff;
100         data[2] = orte_data->motion_speed.left >> 8;
101         data[3] = orte_data->motion_speed.left & 0xff;
102         can_send(CAN_MOTION_CMD, 4, data);
103
104         return 0;
105 }
106
107 int set_jaws_cmd(struct robottype_orte_data *orte_data)
108 {
109         unsigned char data[3];
110
111         data[0] = orte_data->jaws_cmd.req_pos.left >> 8;
112         data[1] = orte_data->jaws_cmd.req_pos.left & 0xff;
113         data[2] = orte_data->jaws_cmd.speed.left;
114         can_send(CAN_JAW_LEFT_CMD, 3, data);
115
116         data[0] = orte_data->jaws_cmd.req_pos.right >> 8;
117         data[1] = orte_data->jaws_cmd.req_pos.right & 0xff;
118         data[2] = orte_data->jaws_cmd.speed.right;
119         can_send(CAN_JAW_RIGHT_CMD, 3, data);
120
121         return 0;
122 }
123
124 int set_lift_cmd(struct robottype_orte_data *orte_data)
125 {
126         unsigned char data[4];
127
128         data[0] = orte_data->lift_cmd.req_pos >> 8;
129         data[1] = orte_data->lift_cmd.req_pos & 0xff;
130         data[2] = orte_data->lift_cmd.speed;
131         data[3] = orte_data->lift_cmd.homing;
132         can_send(CAN_LIFT_CMD, 4, data);
133
134         return 0;
135 }
136
137 int can_send(canid_t id, unsigned char length, unsigned char *data)
138 {
139         struct can_frame frame;
140         size_t size;
141
142         frame.can_id = id;
143         frame.can_dlc = length;
144
145         for(int i=0; i<length; i++)
146                 frame.data[i] = data[i];
147
148         if ((size = write(sock, &frame, sizeof(struct can_frame))) < 0) {
149                 perror("cand: can send: write()");
150                 return -1;
151         } else if (size < sizeof(struct can_frame)) {
152                 perror("cand: can send: incomplete CAN frame\n");
153                 return 1;
154         }
155
156         return 0;
157 }
158
159 /**
160  * Parse frame ID and react as required
161  */
162 void cand_parse_frame(struct robottype_orte_data *orte, struct can_frame frame)
163 {
164         static int status_cnt = 0;
165
166         switch(frame.can_id) {
167                 /* robot commands (start, ..) */
168                 case CAN_JAW_LEFT_STATUS:
169                         orte->jaws_status.act_pos.left = (frame.data[0] << 8) | frame.data[1];
170                         orte->jaws_status.response.left = (frame.data[2] << 8) | frame.data[3];
171                         orte->jaws_status.flags.left = frame.data[4];
172                         ORTEPublicationSend(orte->publication_jaws_status);
173                         break;
174                 case CAN_JAW_RIGHT_STATUS:
175                         orte->jaws_status.act_pos.right = (frame.data[0] << 8) | frame.data[1];
176                         orte->jaws_status.response.right = (frame.data[2] << 8) | frame.data[3];
177                         orte->jaws_status.flags.right = frame.data[4];
178                         ORTEPublicationSend(orte->publication_jaws_status);
179                 break;
180                 case CAN_LIFT_STATUS:
181                         orte->lift_status.act_pos = (frame.data[0] << 8) | frame.data[1];
182                         orte->lift_status.response = (frame.data[2] << 8) | frame.data[3];
183                         orte->lift_status.flags = frame.data[4];
184                         ORTEPublicationSend(orte->publication_lift_status);
185                 break;
186                 case CAN_ROBOT_CMD:
187                         orte->robot_cmd.start_condition = frame.data[0];
188                         ORTEPublicationSend(orte->publication_robot_cmd);
189                         break;
190                 case CAN_ROBOT_SWITCHES:
191                         orte->robot_switches.team_color = (frame.data[0] & CAN_SWITCH_COLOR) ? 1 : 0;
192                         orte->robot_switches.strategy = (frame.data[0] & CAN_SWITCH_STRATEGY ? 1 : 0);
193                         ORTEPublicationSend(orte->publication_robot_switches);
194                         break;
195                 case CAN_ROBOT_BUMPERS:
196                         orte->robot_bumpers.bumper_left = (frame.data[0] & CAN_BUMPER_LEFT) ? 0 : 1;
197                         orte->robot_bumpers.bumper_left_across = (frame.data[0] & CAN_BUMPER_LEFT_ACROSS) ? 0 : 1;
198                         orte->robot_bumpers.bumper_right = (frame.data[0] & CAN_BUMPER_RIGHT) ? 0 : 1;
199                         orte->robot_bumpers.bumper_right_across = (frame.data[0] & CAN_BUMPER_RIGHT_ACROSS) ? 0 : 1;
200                         orte->robot_bumpers.bumper_rear_left = (frame.data[0] & CAN_BUMPER_REAR_LEFT) ? 0 : 1;
201                         orte->robot_bumpers.bumper_rear_right = (frame.data[0] & CAN_BUMPER_REAR_RIGHT) ? 0 : 1;
202                         ORTEPublicationSend(orte->publication_robot_bumpers);
203                 break;
204
205                 /* positioning by odometry */
206                 case CAN_ODO_DATA:
207                         orte->odo_data.right =
208                                         ((frame.data[0]<<24)|
209                                          (frame.data[1]<<16)|
210                                          (frame.data[2]<<8));
211                         orte->odo_data.left =
212                                         ((frame.data[3]<<24)|
213                                          (frame.data[4]<<16)|
214                                          (frame.data[5]<<8));
215                         ORTEPublicationSend(orte->publication_odo_data);
216                         break;
217
218                 /* positioning by odometry */
219                 case CAN_MOTION_ODOMETRY_SIMPLE:
220                         orte->motion_irc.left =
221                                         ((frame.data[0]<<24)|
222                                          (frame.data[1]<<16)|
223                                          (frame.data[2]<<8));
224                         orte->motion_irc.right =
225                                         ((frame.data[3]<<24)|
226                                          (frame.data[4]<<16)|
227                                          (frame.data[5]<<8));
228                         orte->motion_irc.seq = frame.data[6];
229                         ORTEPublicationSend(orte->publication_motion_irc);
230                         break;
231
232                 /* motion status */
233                 case CAN_MOTION_STATUS:
234                         orte->motion_status.err_left =
235                                         (frame.data[0]<<8)|(frame.data[1]);
236                         orte->motion_status.err_right =
237                                         (frame.data[2]<<8)|(frame.data[3]);
238                         if(++status_cnt == 2) { // h8eurobot sends duplicite can messages
239                                 ORTEPublicationSend(orte->publication_motion_status);
240                                 status_cnt = 0;
241                         }
242                         break;
243                 /* voltage measurements from power board */
244                 case CAN_PWR_ADC1:
245                         double volt33, voltBAT;
246                         voltBAT = ((frame.data[0] << 24) | (frame.data[1] << 16) | \
247                                  (frame.data[2] << 8) | (frame.data[3]))/10000.0;
248                         volt33 = ((frame.data[4] << 24) | (frame.data[5] << 16) | \
249                                  (frame.data[6] << 8) | (frame.data[7]))/10000.0;
250                         orte->pwr_voltage.voltage33 = volt33;
251                         orte->pwr_voltage.voltageBAT = voltBAT;
252                         break;
253
254                 case CAN_PWR_ADC2:
255                         double volt80, volt50;
256                         volt50 = ((frame.data[0] << 24) | (frame.data[1] << 16) | \
257                                  (frame.data[2] << 8) | (frame.data[3]))/10000.0;
258                         volt80 = ((frame.data[4] << 24) | (frame.data[5] << 16) | \
259                                  (frame.data[6] << 8) | (frame.data[7]))/10000.0;
260                         orte->pwr_voltage.voltage80 = volt80;
261                         orte->pwr_voltage.voltage50 = volt50;
262
263                         ORTEPublicationSend(orte->publication_pwr_voltage);
264                         
265                         break;
266
267                 case CAN_PWR_ALERT:
268                         orte->pwr_alert.alert_33 = (frame.data[0] & CAN_PWR_ALERT_33 ? 1 : 0);
269                         orte->pwr_alert.alert_50 = (frame.data[0] & CAN_PWR_ALERT_50 ? 1 : 0);
270                         orte->pwr_alert.alert_80 = (frame.data[0] & CAN_PWR_ALERT_80 ? 1 : 0);
271                         orte->pwr_alert.bat_full = (frame.data[0] & CAN_PWR_BATT_FULL ? 1 : 0);
272                         orte->pwr_alert.bat_mean = (frame.data[0] & CAN_PWR_BATT_MEAN ? 1 : 0);
273                         orte->pwr_alert.bat_low = (frame.data[0] & CAN_PWR_BATT_LOW ? 1 : 0);
274                         orte->pwr_alert.bat_critical = (frame.data[0] & CAN_PWR_BATT_CRITICAL ? 1 : 0);
275
276                         ORTEPublicationSend(orte->publication_pwr_alert);
277                         break;
278
279                 default:
280                         //FIXME: add logging here (Filip)
281 //                      printf("received CAN msg with unknown id: %x\n",frame.can_id);
282                         break;
283         }
284 }
285
286 void rcv_pwr_ctrl_cb (const ORTERecvInfo *info, void *vinstance, 
287                         void *recvCallBackParam) 
288 {
289         struct robottype_orte_data *orte_data = (struct robottype_orte_data *)recvCallBackParam;
290
291         switch (info->status) {
292                 case NEW_DATA:
293                         set_pwr_ctrl(orte_data);
294                         break;
295                 case DEADLINE:
296                         //printf("ORTE deadline occurred - PWR_CTRL receive\n");
297                         break;
298         }
299 }
300
301 void rcv_can_msg_cb (const ORTERecvInfo *info, void *vinstance, 
302                         void *recvCallBackParam) 
303 {
304         struct robottype_orte_data *orte_data = (struct robottype_orte_data *)recvCallBackParam;
305
306         switch (info->status) {
307                 case NEW_DATA:
308                         send_can_msg(orte_data);
309                         break;
310                 case DEADLINE:
311                         //printf("ORTE deadline occurred - PWR_CTRL receive\n");
312                         break;
313         }
314 }
315
316 void rcv_motion_speed_cb(const ORTERecvInfo *info, void *vinstance, 
317                                 void *recvCallBackParam)
318 {
319         struct robottype_orte_data *orte_data = (struct robottype_orte_data *)recvCallBackParam;
320
321         switch (info->status) {
322                 case NEW_DATA:
323                         /* reversing motion direction, as it is different, than last year */
324                         orte_data->motion_speed.left *= 1;
325                         orte_data->motion_speed.right *= 1;
326                         set_motor_speed(orte_data);
327                         /*printf("motor cmd received\n");*/
328                         break;
329                 case DEADLINE:
330                         //printf("motor cmd deadline occurred, stopping motors\n");
331                         orte_data->motion_speed.left = 0;
332                         orte_data->motion_speed.right = 0;
333                         set_motor_speed(orte_data);
334                         break;
335         }
336 }
337
338 void rcv_jaws_cmd_cb(const ORTERecvInfo *info, void *vinstance,
339                       void *recvCallBackParam)
340 {
341         struct robottype_orte_data *orte_data = (struct robottype_orte_data *)recvCallBackParam;
342
343         switch (info->status) {
344                 case NEW_DATA:
345                         set_jaws_cmd(orte_data);
346                         break;
347                 case DEADLINE:
348                         break;
349         }
350 }
351
352 void rcv_lift_cmd_cb(const ORTERecvInfo *info, void *vinstance,
353                       void *recvCallBackParam)
354 {
355         struct robottype_orte_data *orte_data = (struct robottype_orte_data *)recvCallBackParam;
356
357         switch (info->status) {
358                 case NEW_DATA:
359                         set_lift_cmd(orte_data);
360                         break;
361                 case DEADLINE:
362                         break;
363 }
364 }
365
366 int main(int argc, char *argv[])
367 {
368         int ret;
369         int size;
370
371         struct robottype_orte_data orte;
372         struct can_frame frame;
373
374         if (cand_init() < 0) {
375                 printf("cand: init failed\n");
376                 exit(1);
377         } else {
378                 printf("cand: init OK\n");
379         }
380
381         orte.strength = 1;
382
383         /* orte initialization */
384         if(robottype_roboorte_init(&orte)) {
385                 printf("Roboorte initialization failed! Exiting...\n");
386                 exit(-1);
387         }
388         else
389                 printf("Roboorte OK\n");
390
391         /* creating publishers */
392         robottype_publisher_pwr_voltage_create(&orte, NULL, NULL);
393         robottype_publisher_motion_status_create(&orte, NULL, NULL);
394         robottype_publisher_odo_data_create(&orte, NULL, NULL);
395         robottype_publisher_motion_irc_create(&orte, NULL, NULL);
396         robottype_publisher_robot_cmd_create(&orte, NULL, NULL);
397         robottype_publisher_robot_switches_create(&orte, NULL, NULL);
398         robottype_publisher_robot_bumpers_create(&orte, NULL, NULL);
399         robottype_publisher_jaws_status_create(&orte, NULL, NULL);
400         robottype_publisher_lift_status_create(&orte, NULL, NULL);
401         printf("Publishers OK\n");
402
403         /* creating subscribers */
404         robottype_subscriber_pwr_ctrl_create(&orte, rcv_pwr_ctrl_cb, &orte);
405         robottype_subscriber_motion_speed_create(&orte, rcv_motion_speed_cb, &orte);
406         robottype_subscriber_jaws_cmd_create(&orte, rcv_jaws_cmd_cb, &orte);
407         robottype_subscriber_lift_cmd_create(&orte, rcv_lift_cmd_cb, &orte);
408         robottype_subscriber_can_msg_create(&orte, rcv_can_msg_cb, &orte);
409
410
411         printf("subscribers OK\n");
412
413         /* main loop */
414         for(;;) {
415                 struct pollfd pfd[1] = {{sock, POLLIN, 0}};
416
417                 ret = poll(pfd, 1, -1);
418                 if (ret < 0) {
419                         perror("cand: poll() error");
420                         goto err;
421                 }
422
423                 /* timeout expired, nothing to be done */
424                 if (ret == 0)
425                         continue;
426
427                 /* read data from SocketCAN */
428                 size = read(sock, &frame, sizeof(struct can_frame));
429
430                 /* parse data */
431                 if (size > 0)
432                         cand_parse_frame(&orte, frame);
433         }
434         return EXIT_SUCCESS;
435
436 err:
437         close(sock);
438         return 1;
439 }