Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

OTDriver.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2003 by Mattia Merzi                                    *
00003  *   ottobit@ferrara.linux.it                                              *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  ***************************************************************************/
00010 
00011 #include <opie2/odebug.h>
00012 #include <qtimer.h>
00013 
00014 #include <sys/poll.h>
00015 #include <bluezlib.h>
00016 #ifndef GET_LINK_QUALITY_RP_SIZE
00017 #define GET_LINK_QUALITY_RP_SIZE READ_LINK_QUALITY_RP_SIZE
00018 #endif
00019 #include <OTGateway.h>
00020 #include <OTDriver.h>
00021 #include <OTHCISocket.h>
00022 
00023 using namespace Opietooth2;
00024 
00025 static struct {
00026     const char  *str;
00027     unsigned short rev;
00028 } csr_map[] = {
00029     { "HCI 11.2 (bc01b)",   114 },
00030     { "HCI 11.3 (bc01b)",   115 },
00031     { "HCI 12.1 (bc01b)",   119 },
00032     { "HCI 12.3 (bc01b)",   134 },
00033     { "HCI 12.7 (bc01b)",   188 },
00034     { "HCI 12.8 (bc01b)",   218 },
00035     { "HCI 12.9 (bc01b)",   283 },
00036     { "HCI 13.10 (bc01b)",  309 },
00037     { "HCI 13.11 (bc01b)",  351 },
00038     { "HCI 16.4 (bc01b)",   523 },
00039     { "HCI 14.3 (bc02x)",   272 },
00040     { "HCI 14.6 (bc02x)",   336 },
00041     { "HCI 14.7 (bc02x)",   373 },
00042     { "HCI 14.8 (bc02x)",   487 },
00043     { "HCI 15.3 (bc02x)",   443 },
00044     { "HCI 16.4 (bc02x)",   525 },
00045     { NULL, 0}
00046 };
00047 
00048 static char *services[] = { "Positioning",
00049                             "Networking",
00050                             "Rendering",
00051                             "Capturing",
00052                             "Object Transfer",
00053                             "Audio",
00054                             "Telephony",
00055                             "Information" };
00056 
00057 static char *major_devices[] = { "Miscellaneous",
00058                                  "Computer",
00059                                  "Phone",
00060                                  "LAN Access",
00061                                  "Audio/Video",
00062                                  "Peripheral",
00063                                  "Imaging",
00064                                  "Uncategorized" };
00065 
00066 
00067 typedef struct {
00068     short Minor;
00069     const char * Description;
00070 } ClassMap_t;
00071 
00072 static ClassMap_t MapMiscClass[] = {
00073     { -1, "" }
00074 };
00075 
00076 static ClassMap_t MapUnclassifiedClass[] = {
00077     { -1, "" }
00078 };
00079 
00080 static ClassMap_t MapComputerClass[] = {
00081     { 0, "Uncategorized" } ,
00082     { 1, "Desktop workstation" } ,
00083     { 2, "Server" } ,
00084     { 3, "Laptop" } ,
00085     { 4, "Handheld" } ,
00086     { 5, "Palm" } ,
00087     { 6, "Wearable" },
00088     { -1, 0 }
00089 };
00090 
00091 static ClassMap_t MapPhoneClass[] = {
00092     { 0, "Uncategorized" },
00093     { 1, "Cellular" },
00094     { 2, "Cordless" },
00095     { 3, "Smart phone" },
00096     { 4, "Wired modem or voice gateway" },
00097     { 5, "Common ISDN Access" },
00098     { 6, "Sim Card Reader" },
00099     { -1, 0 }
00100 };
00101 
00102 static ClassMap_t MapAVClass[] = {
00103     { 0, "Uncategorized" },
00104     { 1, "Device conforms to the Headset profile" },
00105     { 2, "Hands-free" },
00106     { 3, 0 },
00107     { 4, "Microphone" },
00108     { 5, "Loudspeaker" },
00109     { 6, "Headphones" },
00110     { 7, "Portable Audio" },
00111     { 8, "Car Audio" },
00112     { 9, "Set-top box" },
00113     { 10, "HiFi Audio Device" },
00114     { 11, "VCR" },
00115     { 12, "Video Camera" },
00116     { 13, "Camcorder" },
00117     { 14, "Video Monitor" },
00118     { 15, "Video Display and Loudspeaker" },
00119     { 16, "Video Conferencing" },
00120     { 17, 0 },
00121     { 18, "Gaming/Toy" },
00122     { -1, 0 }
00123 };
00124 
00125 static ClassMap_t MapPeripheralClass[] = {
00126     { 16, "Keyboard" },
00127     { 32, "Pointing device" },
00128     { 48, "Combo keyboard/pointing device" },
00129     { -1, 0 }
00130 };
00131 
00132 typedef struct {
00133     int Major;
00134     ClassMap_t * Map;
00135 } MainClassMap_t;
00136 
00137 static MainClassMap_t MainClasses[] = {
00138     { 0, MapMiscClass },
00139     { 1, MapComputerClass },
00140     { 2, MapPhoneClass },
00141     { 3, 0 }, // special case
00142     { 4, MapAVClass },
00143     { 5, MapPeripheralClass },
00144     { 6, 0 }, // special case
00145     { 63, MapUnclassifiedClass },
00146     { -1, 0 }
00147 };
00148 
00149 OTDriver::OTDriver( OTGateway * _OT, struct hci_dev_info* di) : QObject( _OT ), Address() {
00150     OT = _OT;
00151     IsUp = 0;
00152     Socket = 0;
00153 
00154     init(di);
00155     odebug << "Driver " << devname() << oendl;
00156 
00157     AutoClose = new QTimer( this );
00158     connect( AutoClose,
00159              SIGNAL( timeout() ),
00160              this,
00161              SLOT( SLOT_CloseFd() )
00162            );
00163 }
00164 
00165 OTDriver::~OTDriver() {
00166     closeSocket();
00167     SLOT_CloseFd();
00168 }
00169 
00170 void OTDriver::SLOT_CloseFd( void ){
00171     if ( isOpen() ) {
00172       AutoClose->stop();
00173       ::close( fd() );
00174       setfd( -1 );
00175     }
00176 }
00177 
00178 void OTDriver::init(struct hci_dev_info* di) {
00179 
00180     Dev = di->name;
00181 
00182     setDevId(di->dev_id);
00183     setType(di->type);
00184     setFlags(di->flags);
00185     Address.setBDAddr( di->bdaddr );
00186     setFeatures(di->features);
00187     setfd( -1 ); // not open
00188 
00189     Manufacturer = "";
00190 }
00191 
00192 // internal reinitialize
00193 void OTDriver::reinit() {
00194     bool Old;
00195     Old = IsUp;
00196 
00197     if( currentState() < 0 )
00198       return;
00199 
00200     if( Old != IsUp ) {
00201       // state changes
00202       emit stateChange( this, IsUp );
00203     }
00204 }
00205 
00206 // requested by application
00207 int OTDriver::currentState() {
00208     struct hci_dev_info di;
00209 
00210     //  uint16_t tmp_dev_id = device_info.dev_id;
00211     //  bzero(&device_info,sizeof(struct hci_dev_info));
00212     //  device_info.dev_id = tmp_dev_id;
00213 
00214     memset( &di, 0, sizeof( di ) );
00215     di.dev_id = Dev_id;
00216     if( ioctl( OT->getSocket(), HCIGETDEVINFO, (void*)&di) < 0 ) {
00217       SLOT_CloseFd();
00218       return -1;
00219     } else {
00220       // load new info
00221       init(&di);
00222     }
00223 
00224     return IsUp;
00225 }
00226 
00227 bool OTDriver::open() {
00228 
00229     // (re)start single shot close
00230     AutoClose->start( 30000, TRUE );
00231 
00232     if( isOpen() )
00233       // is open
00234       return 1;
00235 
00236     setfd(hci_open_dev(devId()));
00237 
00238     if (fd() < 0) {
00239       emit error( tr( "Can't open device %1. %2 : %3" ).
00240                       arg( devname() ).
00241                       arg( errno ).
00242                       arg( strerror(errno) )
00243                 );
00244       return 0;
00245     }
00246 
00247     return 1;
00248 }
00249 
00250 QString OTDriver::name() {
00251     char name[1000];
00252 
00253     if( ! open() ) {
00254       return tr("Cannot open");
00255     }
00256 
00257     if (hci_read_local_name( fd(), sizeof(name), name, 1000) < 0) {
00258       if (errno != ETIMEDOUT) {
00259         emit error( tr("Can't read local name on %1. %2 : %3.  Default to %4" ).
00260             arg( devname() ).
00261             arg( errno  ).
00262             arg( strerror(errno) ).
00263             arg( devname() )
00264           );
00265       } // ETIMEDOUT error is quite normal, device is down ... I think ! :)
00266       strcpy(name,devname().latin1());
00267     }
00268     return QString(name);
00269 }
00270 
00271 void OTDriver::setFlags(unsigned long flags) {
00272 
00273     //  kdDebug() << "Setting OTDriver Values ..." << endl;
00274     IsUp = BTVALUE(hci_test_bit(HCI_UP, &flags));
00275 
00276     if (isUp()) {
00277         setIScan(BTVALUE(hci_test_bit(HCI_ISCAN, &flags)));
00278         setPScan(BTVALUE(hci_test_bit(HCI_PSCAN, &flags)));
00279         setAuthentication(BTVALUE(hci_test_bit(HCI_AUTH, &flags)));
00280         setEncryption(BTVALUE(hci_test_bit(HCI_ENCRYPT, &flags)));
00281     } else {
00282         setIScan(BT_UNKNOWN);
00283         setPScan(BT_UNKNOWN);
00284         setAuthentication(BT_UNKNOWN);
00285         setEncryption(BT_UNKNOWN);
00286     }
00287 }
00288 
00289 QString OTDriver::revision() {
00290 
00291     struct hci_version ver;
00292 
00293     if( ! open() ) {
00294       return tr("Cannot open");
00295     }
00296 
00297     if (hci_read_local_version(fd(), &ver, 1000) < 0) {
00298       emit error( tr( "Can't read revision info on %1. %2 : %3" ).
00299           arg( devname() ).
00300           arg( errno ).
00301           arg( strerror(errno) ) );
00302       return QString();
00303     }
00304 
00305     setManufacturer(ver.manufacturer);
00306 
00307     switch (ver.manufacturer) {
00308       case 0:
00309         return getRevEricsson();
00310         break;
00311       case 10:
00312         return getRevCsr(ver.hci_rev);
00313         break;
00314       default:
00315         return tr( "Unsupported manufacturer" );
00316         break;
00317     }
00318 }
00319 
00320 QString OTDriver::getRevEricsson() {
00321 
00322     char revision[102];
00323     struct hci_request rq;
00324 
00325     if( ! open() ) {
00326       return QString( "Cannot open" );
00327     }
00328 
00329     memset(&rq, 0, sizeof(rq));
00330     rq.ogf = 0x3f;
00331     rq.ocf = 0x000f;
00332     rq.cparam = NULL;
00333     rq.clen = 0;
00334     rq.rparam = &revision;
00335     rq.rlen = sizeof(revision);
00336 
00337     if (hci_send_req(fd(), &rq, 1000) < 0) {
00338       emit error( tr( "Can't read revision info on %1. %2 : %3" ).
00339           arg( devname() ).
00340           arg( errno ).
00341           arg( strerror(errno) ) );
00342       return QString();
00343     }
00344 
00345     return QString( revision+1 );
00346 }
00347 
00348 QString OTDriver::getRevCsr( unsigned short rev) {
00349 
00350     int i;
00351 
00352     for (i = 0; csr_map[i].str; i++)
00353       if (csr_map[i].rev == rev) {
00354         return QString( csr_map[i].str );
00355       }
00356 
00357     return tr( "Unknown firmware" );
00358 }
00359 
00360 int OTDriver::reset() {
00361 
00362     if( ! open() ) {
00363       return 0;
00364     }
00365 
00366     if( ioctl(fd(), HCIDEVRESET, devId()) < 0 ) {
00367       if( errno != EALREADY ) {
00368         emit error( tr( "Reset failed for %1. %2 : %3" ).
00369             arg( devname() ).
00370             arg( errno ).
00371             arg( strerror(errno) ) );
00372         if (errno == EACCES) {
00373           return EACCES;
00374         }
00375       }
00376     }
00377     return 0;
00378 }
00379 
00380 void OTDriver::setUp( bool M )  {
00381     if( M && ! isUp() ) {
00382       bringUp();
00383     } else if( ! M && isUp() ) {
00384       bringDown();
00385     }
00386 }
00387 
00388 void OTDriver::bringUp() {
00389 
00390     odebug << "bringUp : " << Dev << oendl;
00391 
00392     if( ! open() ) {
00393       return;
00394     }
00395 
00396     if (! isUp()) {
00397       if( ioctl(fd(), HCIDEVUP, devId()) < 0 ) {
00398         if( errno != EALREADY ) {
00399           emit error( tr( "Cannot bring interface %1 up. %2 : %3" ).
00400               arg( devname() ).
00401               arg( errno ).
00402               arg( strerror(errno) ) );
00403         }
00404         return;
00405       }
00406       // have to wait a bit for the 'up' to become active
00407       QTimer::singleShot( 3000, this, SLOT( reinit() ) );
00408     }
00409 }
00410 
00411 void OTDriver::bringDown() {
00412 
00413     odebug << "bringDown : " << Dev << oendl;
00414 
00415     if( ! open() ) {
00416       return;
00417     }
00418 
00419     if ( isUp() ) {
00420       if( ioctl(fd(), HCIDEVDOWN, devId()) < 0 ) {
00421         if( errno != EALREADY ) {
00422           emit error( tr( "Cannot bring interface %1 down. %2 : %3" ).
00423               arg( devname() ).
00424               arg( errno ).
00425               arg( strerror(errno) ) );
00426         }
00427         return;
00428       }
00429       reinit();
00430     }
00431 }
00432 
00433 void OTDriver::setScanMode(bool iscan, bool pscan) {
00434 
00435     struct hci_dev_req dr;
00436 
00437     if( ! open() ) {
00438       return;
00439     }
00440 
00441     dr.dev_id  = devId();
00442     dr.dev_opt = SCAN_DISABLED;
00443 
00444     if( iscan&&(!pscan) )
00445       dr.dev_opt = SCAN_INQUIRY;
00446     else if( pscan&&(!iscan) )
00447       dr.dev_opt = SCAN_PAGE;
00448     else if( pscan&&iscan )
00449       dr.dev_opt = SCAN_PAGE | SCAN_INQUIRY;
00450 
00451     if( ioctl(fd(), HCISETSCAN, (unsigned long)&dr) < 0 ) {
00452       if( errno != EALREADY ) {
00453         emit error( tr( "Can't set scan mode on %1. %2 : %3" ).
00454             arg( devname() ).
00455             arg( errno ).
00456             arg( strerror(errno) ) );
00457       }
00458       return;
00459     }
00460 
00461     reinit();
00462 }
00463 
00464 void OTDriver::changeDevName(const char* name) {
00465 
00466     if( ! open() ) {
00467       return;
00468     }
00469 
00470     if (hci_write_local_name(fd(), name, 1000) < 0) {
00471       emit error( tr( "Can't change local name on %1. %2 : %3" ).
00472           arg( devname() ).
00473           arg( errno ).
00474           arg( strerror(errno) ) );
00475     }
00476 }
00477 
00478 void OTDriver::changeAuthentication(bool _auth) {
00479     struct hci_dev_req dr;
00480 
00481     if( ! open() ) {
00482       return;
00483     }
00484 
00485     dr.dev_id  = devId();
00486     dr.dev_opt = _auth?AUTH_ENABLED:AUTH_DISABLED;
00487    
00488     if (ioctl(fd(),HCISETAUTH,(unsigned long)&dr) < 0) {
00489       if( errno != EALREADY ) {
00490         emit error( tr( "Can't change authentication on %1. %2 : %3" ).
00491             arg( devname() ).
00492             arg( errno ).
00493             arg( strerror(errno) ) );
00494       }
00495       return;
00496     }
00497     reinit();
00498 }
00499 
00500 void OTDriver::changeEncryption(bool _encrypt) {
00501     struct hci_dev_req dr;
00502 
00503     if( ! open() ) {
00504       return;
00505     }
00506 
00507     dr.dev_id  = devId();
00508     dr.dev_opt = _encrypt?ENCRYPT_P2P:ENCRYPT_DISABLED;
00509         
00510     if (ioctl(fd(),HCISETENCRYPT,(unsigned long)&dr) < 0) {
00511       if( errno != EALREADY ) {
00512         emit error( tr( "Can't change encryption on %1. %2 : %3" ).
00513             arg( devname() ).
00514             arg( errno ).
00515             arg( strerror(errno) ) );
00516       }
00517       return;
00518     }
00519 
00520     reinit();
00521 }
00522 
00523 void OTDriver::changeClass ( unsigned char service,  
00524                              unsigned char major,
00525                              unsigned char minor ) {
00526     unsigned long cod = 0;
00527     cod = (service << 16) |
00528           (major   <<  8) |
00529           (minor        ) ;
00530 
00531     if( ! open() ) {
00532       return;
00533     }
00534 
00535     if ( hci_write_class_of_dev(fd(),cod,1000) < 0 ) {
00536       emit error( tr( "Can't change class informations for %1. %2 : %3" ).
00537           arg( devname() ).
00538           arg( errno ).
00539           arg( strerror(errno) ) );
00540       return;
00541     }
00542 }
00543 
00544 void OTDriver::getClass( QString & service,  
00545                          QString & device ) {
00546     unsigned char cls[3];
00547 
00548     if( ! open() ) {
00549       return;
00550     }
00551 
00552     if ( hci_read_class_of_dev(fd(),cls,1000) < 0 ) {
00553       emit error( tr( "Can't read class information for %1. %2 : %3" ).
00554           arg( devname() ).
00555           arg( errno ).
00556           arg( strerror(errno) ) );
00557       return;
00558     }
00559 
00560     if( cls[2] ) {
00561       int first = 1;
00562       for ( unsigned int s = 0; s < sizeof(*services); s++) {
00563         if (cls[2] & (1 << s)) {
00564           if( !first )
00565             service += ", ";
00566           service += services[s];
00567           first = 0;
00568         }
00569       }
00570     } else {
00571       service = "unspecified";
00572     }
00573 
00574     MainClassMap_t * MCM = MainClasses;
00575     int major = cls[1] & 0x1f;
00576     int minor = cls[0] >> 2;
00577 
00578     if( (unsigned)(cls[1] & 0x1f) > sizeof(*major_devices)) {
00579       device = tr("Invalid Device Class");
00580       return;
00581     }
00582 
00583     device = major_devices[cls[1] & 0x1f];
00584 
00585     while( MCM->Major != -1 ) {
00586       if( major == MCM->Major ) {
00587         // this class
00588         ClassMap_t * CM = MCM->Map;
00589         if( MCM->Map ) {
00590           while( CM->Minor != -1 ) {
00591             if( minor == CM->Minor ) {
00592               break;
00593             }
00594             CM ++;
00595           }
00596           device = CM->Description;
00597         } else {
00598           // special case
00599           if( major == 3 ) {
00600             /* lan access */
00601             if( minor == 0 ) {
00602               device = "Uncategorized";
00603             } else {
00604               switch( minor / 8 ) {
00605                 case 0:
00606                   device = "Fully available";
00607                   break;
00608                 case 1:
00609                   device = "1-17% utilized";
00610                   break;
00611                 case 2:
00612                   device = "17-33% utilized";
00613                   break;
00614                 case 3:
00615                   device = "33-50% utilized";
00616                   break;
00617                 case 4:
00618                   device = "50-67% utilized";
00619                   break;
00620                 case 5:
00621                   device = "67-83% utilized";
00622                   break;
00623                 case 6:
00624                   device = "83-99% utilized";
00625                   break;
00626                 case 7:
00627                   device = "No service available";
00628                   break;
00629               }
00630             }
00631           } else if( major == 6 ) { /* imaging */
00632             if (minor & 4)
00633               device = "Display";
00634             if (minor & 8)
00635               device = "Camera";
00636             if (minor & 16)
00637               device = "Scanner";
00638             if (minor & 32)
00639               device = "Printer";
00640           }
00641         }
00642         break;
00643       }
00644       MCM ++;
00645     }
00646 
00647     if( MCM->Major == -1 ) {
00648       device = "Unknown (reserved) minor device class";
00649     }
00650 }
00651 
00652 QString OTDriver::strType() {
00653     return QString( hci_dtypetostr(Type) );
00654 }
00655 
00656 void OTDriver::setFeatures( unsigned char * _f) {
00657     Features = lmp_featurestostr(_f, NULL, 255);
00658 }
00659 
00660 void OTDriver::setManufacturer(int compid) {
00661     Manufacturer = bt_compidtostr(compid);
00662 }
00663 
00664 OTHCISocket * OTDriver::openSocket( void ) {
00665     if( ! Socket ) {
00666       odebug << "Open HCI socket to " << devname() << oendl;
00667       Socket = new OTHCISocket( this );
00668     }
00669     return Socket;
00670 }
00671 
00672 void OTDriver::closeSocket( void ) {
00673     if( Socket ) {
00674       odebug << "Close HCI socket to " << devname() << oendl;
00675       delete Socket;
00676       Socket = 0;
00677     }
00678 }
00679 
00680 QString OTDriver::getPeerName( const OTDeviceAddress & PAddr ) {
00681       QString S;
00682       char name[100 ];
00683 
00684       if( ! open() ) {
00685         return QString("N/A");
00686       }
00687 
00688       if( hci_read_remote_name( fd(), 
00689                                 &(PAddr.getBDAddr()), 
00690                                 sizeof(name), 
00691                                 name, 
00692                                 100000 ) < 0 ) {
00693         return QString( "N/A" );
00694       }
00695 
00696       return QString( name );
00697 }
00698 
00699 long OTDriver::getLinkQuality( const OTDeviceAddress & Addr ) {
00700       struct hci_conn_info_req *cr;
00701       struct hci_request rq;
00702       read_rssi_rp rp;
00703       uint16_t handle;
00704 
00705       if( ! open() ) {
00706         return 0;
00707       }
00708 
00709       cr = (struct hci_conn_info_req *)malloc(
00710                 sizeof(*cr) + sizeof(struct hci_conn_info));
00711       if (!cr)
00712         return 0;
00713 
00714       bacpy( &(cr->bdaddr), &(Addr.getBDAddr()) );
00715       cr->type = ACL_LINK;
00716 
00717       if (ioctl( fd(), HCIGETCONNINFO, (unsigned long) cr) < 0) {
00718         odebug << "Get NetworkSetup info failed" << oendl;
00719         free(cr);
00720         return 0;
00721       }
00722 
00723       handle = htobs(cr->conn_info->handle);
00724 
00725       free(cr);
00726 
00727       memset(&rq, 0, sizeof(rq));
00728       rq.ogf    = OGF_STATUS_PARAM;
00729       rq.ocf    = OCF_READ_RSSI;
00730       rq.cparam = &handle;
00731       rq.clen   = 2;
00732       rq.rparam = &rp;
00733       rq.rlen   = GET_LINK_QUALITY_RP_SIZE;
00734 
00735       if (hci_send_req( fd(), &rq, 100) < 0) {
00736          odebug << "Get NetworkSetup info failed" << oendl;
00737          return 0;
00738       }
00739 
00740       if( rp.status ) {
00741         odebug << QString().sprintf("HCI get_link_quality cmd failed (0x%2.2X)", rp.status) << oendl;
00742         return 0;
00743       }
00744 
00745       return rp.rssi+50;
00746 }

Generated on Sat Nov 5 16:17:55 2005 for OPIE by  doxygen 1.4.2