00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <sys/ioctl.h>
00022 #include <sys/uio.h>
00023 #include <net/if.h>
00024
00025 #include <sys/socket.h>
00026 #include <linux/can.h>
00027 #include <linux/can/raw.h>
00028
00029 #include <unistd.h>
00030
00031 #include <string>
00032 #include <iostream>
00033
00034 #include <cstring>
00035
00036 #include <dashel/dashel.h>
00037 #include <dashel/dashel-posix.h>
00038
00039 #include "../../common/consts.h"
00040
00041 #ifndef AF_CAN
00042 #define AF_CAN 29
00043 #endif
00044 #ifndef PF_CAN
00045 #define PF_CAN AF_CAN
00046 #endif
00047
00048 #ifndef SO_RXQ_OVFL
00049 #define SO_RXQ_OVFL 40
00050 #endif
00051
00052 using namespace Dashel;
00053 using namespace std;
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 class CanStream: public SelectableStream
00071 {
00072 #define TYPE_SMALL_PACKET 0x3
00073 #define TYPE_PACKET_NORMAL 0x0
00074 #define TYPE_PACKET_START 0x1
00075 #define TYPE_PACKET_STOP 0x2
00076
00077 #define CANID_TO_TYPE(canid) ((canid) >> 8)
00078 #define CANID_TO_ID(canid) ((int) ((canid) & 0xFF))
00079 #define TO_CANID(type,id) (((type) << 8) | (id))
00080
00081 protected:
00082 unsigned char tx_buffer[ASEBA_MAX_OUTER_PACKET_SIZE];
00083 int tx_len;
00084 unsigned char rx_buffer[ASEBA_MAX_OUTER_PACKET_SIZE];
00085 unsigned int rx_len;
00086 unsigned int rx_p;
00087
00088 struct iovec iov;
00089 struct msghdr msg;
00090 struct sockaddr_can addr;
00091 char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))];
00092 struct can_frame rframe;
00093
00094 #define RX_CAN_SIZE 1000
00095 struct {
00096 struct can_frame f;
00097 int used;
00098 } rx_fifo[RX_CAN_SIZE];
00099 int rx_insert;
00100 int rx_consume;
00101 public:
00102 CanStream(const string &targetName) :
00103 Stream("can"),
00104 SelectableStream("can")
00105 {
00106 struct ifreq ifr;
00107
00108 target.add("can:if=can0");
00109 target.add(targetName.c_str());
00110 string ifName;
00111 if(target.isSet("if"))
00112 {
00113 target.addParam("if", NULL, true);
00114 ifName = target.get("if");
00115 }
00116 fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
00117 if(fd < 0)
00118 throw DashelException(DashelException::ConnectionFailed, 0, "Socket creation failed");
00119
00120 addr.can_family = AF_CAN;
00121 if(strlen(ifName.c_str()) >= IFNAMSIZ)
00122 throw DashelException(DashelException::ConnectionFailed, 0, "Interface name too long");
00123
00124 strcpy(ifr.ifr_name, ifName.c_str());
00125 if(ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
00126 throw DashelException(DashelException::ConnectionFailed, 0, "Unable to get interface");
00127
00128
00129 int options = 2*1024*1024;
00130 setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &options, sizeof(options));
00131
00132
00133 options = 1;
00134 setsockopt(fd, SOL_SOCKET, SO_RXQ_OVFL, &options, sizeof(options));
00135
00136 addr.can_ifindex = ifr.ifr_ifindex;
00137 if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
00138 throw DashelException(DashelException::ConnectionFailed, 0, "Unable to bind");
00139
00140 rx_insert = rx_consume = 0;
00141 tx_len = 0;
00142 rx_len = 0;
00143 rx_p = 0;
00144 memset(rx_fifo, 0, sizeof(rx_fifo));
00145 iov.iov_base = &rframe;
00146 msg.msg_iov = &iov;
00147 msg.msg_name = &addr;
00148 msg.msg_iovlen = 1;
00149 msg.msg_control = ctrlmsg;
00150 }
00151 private:
00152 int is_packet_tx(void)
00153 {
00154 int packet_len;
00155 if(tx_len < 6)
00156 return 0;
00157 packet_len = tx_buffer[0] | (tx_buffer[1] << 8);
00158 if(tx_len >= packet_len + 6)
00159 return 1;
00160 return 0;
00161 }
00162
00163 void send_aseba_packet()
00164 {
00165 struct can_frame frame;
00166 unsigned int packet_len = tx_buffer[0] | (tx_buffer[1] << 8);
00167 unsigned int nodeId = tx_buffer[2] | (tx_buffer[3] << 8);
00168 unsigned int msgId = tx_buffer[4] | (tx_buffer[5] << 8);
00169
00170 if(packet_len <= 6)
00171 {
00172
00173 frame.can_id = TO_CANID(TYPE_SMALL_PACKET, nodeId);
00174 frame.can_dlc = packet_len + 2;
00175 frame.data[0] = msgId;
00176 frame.data[1] = msgId >> 8;
00177 memcpy(&frame.data[2], &tx_buffer[6], packet_len);
00178 if(::write(fd,&frame, sizeof(frame)) != sizeof(frame))
00179 throw DashelException(DashelException::IOError, 0, "Write error");
00180 }
00181 else
00182 {
00183 unsigned char * p = &tx_buffer[6];
00184 frame.can_id = TO_CANID(TYPE_PACKET_START, nodeId);
00185 frame.can_dlc = 8;
00186 frame.data[0] = msgId;
00187 frame.data[1] = msgId >> 8;
00188 memcpy(&frame.data[2], p, 6);
00189 p += 6;
00190 packet_len -= 6;
00191 if(::write(fd, &frame, sizeof(frame)) != sizeof(frame))
00192 throw DashelException(DashelException::IOError, 0, "Write error");
00193
00194 while(packet_len > 8)
00195 {
00196 frame.can_id = TO_CANID(TYPE_PACKET_NORMAL, nodeId);
00197 frame.can_dlc = 8;
00198 memcpy(frame.data, p, 8);
00199 p+=8;
00200 packet_len -= 8;
00201 if(::write(fd, &frame, sizeof(frame)) != sizeof(frame))
00202 throw DashelException(DashelException::IOError, 0, "Write error");
00203 }
00204 frame.can_id = TO_CANID(TYPE_PACKET_STOP, nodeId);
00205 frame.can_dlc = packet_len;
00206 memcpy(frame.data, p, packet_len);
00207 if(::write(fd, &frame, sizeof(frame)) != sizeof(frame))
00208 throw DashelException(DashelException::IOError, 0, "Write error");
00209 }
00210 tx_len = 0;
00211 }
00212 public:
00213 virtual void write(const void *data, const size_t size)
00214 {
00215 size_t s = size;
00216 const unsigned char * d = (const unsigned char * ) data;
00217 while(s--)
00218 {
00219 tx_buffer[tx_len++] = *d++;
00220 if(is_packet_tx())
00221 send_aseba_packet();
00222 }
00223 }
00224
00225 virtual void flush()
00226 {
00227 }
00228 private:
00229 void pack_fifo()
00230 {
00231 while(!rx_fifo[rx_consume].used && rx_consume != rx_insert)
00232 {
00233 if(++rx_consume == RX_CAN_SIZE)
00234 rx_consume = 0;
00235 }
00236 }
00237
00238
00239
00240
00241 int defragment(void)
00242 {
00243 int i;
00244 int stopId;
00245 int stopPos = -1;
00246 int ignore = 0;
00247 for(i = rx_consume; i != rx_insert; )
00248 {
00249 if(rx_fifo[i].used)
00250 {
00251 if(CANID_TO_TYPE(rx_fifo[i].f.can_id) == TYPE_SMALL_PACKET)
00252 {
00253 if(rx_fifo[i].f.can_dlc < 2)
00254 throw DashelException(DashelException::IOError, 0, "Packet too short");
00255
00256 rx_buffer[0] = rx_fifo[i].f.can_dlc - 2;
00257 rx_buffer[1] = 0;
00258 rx_buffer[2] = CANID_TO_ID(rx_fifo[i].f.can_id);
00259 rx_buffer[3] = 0;
00260 memcpy(&rx_buffer[4], rx_fifo[i].f.data, rx_fifo[i].f.can_dlc);
00261 rx_p = 0;
00262 rx_len = rx_fifo[i].f.can_dlc + 4;
00263
00264 rx_fifo[i].used = 0;
00265 return 1;
00266 }
00267 if(CANID_TO_TYPE(rx_fifo[i].f.can_id) == TYPE_PACKET_STOP)
00268 {
00269 stopPos = i;
00270 stopId = CANID_TO_ID(rx_fifo[i].f.can_id);
00271 break;
00272 }
00273 }
00274 i++;
00275 if(i == RX_CAN_SIZE)
00276 i = 0;
00277 }
00278 if(stopPos < 0)
00279 return 0;
00280
00281 i = rx_consume;
00282
00283 rx_buffer[2] = stopId;
00284 rx_buffer[3] = 0;
00285 rx_len = 4;
00286 while(1)
00287 {
00288 if(rx_fifo[i].used && CANID_TO_ID(rx_fifo[i].f.can_id) == stopId)
00289 {
00290 if(rx_len == 4 && CANID_TO_TYPE(rx_fifo[i].f.can_id) != TYPE_PACKET_START)
00291
00292 ignore = 1;
00293
00294 if(rx_len + rx_fifo[i].f.can_dlc > sizeof(rx_buffer))
00295 throw DashelException(DashelException::IOError, 0, "Packet too large!");
00296
00297 memcpy(&rx_buffer[rx_len], rx_fifo[i].f.data, rx_fifo[i].f.can_dlc);
00298 rx_len += rx_fifo[i].f.can_dlc;
00299 rx_fifo[i].used = 0;
00300
00301 if(i == stopPos)
00302 break;
00303 }
00304 if(++i == RX_CAN_SIZE)
00305 i = 0;
00306 }
00307 if(ignore)
00308 {
00309 rx_len = 0;
00310 rx_p = 0;
00311 return -1;
00312 }
00313 else
00314 {
00315 rx_buffer[0] = rx_len - 6;
00316 rx_buffer[1] = (rx_len - 6) >> 8;
00317 rx_p = 0;
00318 return 1;
00319 }
00320 }
00321 int fifo_full()
00322 {
00323 int i = rx_insert + 1;
00324 if(i == RX_CAN_SIZE)
00325 i = 0;
00326 return i == rx_consume;
00327 }
00328
00329 void read_iface(void)
00330 {
00331 int def;
00332 while(1)
00333 {
00334 while((def = defragment()) == -1);
00335 if(def == 1)
00336 break;
00337
00338 struct cmsghdr *cmsg;
00339 iov.iov_len = sizeof(rframe);
00340 msg.msg_namelen = sizeof(addr);
00341 msg.msg_controllen = sizeof(ctrlmsg);
00342 msg.msg_flags = 0;
00343 if(recvmsg(fd, &msg, 0) < (int) sizeof(rframe))
00344 throw DashelException(DashelException::IOError, 0, "Read error");
00345
00346 for(cmsg = CMSG_FIRSTHDR(&msg);
00347 cmsg && (cmsg->cmsg_level == SOL_SOCKET);
00348 cmsg = CMSG_NXTHDR(&msg,cmsg))
00349 {
00350 if(cmsg->cmsg_type == SO_RXQ_OVFL)
00351 {
00352 __u32 * dropcnt = (__u32 *) CMSG_DATA(cmsg);
00353 if(*dropcnt)
00354 throw DashelException(DashelException::IOError, 0, "Packet dropped");
00355 }
00356 }
00357
00358 if(fifo_full())
00359 throw DashelException(DashelException::IOError, 0, "Fifo full");
00360
00361
00362 memcpy(&rx_fifo[rx_insert].f,&rframe,sizeof(rframe));
00363 rx_fifo[rx_insert++].used = 1;
00364 if(rx_insert == RX_CAN_SIZE)
00365 rx_insert = 0;
00366 }
00367 pack_fifo();
00368 }
00369 public:
00370 virtual void read(void *data, size_t size)
00371 {
00372 unsigned char * d = (unsigned char *) data;
00373 while(size)
00374 {
00375 if(rx_len)
00376 {
00377 *d++ = rx_buffer[rx_p++];
00378 rx_len--;
00379 size--;
00380 }
00381 else
00382 {
00383 read_iface();
00384 }
00385 }
00386 }
00387
00388 virtual bool receiveDataAndCheckDisconnection()
00389 {
00390 return false;
00391 }
00392
00393 virtual bool isDataInRecvBuffer() const
00394 {
00395 struct can_frame f;
00396 if(rx_len || rx_insert != rx_consume)
00397 return true;
00398
00399 if(recv(fd, &f, sizeof(f), MSG_DONTWAIT | MSG_PEEK) == sizeof(f))
00400 return true;
00401
00402 return false;
00403 }
00404
00405
00406 };
00407
00408 namespace Dashel
00409 {
00410 void initPlugins()
00411 {
00412 Dashel::streamTypeRegistry.reg("can", &createInstance<CanStream>);
00413 }
00414 }