|
Fast Research Interface Library
Manual and Documentation
|
00001 /*{{[PH] 00002 **************************************************************************** 00003 Project: FRI 00004 00005 This material is the exclusive property of KUKA Roboter GmbH 00006 and must be returned to KUKA Roboter GmbH immediately upon 00007 request. This material and the information illustrated or 00008 contained herein may not be used, reproduced, stored in a 00009 retrieval system, or transmitted in whole or in part in any 00010 way - electronic, mechanical, photocopying, recording, or 00011 otherwise, without the prior written consent of KUKA Roboter GmbH. 00012 00013 All Rights Reserved 00014 Copyright (C) 2009 00015 KUKA Roboter GmbH 00016 Augsburg, Germany 00017 00018 [PH]}} 00019 */ 00020 00021 /* 00022 {{[FH] 00023 **************************************************************************** 00024 friUdp.cpp 00025 00026 NOTE: This sample, as the corresponding FRI (Fast Research inteface) is subject to radical change 00027 00028 00029 [FH]}} 00030 */ 00031 00032 /* @{ */ 00033 00039 #include "friudp.h" 00040 00041 #ifdef WIN32 00042 #include <winsock2.h> 00043 #pragma comment(lib, "ws2_32.lib") 00044 #endif // WIN32 00045 00046 00047 friUdp::friUdp(int port, char * remoteHost) : serverPort(port) 00048 { 00049 /* check struct sizes */ 00050 if (!FRI_CHECK_SIZES_OK) 00051 { 00052 printf("data structure size error!\n"); 00053 exit(1); 00054 } 00055 00056 m_timestamp=0; 00057 // Make shure, that e.g. simulink uses no stupid standard definition - e.g. 0 00058 if ( serverPort < 10 ) 00059 { 00060 serverPort=FRI_DEFAULT_SERVER_PORT; 00061 } 00062 00063 #ifdef WIN32 00064 StartWinsock(); 00065 #endif 00066 Init(remoteHost); 00067 } 00068 00069 00070 friUdp::~friUdp() 00071 { 00072 Close(); 00073 00074 } 00075 00076 #ifdef WIN32 00077 int friUdp::StartWinsock(void) 00078 { 00079 WSADATA WSAData; 00080 return WSAStartup(MAKEWORD(2,0), &WSAData); 00081 } 00082 #endif// WIN32 00083 00084 void friUdp::Init(char * remoteHost) 00085 { 00086 struct sockaddr_in servAddr; 00087 m_timestamp = 0; 00088 memset(&servAddr, 0, sizeof(servAddr)); 00089 memset(&krcAddr, 0, sizeof(krcAddr)); 00090 00091 /* socket creation */ 00092 udpSock = socket(PF_INET, SOCK_DGRAM, 0); 00093 if (udpSock < 0) 00094 { 00095 printf("opening socket failed!\n"); 00096 exit(1); 00097 } 00098 #ifdef HAVE_TIME_STAMP_RECEIVE 00099 { 00100 int temp = 1; 00101 if (setsockopt(udpSock, SOL_SOCKET, SO_TIMESTAMP, &temp, sizeof(int)) < 0) 00102 { 00103 printf("failed to enable receive time stamps\n"); 00104 exit(1); 00105 } 00106 } 00107 #endif 00108 /* bind local server port */ 00109 servAddr.sin_family = AF_INET; 00110 servAddr.sin_addr.s_addr = htonl(INADDR_ANY); 00111 servAddr.sin_port = htons(serverPort); 00112 00113 if (bind(udpSock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) 00114 { 00115 printf("binding port number %d failed!\n", serverPort); 00116 Close(); 00117 exit(1); 00118 } 00119 // if the remote host is specified, 00120 // preinitialize the socket properly 00121 if ( remoteHost ) 00122 { 00123 printf("preinitialized remote host to %s\n",remoteHost); 00124 krcAddr.sin_addr.s_addr = inet_addr(remoteHost); 00125 krcAddr.sin_family = AF_INET; 00126 krcAddr.sin_port=htons(serverPort); 00127 } 00128 00129 00130 #ifdef HAVE_GETHOSTNAME 00131 /* get IP(s) and port number and display them (just for 00132 convenience, so debugging friOpen is easier) */ 00133 { 00134 char hostname[100]; 00135 struct hostent * host; 00136 int i; 00137 00138 gethostname(hostname, sizeof(hostname)); 00139 host = gethostbyname(hostname); 00140 if (host != NULL) 00141 { 00142 for (i=0; host->h_addr_list[i]!=0; i++) 00143 { 00144 struct in_addr addr; 00145 memcpy(&addr, host->h_addr_list[i], sizeof(addr)); 00146 printf("IP %s - Port %d\n", inet_ntoa(addr), serverPort); 00147 } 00148 } 00149 } 00150 #endif // 00151 00152 00153 } 00154 00155 00156 00157 /* reveive one packet from KRC (blocking!) */ 00158 int friUdp::Recv(tFriMsrData *packet) 00159 { 00160 if (udpSock >= 0) 00161 { 00162 int received; 00163 struct timeval ts; 00164 00165 received = RecvPacket(udpSock, packet, &ts, &krcAddr); 00166 00167 if (received == sizeof(tFriMsrData)) 00168 { 00169 #ifdef HAVE_TIME_STAMP_RECEIVE 00170 00171 /* FIXME: need another #ifdef for VxWorks */ 00172 #ifdef QNX 00173 struct timespec ts; 00174 clock_gettime(CLOCK_REALTIME, &ts); 00175 m_timestamp = (double)ts.tv_sec + (double)ts.tv_nsec/1.0e9; 00176 #else 00177 m_timestamp = (double)ts.tv_sec + (double)ts.tv_usec/1.0e6; 00178 #endif // QNX 00179 #endif // HAVE_TIME_STAMP 00180 return 0; 00181 } 00182 else 00183 { 00184 printf("received something, but wrong size %d (expected %d)...\n",received, (int)sizeof(tFriMsrData)); 00185 fflush(stdout); 00186 } 00187 } 00188 memset(packet, 0, sizeof(tFriMsrData)); 00189 return -1; 00190 } 00191 00192 00193 00194 /* send one answer packet to KRC */ 00195 int friUdp::Send(tFriCmdData *data) 00196 { 00197 krcAddr.sin_family = AF_INET; 00198 #ifdef KRC_IP_ADDRESS 00199 krcAddr.sin_addr.s_addr = inet_addr(KRC_IP_ADDRESS); 00200 #endif 00201 #ifdef KRC_RECEIVE_PORT 00202 krcAddr.sin_port = htons(KRC_RECEIVE_PORT); 00203 #endif 00204 00205 if ((udpSock >= 0) && (ntohs(krcAddr.sin_port) != 0)) 00206 { 00207 int sent; 00208 sent = sendto(udpSock, (char *) data, sizeof(tFriCmdData), 0, 00209 (struct sockaddr *)&krcAddr, sizeof(krcAddr)); 00210 if (sent == sizeof(tFriCmdData)) 00211 { 00212 return 0; 00213 } 00214 } 00215 return -1; 00216 } 00217 00218 00219 00220 00221 /* close the socket */ 00222 void friUdp::Close(void) 00223 { 00224 if (udpSock >= 0) 00225 { 00226 #ifdef WIN32 00227 closesocket(udpSock); 00228 WSACleanup(); 00229 #else 00230 close(udpSock); 00231 #endif 00232 } 00233 udpSock = -1; 00234 } 00235 00236 00237 #ifdef HAVE_TIME_STAMP_RECEIVE 00238 // Socket option SO_TIMESTAMP is supported 00239 /* receive with timestamp */ 00240 int friUdp::RecvPacket(int fd, tFriMsrData* p, struct timeval* ts, struct sockaddr_in* client) 00241 { 00242 struct msghdr msg; 00243 struct iovec vec[1]; 00244 union { 00245 struct cmsghdr cm; 00246 char control[20]; 00247 } cmsg_un; 00248 struct cmsghdr *cmsg; 00249 struct timeval *tv = NULL; 00250 int n; 00251 00252 vec[0].iov_base = p; 00253 vec[0].iov_len = sizeof(*p); 00254 00255 memset(&msg, 0, sizeof(msg)); 00256 memset(&cmsg_un, 0, sizeof(cmsg_un)); 00257 00258 msg.msg_name = (caddr_t)client; 00259 if(client) 00260 msg.msg_namelen = sizeof(*client); 00261 else 00262 msg.msg_namelen = 0; 00263 msg.msg_iov = vec; 00264 msg.msg_iovlen = 1; 00265 msg.msg_control = cmsg_un.control; 00266 msg.msg_controllen = sizeof(cmsg_un.control); 00267 msg.msg_flags = 0; 00268 00269 n = recvmsg(fd, &msg, 0); // MSG_DONTWAIT 00270 if(n < 0) { 00271 perror("recvmsg"); 00272 return -1; 00273 } 00274 if(msg.msg_flags & MSG_TRUNC) { 00275 printf("received truncated message\n"); 00276 return -1; 00277 } 00278 if(!ts) 00279 return n; 00280 00281 /* get time stamp of packet */ 00282 if(msg.msg_flags & MSG_CTRUNC) { 00283 printf("received truncated ancillary data\n"); 00284 return -1; 00285 } 00286 if(msg.msg_controllen < sizeof(cmsg_un.control)) { 00287 printf("received short ancillary data (%d/%d)\n", msg.msg_controllen, (int)sizeof(cmsg_un.control)); 00288 return -1; 00289 } 00290 for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 00291 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP) 00292 tv = (struct timeval *)CMSG_DATA(cmsg); 00293 } 00294 if(tv) { 00295 ts->tv_sec = tv->tv_sec; 00296 ts->tv_usec = tv->tv_usec; 00297 } 00298 return n; 00299 } 00300 00301 #else 00302 /* receive with timestamp */ 00303 int friUdp::RecvPacket(int udpSock, tFriMsrData* data, struct timeval* ts, struct sockaddr_in* client) 00304 { 00305 00306 if (udpSock >= 0) 00307 { 00308 #ifdef WIN32 00309 int sockAddrSize = sizeof(struct sockaddr_in); 00310 #else 00311 socklen_t sockAddrSize = sizeof(struct sockaddr_in); 00312 #endif 00313 00314 int received; 00315 00316 received = recvfrom(udpSock, (char *) data, sizeof(tFriMsrData), 0, 00317 (struct sockaddr *)&krcAddr, &sockAddrSize); 00318 00319 return received; 00320 } 00321 return -1; 00322 } 00323 00324 #endif // HAVE_TIME_STAMP_RECEIVE 00325 00326 00327 #ifdef VXWORKS //USE_BERKELEY_PACKAGE_FILTER_VXWORKS 00328 #define DEBUG_BPF_READ 00329 00330 #include "vxworks.h" 00331 #include "bpfDrv.h" 00332 #include "ioLib.h" 00333 #include <logLib.h> 00334 #include <sys/ioctl.h> 00335 //#include "drv/netif/smNetLib.h" 00336 #include <wrn/coreip/net/ethernet.h> 00337 #include <wrn/coreip/net/if.h> 00338 #include <wrn/coreip/netinet/ip.h> 00339 #include <wrn/coreip/netinet/udp.h> 00340 00341 #ifdef DEBUG_BPF_READ 00342 #include <iostream> 00343 #include "friremote.h" 00344 00345 #endif 00346 00347 00348 /* 00349 * Packet filter program... 00350 * 00351 * XXX: Changes to the filter program may require changes to the 00352 * constant offsets used in if_register_send to patch the BPF program! 00353 */ 00354 struct bpf_insn friUpdSock_bpf_filter[] = { 00355 /* Make sure this is an IP packet... */ 00356 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), 00357 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8), 00358 00359 /* Make sure it's a UDP packet... */ 00360 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23), 00361 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6), 00362 00363 /* Make sure this isn't a fragment... */ 00364 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), 00365 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0), 00366 00367 /* Get the IP header length... */ 00368 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14), 00369 00370 /* Make sure it's to the right port... */ 00371 BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16), 00372 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */ 00373 00374 /* If we passed all the tests, ask for the whole packet. */ 00375 BPF_STMT(BPF_RET+BPF_K, (u_int)-1), 00376 00377 /* Otherwise, drop it. */ 00378 BPF_STMT(BPF_RET+BPF_K, 0), 00379 }; 00380 00381 int friUpdSock_bpf_filter_len = sizeof(friUpdSock_bpf_filter) / sizeof(struct bpf_insn); 00382 struct bpf_program mybpf; 00383 00384 00385 void testBPF1(int socketPort, char * devName) 00386 { 00387 00388 int bpffd = 0; 00389 struct bpf_hdr * buf = NULL; 00390 char * pbuffer = NULL; 00391 int buflen; 00392 int len,i; 00394 char dev[8] = "gei0"; 00395 struct ifreq ifr; 00396 int trueValue=1; 00397 int Rcvlen; 00398 00399 if ( socketPort <= 10) socketPort = 12345; 00400 if ( devName != NULL ) 00401 { 00402 strncpy(dev,devName,8); 00403 dev[8]=0; 00404 } 00405 mybpf.bf_len = friUpdSock_bpf_filter_len; 00406 mybpf.bf_insns = friUpdSock_bpf_filter; 00407 00408 00409 /* Patch the server port into the BPF program... 00410 * 00411 * XXX: changes to filter program may require changes to the 00412 * insn number(s) used below! 00413 */ 00414 friUpdSock_bpf_filter[8].k = socketPort; 00415 00416 bpfDrv(); 00417 00418 if ( bpfDevCreate("/dev/bpf",2,4096) == ERROR) 00419 { 00420 printf("bpfDevCreate failed \n"); 00421 return; 00422 } 00423 bpffd = open( "/dev/bpf0",0,0); 00424 if ( bpffd <= 0) 00425 { 00426 printf("open /dev/bpf0 failed\n"); 00427 return; 00428 } 00429 00430 memset(&ifr, sizeof(struct ifreq), 0); 00431 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); 00432 #define IOCTRL_CAST_THIRD_ARG (int) 00433 00434 00435 00436 if (ioctl(bpffd,BIOCIMMEDIATE, IOCTRL_CAST_THIRD_ARG &trueValue) < 0) 00437 { 00438 printf("Error BIOCIMMEDIATE \n"); 00439 00440 } 00441 00442 00443 00444 if (ioctl(bpffd,(BIOCSETF),IOCTRL_CAST_THIRD_ARG (caddr_t)(&mybpf)) < 0) 00445 { 00446 perror("Error BIOCSETF \n"); 00447 goto errorMark; 00448 } 00449 00450 if (ioctl(bpffd,(BIOCSETIF),IOCTRL_CAST_THIRD_ARG (caddr_t)&ifr) < 0) 00451 { 00452 printf("ERROR BIOCSETIF %s \n",dev); 00453 goto errorMark; 00454 00455 00456 } 00457 if (ioctl(bpffd,BIOCGBLEN, IOCTRL_CAST_THIRD_ARG &buflen) < 0) 00458 { 00459 printf("Error BIOCGBLEN \n"); 00460 00461 } 00462 00463 00464 if (buflen > 4096) buflen=4096; 00465 buf = (struct bpf_hdr *)malloc(buflen); 00466 //bzero(buf,buflen); 00467 memset(buf,0x0,buflen); 00468 while ((len = read(bpffd,(char *)buf,buflen)) != 0) 00469 { 00470 // im bpf header steht noch ein Timestamp -- waere gut fuer Timing thematik 00471 // 00472 00473 // Empfangene Rohdaten ohne bpf Header 00474 pbuffer = (char *)buf + buf->bh_hdrlen; 00475 00476 // Empfangene Rohdatenlaenge ohne bpf Header 00477 Rcvlen = len - (buf->bh_hdrlen); 00478 // 00479 // Wie trennt man nun die "Nutzdaten" von den Verwaltungsdaten?? 00480 // 00481 00482 struct ip * iph = (struct ip *) ((char *) buf + buf->bh_hdrlen + sizeof(struct ether_header)); 00483 struct udphdr * udph = (struct udphdr *) ((char *) iph + sizeof(struct ip)); 00484 char * userData = ((char *) udph) + sizeof( struct udphdr); 00485 00486 tFriCmdData * cmd = ( tFriCmdData * ) userData; 00487 #ifdef DEBUG_BPF_READ 00488 printf("recvLen %d\n",Rcvlen); 00489 printf("IP SRC:\t\t%s\n", inet_ntoa(iph->ip_src)); 00490 printf("IP DST:\t\t%s\n", inet_ntoa(iph->ip_dst)); 00491 printf("UDP SRC:\t%u\n", ntohs(udph->uh_sport)); 00492 printf("UDP DST:\t%u\n", ntohs(udph->uh_dport)); 00493 printf("Len #:\t\t%u\n", ntohs(udph->uh_ulen)); 00494 #endif 00495 00496 logMsg("BUF LEN = 0x%x\n",Rcvlen,0,0,0,0,0); 00497 00498 std::cout << (*cmd) << std::endl; 00499 for (i=0;i< ntohs(udph->uh_ulen);i++) 00500 { 00501 printf(" %2x", userData[i]); 00502 if ((i % 10) == 9) 00503 { 00504 printf("\n");//,0,0,0,0,0,0); 00505 } 00506 } 00507 printf("\nFull packet \n"); 00508 for (i=0;i< Rcvlen;i++) 00509 { 00510 printf(" %2x(%4d)", pbuffer[i],pbuffer[i]); 00511 if ((i % 10) == 9) 00512 { 00513 printf("\n");//,0,0,0,0,0,0); 00514 } 00515 } 00516 } 00517 errorMark: 00518 printf("leaving %s\n",__PRETTY_FUNCTION__); 00519 if ( buf) 00520 free(buf); 00521 if ( bpffd > 0 ) 00522 close (bpffd); 00523 bpfDevDelete("/dev/bpf"); 00524 00525 } 00526 00527 00528 00529 #endif 00530 00531 00532 /***************************************************************************** 00533 $Log: $ 00534 *****************************************************************************/ 00535 00536 00537 00538 /* @} */