diff options
| author | Javier <dev.git@javispedro.com> | 2016-06-05 19:52:05 +0200 | 
|---|---|---|
| committer | Javier <dev.git@javispedro.com> | 2016-06-05 19:52:05 +0200 | 
| commit | 9609356531350285d92072213e02a2908af464f5 (patch) | |
| tree | f12dbf28d9149d46e7ddbb11f4aa2ba584f2f8f8 | |
| parent | 1905841f4008a58932368a7099e370e5758544c4 (diff) | |
| download | libgato-9609356531350285d92072213e02a2908af464f5.tar.gz libgato-9609356531350285d92072213e02a2908af464f5.zip  | |
allow setting connection parameters before actual connection
| -rw-r--r-- | gatoconnectionparameters.cpp | 5 | ||||
| -rw-r--r-- | gatosocket.cpp | 145 | ||||
| -rw-r--r-- | gatosocket.h | 1 | 
3 files changed, 85 insertions, 66 deletions
diff --git a/gatoconnectionparameters.cpp b/gatoconnectionparameters.cpp index 29ec37b..c8270c8 100644 --- a/gatoconnectionparameters.cpp +++ b/gatoconnectionparameters.cpp @@ -12,6 +12,11 @@ struct GatoConnectionParametersPrivate : public QSharedData  GatoConnectionParameters::GatoConnectionParameters()  	: d(new GatoConnectionParametersPrivate)  { +	// Set a connection scan interval between 10 and 320 ms. +	d->connIntervalMin = 10000; +	d->connIntervalMax = 320000; +	d->slaveLatency = 0; +	d->supervisionTimeout = 10000; // 10 seconds  }  GatoConnectionParameters::GatoConnectionParameters(const GatoConnectionParameters &o) diff --git a/gatosocket.cpp b/gatosocket.cpp index 7860c9e..9c7163b 100644 --- a/gatosocket.cpp +++ b/gatosocket.cpp @@ -31,21 +31,6 @@  #ifndef BT_LE_PARAMS  /* Too old kernel headers. */  #define BT_LE_PARAMS	100 -#define BT_LE_SCAN_WINDOW_MIN		0x0004 -#define BT_LE_SCAN_WINDOW_MAX		0x4000 -#define BT_LE_SCAN_WINDOW_DEF		0x0004 -#define BT_LE_SCAN_INTERVAL_MIN		0x0004 -#define BT_LE_SCAN_INTERVAL_MAX		0x4000 -#define BT_LE_SCAN_INTERVAL_DEF		0x0008 -#define BT_LE_CONN_INTERVAL_MIN		0x0006 -#define BT_LE_CONN_INTERVAL_MAX		0x0C80 -#define BT_LE_CONN_INTERVAL_MIN_DEF	0x0008 -#define BT_LE_CONN_INTERVAL_MAX_DEF	0x0100 -#define BT_LE_LATENCY_MAX		0x01F4 -#define BT_LE_LATENCY_DEF		0x0000 -#define BT_LE_SUP_TO_MIN		0x000A -#define BT_LE_SUP_TO_MAX		0x0C80 -#define BT_LE_SUP_TO_DEFAULT		0X03E8  struct bt_le_params {  	uint8_t  prohibit_remote_chg; @@ -64,7 +49,8 @@ struct bt_le_params {  #endif /* BT_LE_PARAMS */  GatoSocket::GatoSocket(QObject *parent) -	: QObject(parent), s(StateDisconnected), fd(-1), desiredSec(SecurityLow) +	: QObject(parent), s(StateDisconnected), fd(-1), +	  desiredSec(SecurityLow), desiredParams()  {  } @@ -82,6 +68,9 @@ GatoSocket::State GatoSocket::state() const  bool GatoSocket::connectTo(const GatoAddress &addr, unsigned short cid)  { +	struct sockaddr_l2 l2addr; +	int err; +  	if (s != StateDisconnected) {  		qWarning() << "Already connecting or connected";  		return false; @@ -95,16 +84,33 @@ bool GatoSocket::connectTo(const GatoAddress &addr, unsigned short cid)  	s = StateConnecting; -	setSecurityLevel(desiredSec); +	// bind the socket to the BLE CID before connecting so that the kernel knows +	memset(&l2addr, 0, sizeof(l2addr)); +	l2addr.l2_family = AF_BLUETOOTH; +	l2addr.l2_cid = htobs(cid); + +	err = ::bind(fd, reinterpret_cast<sockaddr*>(&l2addr), sizeof(l2addr)); +	if (err == -1) { +		qErrnoWarning("Could not bind L2CAP socket"); +		close(); +		return false; +	} + +	if (!setSecurityLevel(desiredSec)) { +		close(); +		return false; +	} +	if (!setConnectionParameters(desiredParams)) { +		close(); +		return false; +	}  	readNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);  	writeNotifier = new QSocketNotifier(fd, QSocketNotifier::Write, this);  	connect(readNotifier, SIGNAL(activated(int)), SLOT(readNotify()));  	connect(writeNotifier, SIGNAL(activated(int)), SLOT(writeNotify())); -	struct sockaddr_l2 l2addr;  	memset(&l2addr, 0, sizeof(l2addr)); -  	l2addr.l2_family = AF_BLUETOOTH;  	l2addr.l2_cid = htobs(cid);  #ifdef BDADDR_LE_PUBLIC @@ -120,6 +126,7 @@ bool GatoSocket::connectTo(const GatoAddress &addr, unsigned short cid)  		l2addr.l2_bdaddr_type = BDADDR_LE_RANDOM;  		break;  	} +	qDebug() << "address type" << l2addr.l2_bdaddr_type;  #else  	// The kernel is probably too old to support this,  	// but BLE might still work (e.g. Nokia N9). @@ -129,7 +136,7 @@ bool GatoSocket::connectTo(const GatoAddress &addr, unsigned short cid)  #endif  	addr.toUInt8Array(l2addr.l2_bdaddr.b); -	int err = ::connect(fd, reinterpret_cast<sockaddr*>(&l2addr), sizeof(l2addr)); +	err = ::connect(fd, reinterpret_cast<sockaddr*>(&l2addr), sizeof(l2addr));  	if (err == -1 && errno != EINPROGRESS) {  		qErrnoWarning("Could not connect to L2CAP socket");  		close(); @@ -178,10 +185,10 @@ void GatoSocket::send(const QByteArray &pkt)  GatoSocket::SecurityLevel GatoSocket::securityLevel() const  { -	bt_security bt_sec; -	socklen_t len = sizeof(bt_sec); -  	if (s != StateDisconnected) { +		bt_security bt_sec; +		socklen_t len = sizeof(bt_sec); +  		if (::getsockopt(fd, SOL_BLUETOOTH, BT_SECURITY, &bt_sec, &len) == 0) {  			switch (bt_sec.level) {  			case BT_SECURITY_SDP: @@ -240,62 +247,68 @@ bool GatoSocket::setSecurityLevel(SecurityLevel level)  GatoConnectionParameters GatoSocket::connectionParameters() const  {  	GatoConnectionParameters params; -	bt_le_params bt_params; -	socklen_t len = sizeof(bt_params); - -	if (s == StateDisconnected) { -		qWarning() << "Socket not connected"; -		return params; -	} -	if (::getsockopt(fd, SOL_BLUETOOTH, BT_LE_PARAMS, &bt_params, &len) == 0) { -		if (bt_params.interval_min == 0 && bt_params.interval_max == 0) { -			// Sometimes the kernel will give us this when no parameters have been set. -			// I believe it is a bug, because in truth the kernel default parameters are in use. -			qDebug() << "Filling in kernel defaults, since the kernel did not"; -			bt_params.interval_min = BT_LE_CONN_INTERVAL_MIN_DEF; -			bt_params.interval_max = BT_LE_CONN_INTERVAL_MAX_DEF; -			bt_params.latency = BT_LE_LATENCY_DEF; -			bt_params.supervision_timeout = BT_LE_SUP_TO_DEFAULT; +	if (s != StateDisconnected) { +		bt_le_params bt_params; +		socklen_t len = sizeof(bt_params); + +		if (::getsockopt(fd, SOL_BLUETOOTH, BT_LE_PARAMS, &bt_params, &len) == 0) { +			qDebug() << "sinternal" << bt_params.scan_interval << "swindow" << bt_params.scan_window +					 << "cinterval" << bt_params.interval_min << bt_params.interval_max +					 << "latency" << bt_params.latency << "sup timeout" << bt_params.supervision_timeout; + +			if (bt_params.interval_min == 0 && bt_params.interval_max == 0) { +				// Sometimes the kernel will give us this when no parameters have been set. +				// I believe it is a bug, because in truth the kernel default parameters are in use. +				qDebug() << "Assuming kernel defaults, since the kernel responded with empty interval"; +				return desiredParams; +			} +			// Kernel uses "multiples of 1.25ms", we use µs, need to convert. +			params.setConnectionInterval(bt_params.interval_min * 1250, bt_params.interval_max * 1250); +			// Kernel units already in ms. +			params.setSlaveLatency(bt_params.latency); +			// Kernel uses "multiples of 10ms", need to convert +			params.setSupervisionTimeout(bt_params.supervision_timeout * 10); + +			return params; +		} else { +			qErrnoWarning("Could not read connection parameters from L2 socket");  		} -		// Kernel uses "multiples of 1.25ms", we use µs, need to convert. -		params.setConnectionInterval(bt_params.interval_min * 1250, bt_params.interval_max * 1250); -		// Kernel units already in ms. -		params.setSlaveLatency(bt_params.latency); -		// Kernel uses "multiples of 10ms", need to convert -		params.setSupervisionTimeout(bt_params.supervision_timeout * 10); -	} else { -		qErrnoWarning("Could not read connection parameters from L2 socket");  	} -	return params; +	return desiredParams;  }  bool GatoSocket::setConnectionParameters(const GatoConnectionParameters ¶ms)  { -	bt_le_params bt_params; -	socklen_t len = sizeof(bt_params); +	desiredParams = params; -	if (s == StateDisconnected) { -		qWarning() << "Socket not connected"; -		return false; -	} +	if (s != StateDisconnected) { +		bt_le_params bt_params; +		socklen_t len = sizeof(bt_params); -	memset(&bt_params, 0, len); +		memset(&bt_params, 0, len); -	// Kernel uses "multiples of 1.25ms", we use µs, need to convert -	bt_params.interval_min = params.connectionIntervalMin() / 1250; -	bt_params.interval_max = params.connectionIntervalMax() / 1250; -	// Kernel units already "ms". -	bt_params.latency = params.slaveLatency(); -	// Kernel uses "multiples of 10ms", need to convert -	bt_params.supervision_timeout = params.supervisionTimeout() / 10; +		// Kernel uses "multiples of 1.25ms", we use µs, need to convert +		bt_params.interval_min = params.connectionIntervalMin() / 1250; +		bt_params.interval_max = params.connectionIntervalMax() / 1250; +		// Kernel units already "ms". +		bt_params.latency = params.slaveLatency(); +		// Kernel uses "multiples of 10ms", need to convert +		bt_params.supervision_timeout = params.supervisionTimeout() / 10; -	if (::setsockopt(fd, SOL_BLUETOOTH, BT_LE_PARAMS, &bt_params, len) == 0) { -		return true; +		qDebug() << "sinternal" << bt_params.scan_interval << "swindow" << bt_params.scan_window +				 << "cinterval" << bt_params.interval_min << bt_params.interval_max +				 << "latency" << bt_params.latency << "sup timeout" << bt_params.supervision_timeout; + +		if (::setsockopt(fd, SOL_BLUETOOTH, BT_LE_PARAMS, &bt_params, len) == 0) { +			return true; +		} else { +			qErrnoWarning("Could not set connection parameters in L2 socket"); +			return false; +		}  	} else { -		qErrnoWarning("Could not set connection parameters in L2 socket"); -		return false; +		return true;  	}  } diff --git a/gatosocket.h b/gatosocket.h index b7634c7..6909e8d 100644 --- a/gatosocket.h +++ b/gatosocket.h @@ -70,6 +70,7 @@ private:  	State s;  	int fd;  	SecurityLevel desiredSec; +	GatoConnectionParameters desiredParams;  	QSocketNotifier *readNotifier;  	QQueue<QByteArray> readQueue;  	QSocketNotifier *writeNotifier;  | 
