00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #include <fcntl.h>
00042 #include <stdlib.h>
00043 #include <unistd.h>
00044 #include <termios.h>
00045 #include <sys/time.h>
00046 #include <stdio.h>
00047 #include <ctype.h>
00048 #include <string.h>
00049
00050 #if defined(_WIN32)
00051 #include <windows.h>
00052 #else
00053 #include <sys/ioctl.h>
00054 #include <errno.h>
00055 #endif
00056
00057 #include "rcx_comm.h"
00058
00059
00060
00061 #define BUFFERSIZE 4096
00062
00063
00064
00065 int __comm_debug = 0;
00066 extern int tty_usb;
00067
00068
00069
00070 typedef struct timeval timeval_t;
00071
00072 #define tvupdate(tv) gettimeofday(tv,NULL)
00073 #define tvsec(tv) ((tv)->tv_sec)
00074 #define tvmsec(tv) ((tv)->tv_usec * 1e-3)
00075
00076 static float
00077 timer_reset(timeval_t *timer)
00078 {
00079 tvupdate(timer);
00080 return 0;
00081 }
00082
00083 static float
00084 timer_read(timeval_t *timer)
00085 {
00086 timeval_t now;
00087 tvupdate(&now);
00088 return tvsec(&now) - tvsec(timer) + (tvmsec(&now) - tvmsec(timer)) * 1e-3;
00089 }
00090
00091 void myperror(char *str) {
00092 #if defined(_WIN32)
00093 fprintf(stderr, "Error %lu: %s\n", (unsigned long) GetLastError(), str);
00094 #else
00095 perror(str);
00096 #endif
00097 }
00098
00099
00100
00101 static int nbread (FILEDESCR fd, void *buf, int maxlen, int timeout)
00102 {
00103 char *bufp = (char *)buf;
00104 int len = 0;
00105 #if defined(LINUX) | defined(linux)
00106 int count;
00107 fd_set fds;
00108 struct timeval tv;
00109 #endif
00110
00111 while (len < maxlen) {
00112
00113 #if defined(_WIN32)
00114 if(tty_usb) {
00115
00116
00117 DWORD count = 0;
00118 struct timeval timebegin ,timenow;
00119 unsigned long elapsed;
00120
00121 gettimeofday(&timebegin,0);
00122 while(count==0) {
00123 ReadFile( fd, &bufp[len], maxlen - len, &count, NULL);
00124 gettimeofday(&timenow,0);
00125 elapsed = (timenow.tv_sec - timebegin.tv_sec ) + (timenow.tv_usec - timebegin.tv_usec);
00126 if(elapsed > timeout)
00127 break;
00128 }
00129 if(count==0) {
00130 if(__comm_debug)
00131 printf("Hary Mahesan - USB mode: nbread(len=%d, maxlen=%d) break...timed out\n", len, maxlen);
00132 break;
00133 }
00134 len += count;
00135 } else {
00136
00137 DWORD count = 0;
00138 COMMTIMEOUTS CommTimeouts;
00139
00140 GetCommTimeouts (fd, &CommTimeouts);
00141
00142
00143 CommTimeouts.ReadIntervalTimeout = MAXDWORD;
00144 CommTimeouts.ReadTotalTimeoutMultiplier = 0;
00145 CommTimeouts.ReadTotalTimeoutConstant = timeout;
00146 CommTimeouts.WriteTotalTimeoutMultiplier = 10;
00147 CommTimeouts.WriteTotalTimeoutConstant = 1000;
00148
00149
00150
00151 SetCommTimeouts(fd, &CommTimeouts);
00152
00153 if (ReadFile(fd, &bufp[len], maxlen - len, &count, NULL) == FALSE) {
00154 myperror("ReadFile");
00155 fprintf(stderr, "nb_read - error reading tty: %lu\n", (unsigned long) GetLastError());
00156 exit(1);
00157 }
00158
00159 len += count;
00160
00161 if (count == 0) {
00162 if(__comm_debug)
00163 printf("Serial mode: nbread(len=%d, maxlen=%d) break...timed out\n", len, maxlen);
00164 break;
00165 }
00166 }
00167 #else
00168 if (tty_usb == 1)
00169 {
00170
00171
00172
00173
00174 ioctl(fd, _IOW('u', 0xc8, int), timeout);
00175 }
00176 else
00177 {
00178 FD_ZERO(&fds);
00179 FD_SET(fd, &fds);
00180
00181 tv.tv_sec = timeout / 1000;
00182 tv.tv_usec = (timeout % 1000) * 1000;
00183
00184 if (select(fd+1, &fds, NULL, NULL, &tv) < 0) {
00185 perror("select");
00186 exit(1);
00187 }
00188 if (!FD_ISSET(fd, &fds))
00189 break;
00190 }
00191
00192 count = read(fd, &bufp[len], maxlen - len);
00193
00194
00195
00196 if (tty_usb == 1 && count == -1 && errno == ETIMEDOUT)
00197 {
00198 break;
00199 }
00200
00201 if (count < 0) {
00202 perror("read");
00203 exit(1);
00204 }
00205
00206 len += count;
00207 #endif
00208
00209 }
00210
00211 return len;
00212 }
00213
00214
00215 static void rx_flush(FILEDESCR fd)
00216 {
00217 #if defined(_WIN32)
00218 if (tty_usb == 0) {
00219 PurgeComm(fd, PURGE_RXABORT | PURGE_RXCLEAR);
00220 } else {
00221 char echo[BUFFERSIZE];
00222 nbread(fd, echo, BUFFERSIZE, 200);
00223 }
00224 #else
00225 char echo[BUFFERSIZE];
00226 nbread(fd, echo, BUFFERSIZE, 200);
00227 #endif
00228 }
00229
00230 int mywrite(FILEDESCR fd, const void *buf, size_t len) {
00231 #if defined(_WIN32)
00232 DWORD nBytesWritten=0;
00233 WriteFile(fd, buf, len, &nBytesWritten, NULL);
00234 return nBytesWritten;
00235 #else
00236
00237
00238
00239
00240
00241 int actual = 0;
00242 int rc;
00243 char * cptr;
00244 int retry = 1000;
00245
00246 if (len < 1) return len;
00247 cptr = (char *) buf;
00248 while (actual < len) {
00249 rc = (long) write(fd, cptr+actual, len-actual);
00250 if (rc == -1) {
00251 if ((errno == EINTR) || (errno == EAGAIN)) {
00252 rc = 0;
00253 usleep(10);
00254 retry --;
00255 } else return -1;
00256 }
00257 actual += rc;
00258 if (retry < 1) return actual;
00259 }
00260 return len;
00261 #endif
00262 }
00263
00264
00265
00266 FILEDESCR rcx_init(char *tty, int is_fast)
00267 {
00268 FILEDESCR fd;
00269
00270 #if defined(_WIN32)
00271 DCB dcb;
00272 #else
00273 struct termios ios;
00274 #endif
00275
00276 if (__comm_debug) printf("mode = %s\n", is_fast ? "fast" : "slow");
00277
00278 #if defined(_WIN32)
00279
00280 if ((fd = CreateFile(tty, GENERIC_READ | GENERIC_WRITE,
00281 0, NULL, OPEN_EXISTING,
00282 0, NULL)) == INVALID_HANDLE_VALUE) {
00283 fprintf(stderr, "Error %lu: Opening %s\n", (unsigned long) GetLastError(), tty);
00284 exit(1);
00285 }
00286
00287
00288 if(tty_usb==0) {
00289
00290 FillMemory(&dcb, sizeof(dcb), 0);
00291 if (!GetCommState(fd, &dcb)) {
00292
00293 myperror("GetCommState");
00294 exit(1);
00295 } else {
00296 dcb.ByteSize = 8;
00297 dcb.Parity = (is_fast ? 0 : 1);
00298 dcb.StopBits = 0;
00299 dcb.fBinary = TRUE ;
00300 dcb.fParity = (is_fast ? FALSE : TRUE) ;
00301 dcb.fAbortOnError = FALSE ;
00302 dcb.BaudRate = (is_fast ? CBR_4800 : CBR_2400);
00303
00304
00305 if (!SetCommState(fd, &dcb)) {
00306
00307
00308 myperror("SetCommState");
00309 exit(1);
00310 }
00311 }
00312 }
00313
00314 #else
00315
00316 if ((fd = open(tty, O_RDWR)) < 0) {
00317 fprintf(stderr,"ERROR: tty=%s, ",tty);
00318 perror("open");
00319 exit(1);
00320 }
00321
00322 if (tty_usb == 0){
00323 if (!isatty(fd)) {
00324 close(fd);
00325 fprintf(stderr, "%s: not a tty\n", tty);
00326 exit(1);
00327 }
00328
00329 memset(&ios, 0, sizeof(ios));
00330
00331 ios.c_cflag = CREAD | CLOCAL | CS8 | (is_fast ? 0 : PARENB | PARODD);
00332
00333 cfsetispeed(&ios, is_fast ? B4800 : B2400);
00334 cfsetospeed(&ios, is_fast ? B4800 : B2400);
00335
00336 if (tcsetattr(fd, TCSANOW, &ios) == -1) {
00337 perror("tcsetattr");
00338 exit(1);
00339 }
00340 }
00341 #endif
00342
00343 return fd;
00344 }
00345
00346 void rcx_close(FILEDESCR fd)
00347 {
00348 #if defined(_WIN32)
00349 CloseHandle(fd);
00350 #else
00351 close(fd);
00352 #endif
00353 }
00354
00355 int rcx_wakeup_tower (FILEDESCR fd, int timeout)
00356 {
00357 char msg[] = { 0x10, 0xfe, 0x10, 0xfe };
00358 char keepalive = 0xff;
00359 char buf[BUFFERSIZE];
00360 timeval_t timer;
00361 int count = 0;
00362 int len;
00363
00364
00365 mywrite(fd, &keepalive, 1);
00366 usleep(20000);
00367 rx_flush(fd);
00368
00369 timer_reset(&timer);
00370
00371 do {
00372 if (__comm_debug) {
00373 printf("writelen = %d\n", sizeof(msg));
00374 hexdump("W", msg, sizeof(msg));
00375 }
00376 if (mywrite(fd, msg, sizeof(msg)) != sizeof(msg)) {
00377 myperror("write");
00378 exit(1);
00379 }
00380 count += len = nbread(fd, buf, BUFFERSIZE, 50);
00381 if (len == sizeof(msg) && !memcmp(buf, msg, sizeof(msg)))
00382 return RCX_OK;
00383 if (__comm_debug) {
00384 printf("recvlen = %d\n", len);
00385 hexdump("R", buf, len);
00386 }
00387 rx_flush(fd);
00388 } while (timer_read(&timer) < (float)timeout / 1000.0f);
00389
00390 if (!count)
00391 return RCX_NO_TOWER;
00392 else
00393 return RCX_BAD_LINK;
00394 }
00395
00396
00397
00398 #define LINE_SIZE 16
00399 #define GROUP_SIZE 4
00400 #define UNPRINTABLE '.'
00401
00402 void hexdump(char *prefix, void *buf, int len)
00403 {
00404 unsigned char *b = (unsigned char *)buf;
00405 int i, j, w;
00406
00407 for (i = 0; i < len; i += w) {
00408 w = len - i;
00409 if (w > LINE_SIZE)
00410 w = LINE_SIZE;
00411 if (prefix)
00412 printf("%s ", prefix);
00413 printf("%04x: ", i);
00414 for (j = 0; j < w; j++, b++) {
00415 printf("%02x ", *b);
00416 if ((j + 1) % GROUP_SIZE == 0)
00417 putchar(' ');
00418 }
00419 putchar('\n');
00420 }
00421 }
00422
00423
00424 int rcx_send (FILEDESCR fd, void *buf, int len, int use_comp)
00425 {
00426 char *bufp = (char *)buf;
00427 char buflen = len;
00428 char msg[BUFFERSIZE];
00429 char echo[BUFFERSIZE];
00430 int msglen, echolen;
00431 int sum;
00432 int tty_usb_echo = 0;
00433
00434
00435
00436 msglen = 0;
00437 sum = 0;
00438
00439 if (use_comp) {
00440 msg[msglen++] = 0x55;
00441 msg[msglen++] = 0xff;
00442 msg[msglen++] = 0x00;
00443 while (buflen--) {
00444 msg[msglen++] = *bufp;
00445 msg[msglen++] = (~*bufp) & 0xff;
00446 sum += *bufp++;
00447 }
00448 msg[msglen++] = sum;
00449 msg[msglen++] = ~sum;
00450 }
00451 else {
00452 msg[msglen++] = 0xff;
00453 while (buflen--) {
00454 msg[msglen++] = *bufp;
00455 sum += *bufp++;
00456 }
00457 msg[msglen++] = sum;
00458 }
00459
00460
00461
00462 if (mywrite(fd, msg, msglen) != msglen) {
00463 myperror("write");
00464 exit(1);
00465 }
00466
00467
00468
00469
00470 if(tty_usb == tty_usb_echo) {
00471
00472 echolen = nbread(fd, echo, msglen, 100);
00473
00474 if (__comm_debug) {
00475 printf("msglen = %d, echolen = %d\n", msglen, echolen);
00476 hexdump("C", echo, echolen);
00477 }
00478
00479
00480
00481
00482 if (echolen != msglen ) {
00483
00484 rx_flush(fd);
00485 return RCX_BAD_ECHO;
00486 }
00487 }
00488
00489 return len;
00490 }
00491
00492 int rcx_recv (FILEDESCR fd, void *buf, int maxlen, int timeout, int use_comp)
00493 {
00494 char *bufp = (char *)buf;
00495 unsigned char msg[BUFFERSIZE];
00496 int msglen;
00497 int sum;
00498 int pos;
00499 int len;
00500
00501
00502
00503 msglen = nbread(fd, msg, BUFFERSIZE, timeout);
00504
00505 if (__comm_debug) {
00506 printf("recvlen = %d\n", msglen);
00507 hexdump("R", msg, msglen);
00508 }
00509
00510
00511
00512 if (!msglen)
00513 return RCX_NO_RESPONSE;
00514
00515
00516
00517 if (use_comp) {
00518 if (msglen < 5 || (msglen - 3) % 2 != 0)
00519 return RCX_BAD_RESPONSE;
00520
00521 if (msg[0] != 0x55 || msg[1] != 0xff || msg[2] != 0x00)
00522 return RCX_BAD_RESPONSE;
00523
00524 for (sum = 0, len = 0, pos = 3; pos < msglen - 2; pos += 2) {
00525 if (msg[pos] != ((~msg[pos+1]) & 0xff))
00526 return RCX_BAD_RESPONSE;
00527 sum += msg[pos];
00528 if (len < maxlen)
00529 bufp[len++] = msg[pos];
00530 }
00531
00532 if (msg[pos] != ((~msg[pos+1]) & 0xff))
00533 return RCX_BAD_RESPONSE;
00534
00535 if (msg[pos] != (sum & 0xff))
00536 return RCX_BAD_RESPONSE;
00537
00538
00539 return len;
00540 }
00541 else {
00542 if (msglen < 4)
00543 return RCX_BAD_RESPONSE;
00544
00545 if (msg[0] != 0x55 || msg[1] != 0xff || msg[2] != 0x00)
00546 return RCX_BAD_RESPONSE;
00547
00548 for (sum = 0, len = 0, pos = 3; pos < msglen - 1; pos++) {
00549 sum += msg[pos];
00550 if (len < maxlen)
00551 bufp[len++] = msg[pos];
00552 }
00553
00554
00555 if (msg[pos] == (sum & 0xff))
00556 return len;
00557
00558
00559 for (sum = 0, len = 0, pos = 3; pos < msglen - 2; pos++) {
00560 sum += msg[pos];
00561 if (len < maxlen)
00562 bufp[len++] = msg[pos];
00563 }
00564
00565
00566 if (msg[pos] == (sum & 0xff))
00567 return len;
00568
00569
00570
00571
00572 for (sum = 0, len = 0, pos = 3; pos < msglen - 1; pos++) {
00573 if (pos == 4) {
00574 if (msg[3] != ((~msg[4]) & 0xff))
00575 return RCX_BAD_RESPONSE;
00576 }
00577 else {
00578 sum += msg[pos];
00579 if (len < maxlen)
00580 bufp[len++] = msg[pos];
00581 }
00582 }
00583
00584 if (msg[pos] != (sum & 0xff))
00585 return RCX_BAD_RESPONSE;
00586
00587
00588 return len;
00589 }
00590 }
00591
00592 int rcx_sendrecv (FILEDESCR fd, void *send, int slen, void *recv, int rlen,
00593 int timeout, int retries, int use_comp)
00594 {
00595 int status = 0;
00596
00597 if (__comm_debug) printf("sendrecv %d:\n", slen);
00598
00599 while (retries--) {
00600 if ((status = rcx_send(fd, send, slen, use_comp)) < 0) {
00601 if (__comm_debug) printf("status = %s\n", rcx_strerror(status));
00602 continue;
00603 }
00604 if ((status = rcx_recv(fd, recv, rlen, timeout, use_comp)) < 0) {
00605 if (__comm_debug) printf("status = %s\n", rcx_strerror(status));
00606 continue;
00607 }
00608 break;
00609 }
00610
00611 if (__comm_debug) {
00612 if (status > 0)
00613 printf("status = %s\n", rcx_strerror(0));
00614 else
00615 printf("status = %s\n", rcx_strerror(status));
00616 }
00617
00618 return status;
00619 }
00620
00621 int rcx_is_alive (FILEDESCR fd, int use_comp)
00622 {
00623 unsigned char send[1] = { 0x10 };
00624 unsigned char recv[1];
00625
00626 return (rcx_sendrecv(fd, send, 1, recv, 1, 50, 5, use_comp) == 1);
00627 }
00628
00629 char *rcx_strerror (int error)
00630 {
00631 switch (error) {
00632 case RCX_OK: return "no error";
00633 case RCX_NO_TOWER: return "tower not responding";
00634 case RCX_BAD_LINK: return "bad ir link";
00635 case RCX_BAD_ECHO: return "bad ir echo";
00636 case RCX_NO_RESPONSE: return "no response from rcx";
00637 case RCX_BAD_RESPONSE: return "bad response from rcx";
00638 default: return "unknown error";
00639 }
00640 }
00641