00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "rlserial.h"
00022
00023 #ifdef RLUNIX
00024 #include <stdio.h>
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 #include <fcntl.h>
00028 #include <termios.h>
00029 #include <unistd.h>
00030 #include <signal.h>
00031 #endif
00032
00033 #ifdef __VMS
00034 #include <stdio.h>
00035 #include <string.h>
00036 #include <stdlib.h>
00037 #include <starlet.h>
00038 #include <descrip.h>
00039 #include <lib$routines.h>
00040 #include <ssdef.h>
00041 #include <iodef.h>
00042 typedef struct
00043 {
00044 short iostat;
00045 unsigned short msg_len;
00046 int reader_pid;
00047 }IOSB;
00048 #endif
00049
00050 #ifdef RLWIN32
00051 #include <windows.h>
00052 #include <stdio.h>
00053 #endif
00054
00055 #ifdef RM3
00056 #include <stdio.h>
00057 #include <stdlib.h>
00058 #include <rmcomp.h>
00059 #include <rmapi.h>
00060 #include <rio.h>
00061 #include <drvspec.h>
00062 #include <rm3cav.h>
00063
00064 #include <rcinc.h>
00065 #define RTS_TIME_WAIT 0x008
00066 #endif
00067
00068 #include "rlthread.h"
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 rlSerial::rlSerial()
00082 {
00083 ttysavefd = -1;
00084 ttystate = RESET;
00085 fd = -1;
00086 trace = 0;
00087 }
00088
00089 rlSerial::~rlSerial()
00090 {
00091 closeDevice();
00092 }
00093
00094 void rlSerial::setTrace(int on)
00095 {
00096 if(on == 1) trace = 1;
00097 else trace = 0;
00098 }
00099
00100 int rlSerial::openDevice(const char *devicename, int speed, int block, int rtscts, int bits, int stopbits, int parity)
00101 {
00102 #ifdef RLUNIX
00103 struct termios buf;
00104
00105 if(fd != -1) return -1;
00106 fd = open(devicename, O_RDWR | O_NOCTTY | O_NDELAY);
00107 if(fd < 0) { return -1; }
00108
00109
00110
00111 if(tcgetattr(fd, &save_termios) < 0) { return -1; }
00112 buf = save_termios;
00113 buf.c_cflag = speed | CLOCAL | CREAD;
00114 if(rtscts == 1) buf.c_cflag |= CRTSCTS;
00115 if(bits == 7) buf.c_cflag |= CS7;
00116 else buf.c_cflag |= CS8;
00117 if(stopbits == 2) buf.c_cflag |= CSTOPB;
00118 if(parity == rlSerial::ODD) buf.c_cflag |= (PARENB | PARODD);
00119 if(parity == rlSerial::EVEN) buf.c_cflag |= PARENB;
00120 buf.c_lflag = IEXTEN;
00121 buf.c_oflag = OPOST;
00122 buf.c_cc[VMIN] = 1;
00123 buf.c_cc[VTIME] = 0;
00124 #ifndef PVMAC
00125 buf.c_line = 0;
00126 #endif
00127 buf.c_iflag = IGNBRK | IGNPAR | IXANY;
00128 if(tcsetattr(fd, TCSAFLUSH, &buf) < 0) { return -1; }
00129
00130 ttystate = RAW;
00131 ttysavefd = fd;
00132 if(block == 1) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
00133 tcflush(fd,TCIOFLUSH);
00134 #endif
00135
00136 #ifdef __VMS
00137
00138 struct dsc$descriptor_s dsc;
00139 int status;
00140
00141 dsc.dsc$w_length = strlen(devicename);
00142 dsc.dsc$a_pointer = (char *) devicename;
00143 dsc.dsc$b_class = DSC$K_CLASS_S;
00144 dsc.dsc$b_dtype = DSC$K_DTYPE_T;
00145 status = SYS$ASSIGN(&dsc,&vms_channel,0,0);
00146 if(status != SS$_NORMAL) return -1;
00147 #endif
00148
00149 #ifdef RLWIN32
00150 DWORD ccsize;
00151 COMMCONFIG cc;
00152 int baudrate,ret;
00153 char devname[100];
00154
00155 if(strlen(devicename) > 80) return -1;
00156 sprintf(devname,"\\\\.\\%s",devicename);
00157 hdl = CreateFile(
00158 devname,
00159 GENERIC_READ | GENERIC_WRITE,
00160 0,
00161 0,
00162 OPEN_EXISTING,
00163 0,
00164 0
00165 );
00166 if(hdl == INVALID_HANDLE_VALUE)
00167 {
00168 printf("CreateFile(%s) failed\n",devicename);
00169 return -1;
00170 }
00171
00172 baudrate = CBR_9600;
00173 if(speed == B50 ) baudrate = 50;
00174 if(speed == B75 ) baudrate = 75;
00175 if(speed == B110 ) baudrate = CBR_110;
00176 if(speed == B134 ) baudrate = 134;
00177 if(speed == B150 ) baudrate = 150;
00178 if(speed == B200 ) baudrate = 200;
00179 if(speed == B300 ) baudrate = CBR_300;
00180 if(speed == B600 ) baudrate = CBR_600;
00181 if(speed == B1200 ) baudrate = CBR_1200;
00182 if(speed == B1800 ) baudrate = 1800;
00183 if(speed == B2400 ) baudrate = CBR_2400;
00184 if(speed == B4800 ) baudrate = CBR_4800;
00185 if(speed == B9600 ) baudrate = CBR_9600;
00186 if(speed == B19200 ) baudrate = CBR_19200;
00187 if(speed == B38400 ) baudrate = CBR_38400;
00188 if(speed == B57600 ) baudrate = CBR_57600;
00189 if(speed == B115200 ) baudrate = CBR_115200;
00190 if(speed == B230400 ) baudrate = 230400;
00191 if(speed == B460800 ) baudrate = 460800;
00192 if(speed == B500000 ) baudrate = 500000;
00193 if(speed == B576000 ) baudrate = 576000;
00194 if(speed == B921600 ) baudrate = 921600;
00195 if(speed == B1000000) baudrate = 1000000;
00196 if(speed == B1152000) baudrate = 1152000;
00197 if(speed == B1500000) baudrate = 1500000;
00198 if(speed == B2000000) baudrate = 2000000;
00199 if(speed == B2500000) baudrate = 2500000;
00200 if(speed == B3000000) baudrate = 3000000;
00201 if(speed == B3500000) baudrate = 3500000;
00202 if(speed == B4000000) baudrate = 4000000;
00203
00204 GetCommConfig(hdl,&cc,&ccsize);
00205
00206
00207
00208
00209 cc.dcb.DCBlength = sizeof(DCB);
00210 cc.dcb.BaudRate = baudrate;
00211 cc.dcb.fBinary = 1;
00212 cc.dcb.fParity = 1;
00213 cc.dcb.fOutxCtsFlow = 0;
00214 if(rtscts == 1) cc.dcb.fOutxCtsFlow = 1;
00215 cc.dcb.fOutxDsrFlow = 0;
00216 cc.dcb.fDtrControl = DTR_CONTROL_DISABLE;
00217 cc.dcb.fDsrSensitivity = 0;
00218 cc.dcb.fTXContinueOnXoff = 1;
00219
00220
00221
00222 cc.dcb.fNull = 0;
00223 cc.dcb.fRtsControl = RTS_CONTROL_DISABLE;
00224 if(rtscts == 1) cc.dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
00225 cc.dcb.fAbortOnError = 0;
00226
00227
00228
00229
00230 cc.dcb.ByteSize = bits;
00231 cc.dcb.Parity = 0;
00232 if(parity == rlSerial::ODD) cc.dcb.Parity = 1;
00233 if(parity == rlSerial::EVEN) cc.dcb.Parity = 2;
00234 cc.dcb.StopBits = ONESTOPBIT;
00235 if(stopbits==2) cc.dcb.StopBits = TWOSTOPBITS;
00236
00237
00238
00239
00240
00241
00242 cc.dwProviderSubType = PST_RS232;
00243
00244
00245
00246
00247 ret = SetCommConfig(hdl,&cc,sizeof(cc));
00248 if(ret == 0)
00249 {
00250 printf("SetCommConfig ret=%d devicename=%s LastError=%d\n",ret,devicename,GetLastError());
00251 return -1;
00252 }
00253 #endif
00254
00255 #ifdef RM3
00256 RmEntryStruct CatEntry;
00257 int iStatus;
00258 RmIOStatusStruct DrvSts;
00259 RmBytParmStruct PBlock;
00260 static UCD_BYT_PORT Ucd_byt_drv;
00261 ushort uTimeBd;
00262 uint uMode;
00263 unsigned char cByte;
00264
00265
00266 char byt_com[32];
00267
00268
00269 if (strcmp(devicename,"COM1") == 0)
00270 {
00271 strcpy(byt_com,"BYT_COM1");
00272 com = 0x3f8;
00273 }
00274 else if(strcmp(devicename,"COM2") == 0)
00275 {
00276 strcpy(byt_com,"BYT_COM2");
00277 com = 0x2f8;
00278 }
00279 else
00280 {
00281 printf("Error: devicename=%s unknown\n",devicename);
00282 return -1;
00283 }
00284
00285
00286
00287
00288
00289 if( RmGetEntry( RM_WAIT, byt_com, &CatEntry ) != RM_OK )
00290 {
00291 printf( "Error: %s device not found\n", byt_com);
00292 return -1;
00293 }
00294
00295 device = (int) ((ushort) CatEntry.ide);
00296 unit = (int) CatEntry.id;
00297
00298
00299
00300
00301 if( RmIO( BYT_RESERVE, (unsigned)(device), (unsigned)(unit), 0u, 0u, &DrvSts, &PBlock ) < 0 )
00302 {
00303 printf( "Error: Unable to reserve %s device\n", byt_com);
00304 return -1;
00305 }
00306
00307
00308
00309
00310 baudrate = 9600;
00311 if(speed == B50 ) baudrate = 50;
00312 if(speed == B75 ) baudrate = 75;
00313 if(speed == B110 ) baudrate = 110;
00314 if(speed == B134 ) baudrate = 134;
00315 if(speed == B150 ) baudrate = 150;
00316 if(speed == B200 ) baudrate = 200;
00317 if(speed == B300 ) baudrate = 300;
00318 if(speed == B600 ) baudrate = 600;
00319 if(speed == B1200 ) baudrate = 1200;
00320 if(speed == B1800 ) baudrate = 1800;
00321 if(speed == B2400 ) baudrate = 2400;
00322 if(speed == B4800 ) baudrate = 4800;
00323 if(speed == B9600 ) baudrate = 9600;
00324 if(speed == B19200 ) baudrate = 19200;
00325 if(speed == B38400 ) baudrate = 38400;
00326 if(speed == B57600 ) baudrate = 57600;
00327 if(speed == B115200 ) baudrate = 115200;
00328 if(speed == B230400 ) baudrate = 230400;
00329 if(speed == B460800 ) baudrate = 460800;
00330 if(speed == B500000 ) baudrate = 500000;
00331 if(speed == B576000 ) baudrate = 576000;
00332 if(speed == B921600 ) baudrate = 921600;
00333 if(speed == B1000000) baudrate = 1000000;
00334 if(speed == B1152000) baudrate = 1152000;
00335 if(speed == B1500000) baudrate = 1500000;
00336 if(speed == B2000000) baudrate = 2000000;
00337 if(speed == B2500000) baudrate = 2500000;
00338 if(speed == B3000000) baudrate = 3000000;
00339 if(speed == B3500000) baudrate = 3500000;
00340 if(speed == B4000000) baudrate = 4000000;
00341 uTimeBd = 748800 / baudrate;
00342
00343
00344
00345
00346 uMode = 0x1000 | DATA_8 | STOP_1 | NOPARITY;
00347
00348
00349
00350
00351 PBlock.string = 0;
00352 PBlock.strlen = 0;
00353 PBlock.buffer = (char *)&Ucd_byt_drv;
00354 PBlock.timlen = sizeof(UCD_BYT_PORT);
00355 PBlock.status = 0;
00356
00357 iStatus = RmIO( BYT_CREATE_NEW, (unsigned)(device), (unsigned)(unit), 0u, 0u, &DrvSts, &PBlock );
00358
00359
00360
00361
00362 Ucd_byt_drv.mobyte[5] |= (ushort) (uMode & 0xFFu);
00363
00364
00365
00366
00367 Ucd_byt_drv.header.timout = timeout;
00368
00369
00370
00371
00372 PBlock.string = (char*) &Ucd_byt_drv;
00373 PBlock.strlen = sizeof(UCD_BYT_PORT);
00374 PBlock.buffer = 0;
00375 PBlock.timlen = 0;
00376 PBlock.status = 0;
00377
00378 iStatus = RmIO( BYT_CREATE_NEW, (unsigned)(device), (unsigned)(unit), 0u, 0u, &DrvSts, &PBlock );
00379
00380
00381
00382
00383 cByte = inbyte( com + 0x03 );
00384 outbyte( com + 0x03, (unsigned char)(cByte | 0x80) );
00385
00386
00387
00388
00389 outbyte( com + 0x00, (ushort) LOW (uTimeBd) );
00390 outbyte( com + 0x01, (ushort) HIGH (uTimeBd) );
00391
00392
00393
00394
00395 outbyte( com + 0x03, cByte );
00396
00397 if( iStatus ) printf( "BYT_CREATE_NEW (set ucb): Error status = %X\n", iStatus );
00398 #endif
00399
00400 return 0;
00401 }
00402
00403 int rlSerial::readChar()
00404 {
00405 #ifdef RLUNIX
00406 int ret;
00407 unsigned char buf[2];
00408
00409 if(fd == -1) return -1;
00410 ret = read(fd,buf,1);
00411 if(ret == 1) return buf[0];
00412 if(ret == 0) return -2;
00413 return -1;
00414 #endif
00415
00416 #ifdef __VMS
00417 unsigned char buf[2];
00418
00419 if(readBlock(buf, 1) < 0) return -1;
00420 return buf[0];
00421 #endif
00422
00423 #ifdef RLWIN32
00424 BOOL ret;
00425 unsigned char buf[2];
00426 unsigned long len;
00427
00428 ret = ReadFile(
00429 hdl,
00430 buf,
00431 1,
00432 &len,
00433 NULL
00434 );
00435 if(len > 0)
00436 {
00437 if(trace == 1) printf("readChar %d\n",(int) buf[0]);
00438 return buf[0];
00439 }
00440 return -1;
00441 #endif
00442
00443 #ifdef RM3
00444 int ret;
00445 unsigned char buf[2];
00446
00447 ret = readBlock(buf,1);
00448 if(ret < 0) return ret;
00449 return buf[0];
00450 #endif
00451 }
00452
00453 int rlSerial::writeChar(unsigned char uchar)
00454 {
00455 #ifdef RLUNIX
00456 int ret;
00457 if(fd == -1) return -1;
00458 if(trace == 1) printf("writeChar %d\n",(int)uchar);
00459 ret = write(fd,&uchar,1);
00460 if(ret < 0) return -1;
00461
00462 return ret;
00463 #endif
00464
00465 #ifdef __VMS
00466 int status;
00467 IOSB iosb;
00468
00469 status = SYS$QIOW(0,vms_channel,IO$_WRITEVBLK | IO$M_CANCTRLO | IO$M_NOFORMAT,
00470 &iosb,0,0,&uchar,1,0,0,0,0);
00471 if(status != SS$_NORMAL) return -1;
00472 return 1;
00473 #endif
00474
00475 #ifdef RLWIN32
00476 BOOL ret;
00477 unsigned long len;
00478
00479 if(trace == 1) printf("writeChar %d\n",(int)uchar);
00480 ret = WriteFile(
00481 hdl,
00482 &uchar,
00483 1,
00484 &len,
00485 NULL
00486 );
00487
00488 if(ret) return (int) len;
00489 return -1;
00490 #endif
00491
00492 #ifdef RM3
00493 return writeBlock(&uchar, 1);
00494 #endif
00495 }
00496
00497 int rlSerial::readBlock(unsigned char *buf, int len, int timeout)
00498 {
00499 #ifdef RLUNIX
00500 int c, retlen;
00501
00502 retlen = 0;
00503 for(int i=0; i<len; i++)
00504 {
00505 if(timeout >= 0)
00506 {
00507 if(select(timeout) == 0) break;
00508 }
00509 c = readChar();
00510 if(c < 0) return c;
00511 buf[i] = (unsigned char) c;
00512 retlen = i+1;
00513 }
00514 if(retlen <= 0) return -1;
00515 return retlen;
00516 #endif
00517
00518 #ifdef __VMS
00519 int status;
00520 int _timeout = 1;
00521 short iosb[4];
00522
00523 status = SYS$QIOW(0,vms_channel,
00524 IO$_READVBLK | IO$M_NOFILTR | IO$M_NOECHO | IO$M_TIMED,
00525 iosb,0,0,buf,len,_timeout,0,0,0);
00526 if(status != SS$_NORMAL) return -1;
00527 len=iosb[1];
00528 if(iosb[2] != 0)
00529 {
00530 len++;
00531 buf[len] = iosb[2];
00532 }
00533 return len;
00534 #endif
00535
00536 #ifdef RLWIN32
00537 BOOL ret;
00538 unsigned long retlen;
00539
00540 if(timeout >= 0) select(timeout);
00541 ret = ReadFile(
00542 hdl,
00543 buf,
00544 len,
00545 &retlen,
00546 NULL
00547 );
00548 if(retlen > 0)
00549 {
00550 if(trace == 1) printf("readBlock retlen=%d\n",retlen);
00551 return (int) retlen;
00552 }
00553 return -1;
00554 #endif
00555
00556 #ifdef RM3
00557 RmBytParmStruct PBlock;
00558 RmIOStatusStruct DrvSts;
00559 int iStatus;
00560 int i;
00561
00562
00563
00564
00565
00566 PBlock.string = 0;
00567 PBlock.strlen = 0;
00568 PBlock.buffer = (char*)buf;
00569 PBlock.timlen = len;
00570 PBlock.status = 0;
00571
00572
00573
00574
00575 iStatus = RmIO( BYT_POLL_XBUF_WAIT, (unsigned)device, (unsigned)unit, 0u, 0u, &DrvSts, &PBlock );
00576
00577 if( iStatus ) printf( "BYT_POLL_XBUF_WAIT (set ucb): Error status = %X\n", iStatus );
00578
00579 if( !iStatus ) return len;
00580 return -1;
00581 #endif
00582 }
00583
00584 int rlSerial::writeBlock(const unsigned char *buf, int len)
00585 {
00586 #ifdef RLUNIX
00587 int ret;
00588
00589 if(fd == -1) return -1;
00590 if(trace == 1)
00591 {
00592 printf("writeBlock:");
00593 for(int i=0; i<len; i++) printf(" %d",(int) buf[i]);
00594 printf("\n");
00595 }
00596 ret = write(fd,buf,len);
00597
00598 return ret;
00599 #endif
00600
00601 #ifdef __VMS
00602 int status;
00603 IOSB iosb;
00604
00605
00606 status = SYS$QIOW(0,vms_channel,IO$_WRITEVBLK | IO$M_CANCTRLO | IO$M_NOFORMAT,
00607 &iosb,0,0,buf,len,0,0,0,0);
00608 if(status != SS$_NORMAL) return -1;
00609 return len;
00610 #endif
00611
00612 #ifdef RLWIN32
00613 BOOL ret;
00614 unsigned long retlen;
00615
00616 if(trace == 1)
00617 {
00618 printf("writeBlock:");
00619 for(int i=0; i<len; i++) printf(" %d",(int) buf[i]);
00620 printf("\n");
00621 }
00622 retlen = len;
00623 ret = WriteFile(
00624 hdl,
00625 buf,
00626 len,
00627 &retlen,
00628 NULL
00629 );
00630
00631 if(ret) return (int) retlen;
00632 return -1;
00633 #endif
00634
00635 #ifdef RM3
00636 RmBytParmStruct PBlock;
00637 RmIOStatusStruct DrvSts;
00638 unsigned char cByte;
00639 int iStatus;
00640 int i;
00641
00642
00643
00644
00645
00646 PBlock.string = (char*)buf;
00647 PBlock.strlen = len;
00648 PBlock.buffer = 0;
00649 PBlock.timlen = 0;
00650 PBlock.status = 0;
00651
00652
00653
00654
00655
00656
00657
00658
00659 cByte = inbyte( com + 0x04u );
00660 outbyte( com + 0x04, (unsigned char)(cByte | 0x02u) );
00661
00662
00663
00664
00665 iStatus = RmIO( BYT_WRITE_WAIT, (unsigned)device, (unsigned)unit, 0u, 0u, &DrvSts, &PBlock );
00666
00667
00668
00669
00670
00671
00672
00673 RmPauseTask((RTS_TIME_WAIT*9600)/baudrate);
00674
00675
00676
00677
00678 outbyte( com + 0x04, (unsigned char)(cByte & 0xFDu) );
00679
00680 if( iStatus ) printf( "BYT_WRITE_WAIT (write block): Error status = %X\n", iStatus );
00681
00682 if( !iStatus ) return len;
00683 return -1;
00684 #endif
00685 }
00686
00687 int rlSerial::readLine(unsigned char *buf, int maxlen, int timeout)
00688 {
00689 int i,c,ret;
00690
00691 if(maxlen <= 1) return -1;
00692 ret = 0;
00693 buf[maxlen-1] = '\0';
00694 for(i=0; i<maxlen-2; i++)
00695 {
00696 ret = i;
00697 if(timeout > 0)
00698 {
00699 int t = select(timeout);
00700 if(t == 0) return -1;
00701 }
00702 c = readChar();
00703 if(c < 0)
00704 {
00705 buf[i] = '\0';
00706 ret = c;
00707 break;
00708 }
00709 buf[i] = (unsigned char) c;
00710 if(c < ' ' && c != '\t')
00711 {
00712 buf[i+1] = '\0';
00713 break;
00714 }
00715 }
00716 return ret;
00717 }
00718
00719 int rlSerial::select(int timeout)
00720 {
00721 #ifdef RLUNIX
00722 struct timeval timout;
00723 fd_set wset,rset,eset;
00724 int ret,maxfdp1;
00725
00726 if(timeout <= 0) return 1;
00727
00728 maxfdp1 = fd+1;
00729 FD_ZERO(&rset);
00730 FD_SET (fd,&rset);
00731 FD_ZERO(&wset);
00732 FD_ZERO(&eset);
00733 timout.tv_sec = timeout / 1000;
00734 timout.tv_usec = (timeout % 1000) * 1000;
00735
00736 ret = ::select(maxfdp1,&rset,&wset,&eset,&timout);
00737 if(ret == 0) return 0;
00738 return 1;
00739 #endif
00740
00741 #ifdef __VMS
00742 return 1;
00743 #endif
00744
00745 #ifdef RLWIN32
00746 COMMTIMEOUTS ctimeout;
00747
00748 ctimeout.ReadIntervalTimeout = timeout;
00749 ctimeout.ReadTotalTimeoutMultiplier = 1;
00750 ctimeout.ReadTotalTimeoutConstant = timeout;
00751 ctimeout.WriteTotalTimeoutMultiplier = 1;
00752 ctimeout.WriteTotalTimeoutConstant = timeout;
00753
00754 SetCommTimeouts(hdl, &ctimeout);
00755 return 1;
00756 #endif
00757
00758 #ifdef RM3
00759 return 1;
00760 #endif
00761 }
00762
00763 int rlSerial::closeDevice()
00764 {
00765 #ifdef RLUNIX
00766 if(fd == -1) return -1;
00767
00768 if(::tcsetattr(fd,TCSANOW,&save_termios) < 0) return -1;
00769 ::close(fd);
00770 ttystate = RESET;
00771 fd = -1;
00772 return 0;
00773 #endif
00774
00775 #ifdef __VMS
00776 sys$dassgn(vms_channel);
00777 return 0;
00778 #endif
00779
00780 #ifdef RLWIN32
00781 CloseHandle(hdl);
00782 return 0;
00783 #endif
00784
00785 #ifdef RM3
00786 RmBytParmStruct PBlock;
00787 RmIOStatusStruct DrvSts;
00788
00789 if( RmIO( BYT_RELEASE, (unsigned)(device), (unsigned)(unit), 0u, 0u, &DrvSts, &PBlock ) < 0 )
00790 {
00791 printf( "Error: Unable to release device. device: %i, unit: %i\n",device, unit );
00792 return -1;
00793 }
00794 return 0;
00795 #endif
00796 }