/*
* Copyleft of Simone Margaritelli aka evilsocket <evilsocket@gmail.com>
* http://www.evilsocket.net/
*
* This 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 3 of the License, or
* (at your option) any later version.
*
* This is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software. If not, see <http://www.gnu.org/licenses/>.
*/
package com.evilsocket.blehacks;
import java.util.LinkedList;
import java.util.Queue;
import com.evilsocket.blehacks.BLEIoOperation.Type;
import com.evilsocket.blehacks.Utils.Logger;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothProfile;
public class BLEIoQueue extends BluetoothGattCallback
{
public interface QueueCallbacks
{
public void onServicesDiscovered( BLEIoQueue queue, BluetoothGatt gatt, final int status);
};
private Queue<BLEIoOperation> _ops;
private BluetoothGatt _gatt;
private QueueCallbacks _callbacks;
private BLEIoOperation _current;
public BLEIoQueue( QueueCallbacks callbacks ) {
_ops = new LinkedList<BLEIoOperation>();
_callbacks = callbacks;
_current = null;
}
public void add( BLEIoOperation op ) {
_ops.add(op);
}
private void next()
{
BLEIoOperation op = _ops.poll();
if( op == null ){
Logger.d( "No I/O operations to execute." );
return;
}
_current = op;
boolean ok = false;
BluetoothGattDescriptor desc = op.get_descriptor();
BluetoothGattCharacteristic charact = op.get_characteristic();
byte[] data = op.get_data();
if( op.get_type() == Type.NOTIFY_START )
{
ok = _gatt.setCharacteristicNotification(charact, true);
if( ok ){
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
ok = _gatt.writeDescriptor(desc);
}
}
else if( op.get_type() == Type.WRITE_DESCRIPTOR )
{
desc.setValue(data);
ok = _gatt.writeDescriptor(desc);
}
else if( op.get_type() == Type.WRITE_CHARACTERISTICS )
{
charact.setValue(data);
Packet p = new Packet(charact.getValue());
Logger.d( ">> " + p.toString() );
ok = _gatt.writeCharacteristic(charact);
}
else if( op.get_type() == Type.READ_CHARACTERISTICS )
{
ok = _gatt.readCharacteristic(charact);
}
else
{
Logger.e( "Unhandled Operation");
}
if( ok == false ){
Logger.e( "Operation failed, fetching next ..." );
next();
}
}
@Override
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
if( newState == BluetoothProfile.STATE_CONNECTED )
{
Logger.i( "Connected to GATT server, starting services discovery ..." );
_gatt = gatt;
gatt.discoverServices();
}
else if( newState == BluetoothProfile.STATE_DISCONNECTED )
{
Logger.w( "Disconnected." );
}
}
@Override
public void onServicesDiscovered(final BluetoothGatt gatt, final int status)
{
_callbacks.onServicesDiscovered( this, gatt, status );
next();
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
next();
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Packet p = new Packet( characteristic.getValue() );
int op = ( p.getBuffer()[1] & 0xFF );
if( op == 0xF4 || op == 0x15 )
{
// just session pings
}
else if( _current != null && _current.get_callback() != null )
{
_current.get_callback().onData(p);
}
else
{
Logger.w( "Unhandled Response: " + p.toString() );
}
next();
}
}