Diffstat (limited to 'noncore/settings/networksettings2/opietooth2/OTHCISocket.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/settings/networksettings2/opietooth2/OTHCISocket.cpp | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/noncore/settings/networksettings2/opietooth2/OTHCISocket.cpp b/noncore/settings/networksettings2/opietooth2/OTHCISocket.cpp new file mode 100644 index 0000000..471c3bf --- a/dev/null +++ b/noncore/settings/networksettings2/opietooth2/OTHCISocket.cpp @@ -0,0 +1,274 @@ +//-*-c++-*- +/*************************************************************************** + * Copyright (C) 2003 by Fred Schaettgen * + * kdebluetooth@schaettgen.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include <qbuffer.h> +#include <qtimer.h> +#include <qdatastream.h> +#include <opie2/odebug.h> + +#include <bluezlib.h> + +// #include "deviceaddress.h" +#include <OTHCISocket.h> +#include <OTDriver.h> + +using namespace Opietooth2; + +OTHCISocket::OTHCISocket( OTDriver * D ) : + QObject( D, D->devname() ) { + BStatusSet = false; + Driver = D; + HCIReadNotifier = 0; +} + +OTHCISocket::~OTHCISocket() { + close(); +} + +void OTHCISocket::close() { + owarn << "OTHCISocket::close()" << oendl; + if( HCIReadNotifier ) { + delete HCIReadNotifier; + } + + if( HCISocket.isValid() ) { + HCISocket.close(); + } +} + +bool OTHCISocket::open() { + + owarn << "OTHCISocket::open()" << oendl; + int s; + + s = ::socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + + if (s < 0) { + emit error( tr( "Error creating socket on %1 : %2 %3"). + arg( Driver->devname() ). + arg( errno ). + arg( strerror(errno) ) + ); + return false; + } + + /* Bind socket to the HCI device */ + struct sockaddr_hci sa; + sa.hci_family = AF_BLUETOOTH; + sa.hci_dev = Driver->devId(); + if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) { + ::close(s); + emit error( tr( "Error binding to socket to %1 : %2 %3"). + arg( Driver->devname() ). + arg( errno ). + arg( strerror(errno) ) + ); + return false; + } + + struct hci_filter flt; + hci_filter_clear(&flt); + hci_filter_set_ptype(HCI_EVENT_PKT, &flt); + hci_filter_all_events(&flt); + if( setsockopt(s, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0 ) { + ::close(s); + emit error( tr( "HCI filter setup failed on %1 : %2 %3"). + arg( Driver->devname() ). + arg( errno ). + arg( strerror(errno) ) + ); + return false; + } + + if( HCIReadNotifier ) { + delete HCIReadNotifier; + } + + HCISocket.setSocket(s, QSocketDevice::Datagram); + HCIReadNotifier = new QSocketNotifier( + s, QSocketNotifier::Read, this); + + connect( HCIReadNotifier, + SIGNAL(activated(int)), + this, + SLOT(slotSocketActivated()) + ); + + //connect(hciSocket, SIGNAL(error(int)), + // this, SLOT(slotSocketError(int))); + //connect(hciSocket, SIGNAL(connectionClosed()), + // this, SLOT(slotConnectionClosed())); + //hciSocket->setSocket(s); + + return true; +} + +void OTHCISocket::slotSocketError(int e) { + close(); + emit error( tr( "HCI socket error 0x%1 on %1 : %2 %3"). + arg(e,2,16). + arg( Driver->devname() ). + arg( errno ). + arg( strerror(errno) ) + ); +} + +void OTHCISocket::slotSocketActivated() { + + QSocketDevice::Error err = HCISocket.error(); + + if( (err == QSocketDevice::NoError ) && + ( HCISocket.isValid() ) ) { + //kdDebug() << "HCI socket ready read." << endl; + + unsigned char buf[512]; + int psize = HCISocket.readBlock((char*)buf, 512); + + if (psize <= 0) { + slotSocketError(HCISocket.error()); + HCISocket.close(); + return; + } + + //unsigned char packetType = buf[0]; + unsigned char eventCode = buf[1]; + unsigned char len = buf[2]; + + if (psize-3 == len) { + + QByteArray databuf; + databuf.duplicate((char*)(buf+3), len); + emit event(eventCode, databuf); + if (eventCode == EVT_CMD_STATUS) { + updateStatus( databuf ); + } + } else { + owarn << "Error reading hci packet: packetSize(" + << psize + << ")-3 != dataSize(" + << len + << ")" + << oendl; + } + } else if (err == QSocketDevice::NoError) { + slotConnectionClosed(); + } else { + HCISocket.close(); + slotSocketError(err); + } +} + +void OTHCISocket::updateStatus(const QByteArray& data) { + + QDataStream stream(data, IO_ReadOnly); + stream.setByteOrder(QDataStream::LittleEndian); + Q_UINT8 status, dummy; + Q_UINT16 opcode; + + BStatusSet = true; + + stream >> status >> dummy >> opcode; + //kdDebug() << "updatestatus opcode=" << uint32_t(opcode) << endl; + LastStatus = status; + LastStatusOgf = cmd_opcode_ogf(opcode); + LastStatusOcf = cmd_opcode_ocf(opcode); +} + +void OTHCISocket::slotConnectionClosed() { + owarn << "HCI connection closed." << oendl; + emit connectionClosed(); +} + +void OTHCISocket::readEvent() { + + if (HCIReadNotifier) { + slotSocketActivated(); + } +} + +bool OTHCISocket::sendCommand( unsigned char ogf, + unsigned short ocf, + QByteArray buf + ) { + QBuffer packet; + QDataStream stream(&packet); + + stream.setByteOrder(QDataStream::LittleEndian); + packet.open(IO_WriteOnly); + + if (buf.size() > 255) return false; + + //kdDebug() << "sendCommand. ogf=" << ogf << " ocf=" << ocf << endl; + Q_UINT16 opcode = cmd_opcode_pack(ogf, ocf); + Q_UINT8 pType = HCI_COMMAND_PKT; + Q_UINT8 buflen = buf.size(); + + stream << pType << opcode << buflen; + stream.writeRawBytes(buf.data(), buflen); + packet.close(); + HCISocket.writeBlock((const char*)packet.buffer(), + packet.buffer().size()); + return true; +} + +bool OTHCISocket::readStatus( unsigned char ogf, + unsigned short ocf, + int *status, + int timeout_ms) { + QTimer timer; + + timer.start(timeout_ms, true); + BStatusSet = false; + + while (timer.isActive() && HCISocket.isValid()) { + + owarn << "OTHCISocket::readStatus()" << oendl; + bool timeout = false; + + if( HCISocket.bytesAvailable() == 0) { + int rv = HCISocket.waitForMore(timeout_ms); + timeout = (rv == 0); + } + + if (!timeout) { + slotSocketActivated(); + } + + if( BStatusSet == true && + ogf == LastStatusOgf && + ocf == LastStatusOcf) { + *status = LastStatus; + owarn << "OTHCISocket::readStatus(ogf=" + << ogf + << ",ocf=" + << ocf + << ",timeout=" + << LastStatus + << ")" + << oendl; + return true; + } + } + + owarn << "OTHCISocket::readStatus(ogf=" + << ogf + << ",ocf=" + << ocf + << ",timeout=" + << LastStatus + << ") : timeout " + << oendl; + return false; +} + +int OTHCISocket::socket() { + return HCISocket.socket(); +} |