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

obluetooth.cpp

Go to the documentation of this file.
00001 /*
00002                              This file is part of the Opie Project
00003                              Copyright (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de>
00004               =.             Copyright (C) The Opie Team <opie-devel@handhelds.org>
00005             .=l.
00006            .>+-=
00007  _;:,     .>    :=|.         This program is free software; you can
00008 .> <`_,   >  .   <=          redistribute it and/or  modify it under
00009 :`=1 )Y*s>-.--   :           the terms of the GNU Library General Public
00010 .="- .-=="i,     .._         License as published by the Free Software
00011  - .   .-<_>     .<>         Foundation; version 2 of the license.
00012      ._= =}       :
00013     .%`+i>       _;_.
00014     .i_,=:_.      -<s.       This program is distributed in the hope that
00015      +  .  -:.       =       it will be useful,  but WITHOUT ANY WARRANTY;
00016     : ..    .:,     . . .    without even the implied warranty of
00017     =_        +     =;=|`    MERCHANTABILITY or FITNESS FOR A
00018   _.=:.       :    :=>`:     PARTICULAR PURPOSE. See the GNU
00019 ..}^=.=       =       ;      Library General Public License for more
00020 ++=   -.     .`     .:       details.
00021  :     =  ...= . :.=-
00022  -.   .:....=;==+<;          You should have received a copy of the GNU
00023   -_. . .   )=.  =           Library General Public License along with
00024     --        :-=`           this library; see the file COPYING.LIB.
00025                              If not, write to the Free Software Foundation,
00026                              Inc., 59 Temple Place - Suite 330,
00027                              Boston, MA 02111-1307, USA.
00028 */
00029 
00030 #include "obluetooth.h"
00031 
00032 /* OPIE */
00033 #include <opie2/odebug.h>
00034 using namespace Opie::Core;
00035 
00036 /* STD */
00037 #include <bluetooth/bluetooth.h>
00038 #include <bluetooth/hci.h>
00039 #include <bluetooth/hci_lib.h>
00040 #include <assert.h>
00041 #include <errno.h>
00042 #include <stdlib.h>
00043 #include <string.h>
00044 #include <unistd.h>
00045 #include <sys/ioctl.h>
00046 #include <sys/types.h>
00047 #include <sys/socket.h>
00048 
00049 namespace Opie {
00050 namespace Bluez {
00051 
00052 /*======================================================================================
00053  * OBluetooth
00054  *======================================================================================*/
00055 
00056 OBluetooth* OBluetooth::_instance = 0;
00057 
00058 OBluetooth::OBluetooth()
00059 {
00060     synchronize();
00061 }
00062 
00063 OBluetooth* OBluetooth::instance()
00064 {
00065     if ( !_instance ) _instance = new OBluetooth();
00066     return _instance;
00067 }
00068 
00069 OBluetooth::InterfaceIterator OBluetooth::iterator() const
00070 {
00071     return OBluetooth::InterfaceIterator( _interfaces );
00072 }
00073 
00074 int OBluetooth::count() const
00075 {
00076     return _interfaces.count();
00077 }
00078 
00079 OBluetoothInterface* OBluetooth::interface( const QString& iface ) const
00080 {
00081     return _interfaces[iface];
00082 }
00083 
00084 void OBluetooth::synchronize()
00085 {
00086     odebug << "OBluetooth::synchronize() - gathering available HCI devices" << oendl;
00087     _interfaces.clear();
00088 
00089     _fd = ::socket( AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI );
00090     if ( _fd == -1 )
00091     {
00092         owarn << "OBluetooth::synchronize() - can't open HCI control socket (" << strerror( errno ) << ")" << oendl;
00093         return;
00094     }
00095 
00096     struct hci_dev_list_req *dl;
00097     struct hci_dev_req *dr;
00098     struct hci_dev_info di;
00099 
00100     if (!(dl = (struct hci_dev_list_req*)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t))))
00101     {
00102         ofatal << "OBluetooth::synchronize() - can't allocate memory for HCI request" << oendl;
00103         return;
00104     }
00105 
00106     dl->dev_num = HCI_MAX_DEV;
00107     dr = dl->dev_req;
00108 
00109     if (::ioctl( _fd, HCIGETDEVLIST, (void *) dl) == -1)
00110     {
00111         owarn << "OBluetooth::synchronize() - can't complete HCIGETDEVLIST (" << strerror( errno ) << ")" << oendl;
00112         return;
00113     }
00114 
00115     for ( int i = 0; i < dl->dev_num; ++i )
00116     {
00117         di.dev_id = ( dr + i )->dev_id;
00118         if ( ::ioctl( _fd, HCIGETDEVINFO, (void *) &di ) == -1 )
00119         {
00120             owarn << "OBluetooth::synchronize() - can't issue HCIGETDEVINFO on device " << i << " (" << strerror( errno ) << ") - skipping that device. " << oendl;
00121             continue;
00122         }
00123         odebug << "OBluetooth::synchronize() - found device #" << di.dev_id << oendl;
00124         _interfaces.insert( di.name, new OBluetoothInterface( this, di.name, (void*) &di, _fd ) );
00125     }
00126 }
00127 
00128 /*======================================================================================
00129  * OBluetoothInterface
00130  *======================================================================================*/
00131 
00132 class OBluetoothInterface::Private
00133 {
00134   public:
00135     Private( struct hci_dev_info* di, int fd )
00136     {
00137         ::memcpy( &devinfo, di, sizeof(struct hci_dev_info) );
00138         ctlfd = fd;
00139     }
00140     void reloadInfo()
00141     {
00142         int result = ::ioctl( ctlfd, HCIGETDEVINFO, (void *) &devinfo );
00143         if ( result == -1 )
00144         {
00145             owarn << "OBluetoothInterface::Private - can't reload device info (" << strerror( errno ) << ")" << oendl;
00146         }
00147     }
00148     struct hci_dev_info devinfo;
00149     int ctlfd;
00150 };
00151 
00152 OBluetoothInterface::OBluetoothInterface( QObject* parent, const char* name, void* devinfo, int ctlfd )
00153                     :QObject( parent, name )
00154 {
00155     d = new OBluetoothInterface::Private( (struct hci_dev_info*) devinfo, ctlfd );
00156 }
00157 
00158 OBluetoothInterface::~OBluetoothInterface()
00159 {
00160 }
00161 
00162 QString OBluetoothInterface::macAddress() const
00163 {
00164     return QString().sprintf( "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
00165                               d->devinfo.bdaddr.b[5],
00166                               d->devinfo.bdaddr.b[4],
00167                               d->devinfo.bdaddr.b[3],
00168                               d->devinfo.bdaddr.b[2],
00169                               d->devinfo.bdaddr.b[1],
00170                               d->devinfo.bdaddr.b[0] );
00171 }
00172 
00173 bool OBluetoothInterface::setUp( bool b )
00174 {
00175     int cmd = b ? HCIDEVUP : HCIDEVDOWN;
00176     int result = ::ioctl( d->ctlfd, cmd, d->devinfo.dev_id );
00177     if ( result == -1 && errno != EALREADY )
00178     {
00179         owarn << "OBluetoothInterface::setUp( " << b << " ) - couldn't change interface state (" << strerror( errno ) << ")" << oendl;
00180         return false;
00181     }
00182     else
00183     {
00184         d->reloadInfo();
00185         return true;
00186     }
00187 }
00188 
00189 bool OBluetoothInterface::isUp() const
00190 {
00191     return hci_test_bit( HCI_UP, &d->devinfo.flags );
00192 }
00193 
00194 OBluetoothInterface::DeviceIterator OBluetoothInterface::neighbourhood()
00195 {
00196     _devices.clear();
00197     struct hci_inquiry_req* ir;
00198     int nrsp = 255;
00199 
00200     char* mybuffer = static_cast<char*>( malloc( sizeof( *ir ) + ( sizeof( inquiry_info ) * (nrsp) ) ) );
00201     assert( mybuffer );
00202 
00203     ir = (struct hci_inquiry_req*) mybuffer;
00204     memset( ir, 0, sizeof( *ir ) + ( sizeof( inquiry_info ) * (nrsp) ) );
00205 
00206     ir->dev_id  = d->devinfo.dev_id;
00207     ir->num_rsp = nrsp;
00208     ir->length  = 8; // 10 seconds
00209     ir->flags   = 0;
00210     ir->lap[0] = 0x33; // GIAC
00211     ir->lap[1] = 0x8b;
00212     ir->lap[2] = 0x9e;
00213 
00214     int result = ::ioctl( d->ctlfd, HCIINQUIRY, mybuffer );
00215     if ( result == -1 )
00216     {
00217         owarn << "OBluetoothInterface::neighbourhood() - can't issue HCIINQUIRY (" << strerror( errno ) << ")" << oendl;
00218         return DeviceIterator( _devices );
00219     }
00220 
00221     inquiry_info* ii = (inquiry_info*)( ir+1 );
00222 
00223     for ( int i = 0; i < ir->num_rsp; ++i )
00224     {
00225         OBluetoothDevice* dev = new OBluetoothDevice( this, 0, ii );
00226         _devices.insert( dev->macAddress(), dev );
00227         ++ii;
00228     }
00229 
00230     return DeviceIterator( _devices );
00231 }
00232 
00233 /*======================================================================================
00234  * OBluetoothDevice
00235  *======================================================================================*/
00236 
00237 class OBluetoothDevice::Private
00238 {
00239   public:
00240     Private( inquiry_info* ii )
00241     {
00242         ::memcpy( &inqinfo, ii, sizeof(inquiry_info) );
00243     }
00244     inquiry_info inqinfo;
00245 };
00246 
00247 OBluetoothDevice::OBluetoothDevice( QObject* parent, const char* name, void* inqinfo )
00248                  :QObject( parent, name )
00249 {
00250     odebug << "OBluetoothDevice::OBluetoothDevice() - '" << name << "'" << oendl;
00251     d = new OBluetoothDevice::Private( (inquiry_info*) inqinfo );
00252 }
00253 
00254 OBluetoothDevice::~OBluetoothDevice()
00255 {
00256     odebug << "OBluetoothDevice::~OBluetoothDevice()" << oendl;
00257 }
00258 
00259 QString OBluetoothDevice::macAddress() const
00260 {
00261     return QString().sprintf( "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
00262     d->inqinfo.bdaddr.b[5],
00263     d->inqinfo.bdaddr.b[4],
00264     d->inqinfo.bdaddr.b[3],
00265     d->inqinfo.bdaddr.b[2],
00266     d->inqinfo.bdaddr.b[1],
00267     d->inqinfo.bdaddr.b[0] );
00268 }
00269 
00270 QString OBluetoothDevice::deviceClass() const
00271 {
00272     int maj = d->inqinfo.dev_class[1] & 0x1f;
00273     int min = d->inqinfo.dev_class[0] >> 2;
00274 
00275     QString major = QString( "Unknown(%1)" ).arg( maj );
00276     QString minor = QString( "Unknown(%1)" ).arg( min );
00277 
00278     switch ( maj )
00279     {
00280         case 0: major = "Miscellaneous";
00281         break;
00282 
00283         case 1: major = "Computer";
00284         switch ( min )
00285         {
00286             case 0: minor = "Uncategorized";
00287             case 1: minor = "Desktop workstation";
00288             case 2: minor = "Server";
00289             case 3: minor = "Laptop";
00290             case 4: minor = "Handheld";
00291             case 5: minor = "Palm";
00292             case 6: minor = "Wearable";
00293         }
00294         break;
00295 
00296         case 2: major = "Phone";
00297         switch ( min )
00298         {
00299             case 0: minor = "Uncategorized"; break;
00300             case 1: minor = "Cellular"; break;
00301             case 2: minor = "Cordless"; break;
00302             case 3: minor = "Smart phone"; break;
00303             case 4: minor = "Wired modem or voice gateway"; break;
00304             case 5: minor = "Common ISDN Access"; break;
00305             case 6: minor = "Sim Card Reader"; break;
00306         }
00307         break;
00308 
00309         case 3: major = "LAN Access";
00310         break;
00311 
00312         case 4: major = "Audio/Video";
00313         switch ( min )
00314         {
00315             case 0: minor = "Uncategorized"; break;
00316             case 1: minor = "Device conforms to the Headset profile"; break;
00317             case 2: minor = "Hands-free"; break;
00318             case 3: minor = "Reserved(3)"; break;
00319             case 4: minor = "Microphone"; break;
00320             case 5: minor = "Loudspeaker"; break;
00321             case 6: minor = "Headphones"; break;
00322             case 7: minor = "Portable Audio"; break;
00323             case 8: minor = "Car Audio"; break;
00324             case 9: minor = "Set-top box"; break;
00325             case 10: minor = "HiFi Audio Device"; break;
00326             case 11: minor = "VCR"; break;
00327             case 12: minor = "Video Camera"; break;
00328             case 13: minor = "Camcorder"; break;
00329             case 14: minor = "Video Monitor"; break;
00330             case 15: minor = "Video Display and Loudspeaker"; break;
00331             case 16: minor = "Video Conferencing"; break;
00332             case 17: minor = "Reserved(17)"; break;
00333             case 18: minor = "Gaming/Toy"; break;
00334         }
00335         break;
00336 
00337         case 5: major = "Peripheral";
00338         switch ( min )
00339         {
00340             case 16: minor = "Keyboard"; break;
00341             case 32: minor = "Pointing Device"; break;
00342             case 48: minor = "Keyboard and Pointing Device"; break;
00343         }
00344         break;
00345 
00346         case 6: major = "Imaging";
00347         if (min & 4) minor = "Display";
00348         else if (min & 8) minor = "Camera";
00349         else if (min & 16) minor = "Scanner";
00350         else if (min & 32) minor = "Printer";
00351         break;
00352 
00353         case 63: major = "Uncategorized";
00354         break;
00355     }
00356 
00357     return QString( "%1:%2" ).arg( major ).arg( minor );
00358 }
00359 
00360 QString OBluetoothDevice::getName()
00361 {
00362     /* FIXME: Uahhh, this gets ugly.
00363     The BlueZ kernel interface seems to be very badly (if at all) documented.
00364     All people are assuming that you use libbluetooth to talk to that stack.
00365     However since libbluetooth is GPL, we can't do that :/
00366     Guess, we are stuck here until someone finds time and/or motivation to look
00367     into that and create some easy-to-understand examples for how to talk
00368     directly to the BlueZ kernel interface.
00369     */
00370 };
00371 
00372 
00373 }
00374 }

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