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 #ifdef HAVE_CONFIG_H
00027 #include "config.h"
00028 #endif
00029
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 #include <sys/ioctl.h>
00033 #include <sys/file.h>
00034 #include <fcntl.h>
00035 #include <termios.h>
00036 #include <unistd.h>
00037 #include <stdlib.h>
00038 #include <stdio.h>
00039 #include <string.h>
00040 #include <signal.h>
00041 #include <pwd.h>
00042 #include <errno.h>
00043
00044 #include <tqglobal.h>
00045
00046 #include <tdelocale.h>
00047 #include <kdebug.h>
00048
00049 #include "modem.h"
00050
00051
00052 #ifndef CSOH
00053 #define CSOH 01
00054 #endif
00055
00056 #ifndef CSTX
00057 #define CSTX 02
00058 #endif
00059
00060 #ifndef CEOT
00061 #define CEOT 04
00062 #endif
00063
00064 #ifndef CACK
00065 #define CACK 06
00066 #endif
00067
00068 #ifndef CNAK
00069 #define CNAK 025
00070 #endif
00071
00072 #ifndef CCAN
00073 #define CCAN 030
00074 #endif
00075
00076
00077
00078 Modem::Modem( KandyPrefs *kprefs, TQObject *parent, const char *name ) :
00079 TQObject(parent, name), fd(-1)
00080 {
00081 mOpen = false;
00082
00083 prefs = kprefs;
00084
00085 timer = new TQTimer( this, "modemtimer" );
00086 TQ_CHECK_PTR( timer );
00087 connect( timer, TQT_SIGNAL( timeout() ), TQT_SLOT( timerDone() ) );
00088
00089 init();
00090 xreset();
00091 }
00092
00093
00094 Modem::~Modem()
00095 {
00096 close();
00097 }
00098
00099
00100 void Modem::setSpeed( int speed )
00101 {
00102 switch ( speed ) {
00103 case 300:
00104 cspeed = B300;
00105 break;
00106 case 600:
00107 cspeed = B600;
00108 break;
00109 case 1200:
00110 cspeed = B1200;
00111 break;
00112 case 2400:
00113 cspeed = B2400;
00114 break;
00115 case 4800:
00116 cspeed = B4800;
00117 break;
00118 case 9600:
00119 cspeed = B9600;
00120 break;
00121 case 19200:
00122 cspeed = B19200;
00123 break;
00124 case 38400:
00125 cspeed = B38400;
00126 break;
00127 case 57600:
00128 cspeed = B57600;
00129 break;
00130 case 115200:
00131 cspeed = B115200;
00132 break;
00133 case 230400:
00134 cspeed = B230400;
00135 break;
00136 default:
00137 #ifdef MODEM_DEBUG
00138 fprintf(stderr, "Modem: setSpeed(): fallback to default speed.\n");
00139 #endif
00140 cspeed = B38400;
00141 }
00142 }
00143
00144
00145 void Modem::setData( int data )
00146 {
00147 cflag &= ~CSIZE;
00148
00149 switch ( data ) {
00150 case 5:
00151 cflag |= CS5;
00152 break;
00153 case 6:
00154 cflag |= CS6;
00155 break;
00156 case 7:
00157 cflag |= CS7;
00158 break;
00159 default:
00160 cflag |= CS8;
00161 }
00162 }
00163
00164
00165 void Modem::setParity( char parity )
00166 {
00167 cflag &= ~( PARENB | PARODD );
00168
00169 if ( parity == 'E' )
00170 cflag |= PARENB;
00171 else if ( parity == 'O' )
00172 cflag |= PARENB | PARODD;
00173 }
00174
00175
00176 void Modem::setStop( int stop )
00177 {
00178 if (stop == 2)
00179 cflag |= CSTOPB;
00180 else
00181 cflag &= ~CSTOPB;
00182 }
00183
00184
00185 bool Modem::open()
00186 {
00187 struct termios tty;
00188
00189 close();
00190
00191 if (fd == -1)
00192 {
00193 TQCString dev = TQFile::encodeName( (*prefs).serialDevice() );
00194 const char *fdev = dev.data();
00195 if ( ( fd = ::open( fdev, O_RDWR | O_NOCTTY | O_NONBLOCK ) ) == -1 ) {
00196 emit errorMessage( i18n( "Unable to open device '%1'. "
00197 "Please check that you have sufficient permissions." )
00198 .arg( fdev ) );
00199 return false;
00200 }
00201 }
00202
00203 if ( !lockDevice() )
00204 return false;
00205
00206 tcflush( fd, TCIOFLUSH );
00207 if ( tcgetattr( fd, &init_tty ) == -1 ) {
00208 int errnumber = errno;
00209 emit errorMessage( i18n( "Communication setup failed (tcgetattr code: %1)" )
00210 .arg(strerror(errnumber)) );
00211 unlockDevice();
00212 ::close( fd );
00213 fd = -1;
00214 return false;
00215 }
00216
00217 memset( &tty, 0, sizeof( tty ) );
00218 tty.c_iflag = IGNBRK | IGNPAR;
00219 tty.c_oflag = 0;
00220 tty.c_cflag = cflag;
00221 tty.c_lflag = 0;
00222 cfsetospeed( &tty, cspeed );
00223 cfsetispeed( &tty, cspeed );
00224 tcdrain( fd );
00225
00226 if ( tcsetattr( fd, TCSANOW, &tty ) == -1 ) {
00227 emit errorMessage( i18n( "tcsetattr() failed." ) );
00228 unlockDevice();
00229 ::close( fd );
00230 fd = -1;
00231 return false;
00232 }
00233
00234 sn = new TQSocketNotifier( fd, TQSocketNotifier::Read, this,
00235 "modemsocketnotifier" );
00236 TQ_CHECK_PTR( sn );
00237 connect( sn, TQT_SIGNAL( activated( int ) ), TQT_SLOT( readChar( int ) ) );
00238
00239 mOpen = true;
00240
00241 return true;
00242 }
00243
00244
00245 void Modem::close()
00246 {
00247 timer->stop();
00248
00249 delete sn;
00250 sn = 0;
00251
00252 unlockDevice();
00253
00254 if ( fd ) {
00255 tcflush( fd, TCIOFLUSH );
00256 tcsetattr( fd, TCSANOW, &init_tty );
00257 ::close( fd );
00258 fd = -1;
00259 }
00260
00261 xreset();
00262
00263 mOpen = false;
00264 }
00265
00266
00267 void Modem::flush()
00268 {
00269 if ( fd != -1) {
00270 tcflush( fd, TCIOFLUSH );
00271 bufpos = 0;
00272 }
00273 }
00274
00275 bool Modem::lockDevice()
00276 {
00277 if (is_locked)
00278 return true;
00279
00280 if (flock(fd, LOCK_EX))
00281 {
00282
00283 is_locked = false;
00284 emit errorMessage(i18n("Unable to lock device '%1'.").arg((*prefs).serialDevice()));
00285 }
00286 else
00287 {
00288 is_locked = true;
00289 }
00290
00291 return is_locked;
00292 }
00293
00294
00295 void Modem::unlockDevice()
00296 {
00297 if (fd != -1 && is_locked)
00298 {
00299 flock(fd, LOCK_UN);
00300 is_locked = false;
00301 }
00302 }
00303
00304
00305 bool Modem::dsrOn()
00306 {
00307 int flags;
00308
00309
00310 if ( fd == -1 ) {
00311 #ifdef MODEM_DEBUG
00312 fprintf( stderr, "Modem: dsrOn(): File not open.\n" );
00313 #endif
00314 return false;
00315 }
00316
00317 if ( ioctl( fd, TIOCMGET, &flags ) == -1 ) {
00318 #ifdef MODEM_DEBUG
00319 fprintf( stderr, "Modem: dsrOn(): ioctl() failed.\n" );
00320 #endif
00321 return false;
00322 }
00323
00324 return ( flags & TIOCM_DSR ) != 0;
00325 }
00326
00327
00328 bool Modem::ctsOn()
00329 {
00330 int flags;
00331
00332
00333 if ( fd == -1 ) {
00334 #ifdef MODEM_DEBUG
00335 fprintf( stderr, "Modem: ctsOn(): File not open.\n" );
00336 #endif
00337 return false;
00338 }
00339
00340 if ( ioctl( fd, TIOCMGET, &flags ) == -1) {
00341 #ifdef MODEM_DEBUG
00342 fprintf( stderr, "Modem: ctsOn(): ioctl() failed.\n" );
00343 #endif
00344 return false;
00345 }
00346
00347 return ( flags & TIOCM_CTS ) != 0;
00348 }
00349
00350
00351 void Modem::writeChar( const char c )
00352 {
00353 write( fd, (const void *) &c, 1 );
00354 }
00355
00356
00357 void Modem::writeLine( const char *line )
00358 {
00359 kdDebug() << "Modem::writeLine(): " << line << endl;
00360
00361 write( fd, (const void *) line, strlen( line ) );
00362 writeChar( '\r' );
00363 }
00364
00365
00366 void Modem::timerStart( int msec )
00367 {
00368 timer->start( msec, true );
00369 }
00370
00371
00372 void Modem::receiveXModem( bool crc )
00373 {
00374 disconnect( sn, 0, this, 0 );
00375 connect( sn, TQT_SIGNAL( activated( int ) ), TQT_SLOT( readXChar( int ) ) );
00376
00377 xcrc = crc;
00378
00379 if ( xcrc ) {
00380 writeChar( 'C' );
00381 xstate = 1;
00382 timerStart( 3000 );
00383 } else {
00384 writeChar( CNAK );
00385 xstate = 5;
00386 timerStart( 10000 );
00387 }
00388
00389 xblock = 1;
00390 }
00391
00392
00393 void Modem::abortXModem()
00394 {
00395 timer->stop();
00396 writeChar( CCAN );
00397 xreset();
00398 emit xmodemDone( false );
00399 }
00400
00401
00402 void Modem::timerDone()
00403 {
00404 #ifdef MODEM_DEBUG
00405 fprintf( stderr, "Modem: timeout, xstate = %d.\n", xstate );
00406 #endif
00407
00408 switch ( xstate ) {
00409 case 0:
00410 emit timeout();
00411 break;
00412
00413 case 1:
00414 case 2:
00415 case 3:
00416 writeChar( 'C' );
00417 xstate++;
00418 timerStart( 1000 );
00419 break;
00420
00421 case 4:
00422 xcrc = false;
00423
00424 case 5:
00425 case 6:
00426 case 7:
00427 case 8:
00428 case 9:
00429 writeChar( CNAK );
00430 xstate++;
00431 timerStart( 1000 );
00432 break;
00433
00434 case 10:
00435 xreset();
00436 emit xmodemDone( false );
00437 break;
00438
00439 default:
00440 writeChar( CNAK );
00441 xstate = 5;
00442 timerStart( 1000 );
00443 }
00444 }
00445
00446
00447 void Modem::readChar( int )
00448 {
00449 uchar c;
00450
00451
00452 while ( read( fd, (void *) &c, 1 ) == 1 ) {
00453 if ( c == '\n' ) {
00454 buffer[ bufpos ] = 0;
00455 bufpos = 0;
00456 emit gotLine( (const char *) buffer );
00457 break;
00458 } else
00459 if ( ( bufpos < 1000 ) && ( c != '\r' ) )
00460 buffer[ bufpos++ ] = c;
00461 }
00462 }
00463
00464
00465 void Modem::readXChar( int )
00466 {
00467 uchar c;
00468 static uchar crc_hi, block, cblock;
00469
00470
00471 while ( read( fd, (void *) &c, 1 ) == 1 ) {
00472 switch ( xstate ) {
00473 case 1:
00474 case 2:
00475 case 3:
00476 case 4:
00477 case 5:
00478 case 6:
00479 case 7:
00480 case 8:
00481 case 9:
00482 case 10:
00483 if ( c == CSOH ) {
00484 timerStart( 1000 );
00485 xsize = 128;
00486 xstate = 11;
00487 } else
00488 if ( c == CSTX ) {
00489 timerStart( 1000 );
00490 xsize = 1024;
00491 xstate = 11;
00492 } else
00493 if ( c == CEOT ) {
00494 timer->stop();
00495 writeChar( CACK );
00496 xreset();
00497 emit xmodemDone( true );
00498 } else
00499 timerStart( 1000 );
00500 break;
00501
00502 case 11:
00503 timerStart( 1000 );
00504 block = c;
00505 xstate++;
00506 break;
00507
00508 case 12:
00509 timerStart( 1000 );
00510 cblock = c;
00511 xstate++;
00512 bufpos = 0;
00513 break;
00514
00515 case 13:
00516 timerStart( 1000 );
00517 buffer[ bufpos++ ] = c;
00518 if ( bufpos == xsize ) {
00519 bufpos = 0;
00520 xstate++;
00521 if ( !xcrc )
00522 xstate++;
00523 }
00524 break;
00525
00526 case 14:
00527 timerStart( 1000 );
00528 crc_hi = c;
00529 xstate++;
00530 break;
00531
00532 case 15:
00533 timerStart( 10000 );
00534 xstate = 4;
00535 if ( (uchar) ( block ^ cblock ) != 0xff ) {
00536 writeChar( CNAK );
00537 break;
00538 }
00539 if ( block+1 == xblock ) {
00540 writeChar( CACK );
00541 break;
00542 }
00543 if ( block != xblock ) {
00544 timer->stop();
00545 writeChar( CCAN );
00546 xreset();
00547 emit xmodemDone( false );
00548 break;
00549 }
00550 if ( xcrc ) {
00551 if ( ( (ushort) crc_hi << 8 | (ushort) c ) != calcCRC() ) {
00552 writeChar( CNAK );
00553 break;
00554 }
00555 } else {
00556 if ( c != calcChecksum() ) {
00557 writeChar( CNAK );
00558 break;
00559 }
00560 }
00561 writeChar( CACK );
00562 xblock++;
00563 emit gotXBlock( buffer, xsize );
00564 break;
00565
00566 default:
00567 break;
00568 }
00569 }
00570 }
00571
00572
00573 void Modem::init()
00574 {
00575 is_locked = false;
00576
00577 fd = -1;
00578 sn = 0;
00579
00580 cspeed = B38400;
00581
00582
00583 cflag = CS8 | CREAD | CLOCAL;
00584
00585
00586 bufpos = 0;
00587 }
00588
00589
00590 void Modem::xreset()
00591 {
00592 bufpos = 0;
00593
00594 xstate = 0;
00595 xcrc = false;
00596 xblock = 0;
00597 xsize = 0;
00598
00599 if ( sn ) {
00600 disconnect( sn, 0, this, 0 );
00601 connect( sn, TQT_SIGNAL( activated( int ) ), TQT_SLOT( readChar( int ) ) );
00602 }
00603 }
00604
00605
00606 uchar Modem::calcChecksum()
00607 {
00608 int i;
00609 uchar c = 0;
00610
00611
00612 for ( i = 0; i < xsize; i++ )
00613 c += buffer[ i ];
00614
00615 return c;
00616 }
00617
00618
00619 ushort Modem::calcCRC()
00620 {
00621 int i, j;
00622 ushort c = 0;
00623
00624
00625 for ( i = 0; i < xsize; i++ ) {
00626 c ^= (ushort) buffer[ i ] << 8;
00627 for ( j = 0; j < 8; j++ )
00628 if ( c & 0x8000 )
00629 c = c << 1 ^ 0x1021;
00630 else
00631 c <<= 1;
00632 }
00633
00634 return c;
00635 }
00636
00637 #include "modem.moc"