Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions .idea/libraries/appcompat_v7_20_0_0.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions .idea/libraries/support_v4_20_0_0.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified app/app-release.apk
Binary file not shown.
225 changes: 225 additions & 0 deletions app/src/main/java/com/mooshim/mooshimeter/common/BLEUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
package com.mooshim.mooshimeter.common;

import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;

import com.mooshim.mooshimeter.main.SensorTagGatt;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.UUID;

/**
* Created by JWHONG on 1/26/2015.
* The purpose of this class is to pace all interactions with the BLE layer to one request at a time.
* Anything more than that and everything gets buggy.
*/
public class BLEUtil {
private static final String TAG="BLEUtil";
private Context mContext;
private BluetoothLeService bt_service;
private BluetoothGattService bt_gatt_service;

private LinkedList<BLEUtilRequest> mExecuteQueue = new LinkedList<BLEUtilRequest>();
private BLEUtilRequest mRunning = null;
private HashMap<UUID,BLEUtilCB> mNotifyCB= new HashMap<UUID,BLEUtilCB>();

public static abstract class BLEUtilCB implements Runnable {
public UUID uuid; // UUID
public byte[] value; // Value for the characteristic in question
public int error; // Error from the BLE layer
public abstract void run();
};

private static class BLEUtilRequest {
public Runnable payload;
public BLEUtilCB callback;
protected BLEUtilRequest() {};
public BLEUtilRequest(final Runnable p, final BLEUtilCB c) {
payload = p;
callback = c;
}
}

private static BLEUtil mInstance = null;

public static synchronized BLEUtil getInstance() {
return mInstance;
}

public static synchronized BLEUtil getInstance(Context context) {
if(mInstance == null) {
mInstance = new BLEUtil(context);
}
return getInstance();
}

public static void Destroy() {
// Clear the global instance
if(mInstance != null) {
mInstance.mContext.unregisterReceiver(mInstance.mGattUpdateReceiver);
mInstance.close();
mInstance = null;
}
}

protected BLEUtil(Context context) {
// Initialize internal structures
mContext = context;
bt_service = BluetoothLeService.getInstance();
if(bt_service != null) {
// Get the GATT service
bt_gatt_service = null;
for( BluetoothGattService s : bt_service.getSupportedGattServices() ) {
// FIXME: Should be able to specify the service to attach to instead of hardcode
if(s.getUuid().equals(MooshimeterDevice.mUUID.METER_SERVICE)) {
Log.i(TAG, "Found the meter service");
bt_gatt_service = s;
break;
}
}
if(bt_gatt_service == null) {
Log.e(TAG, "Did not find the meter service!");
}
}
// FIXME: I am unhappy with the way this class and DeviceActivity are structured
// There are a lot of interdependencies that make them complicated to work with.
// But I don't want to change too many things at once.
final IntentFilter fi = new IntentFilter();
fi.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
fi.addAction(BluetoothLeService.ACTION_DATA_NOTIFY);
fi.addAction(BluetoothLeService.ACTION_DATA_WRITE);
fi.addAction(BluetoothLeService.ACTION_DESCRIPTOR_WRITE);
fi.addAction(BluetoothLeService.ACTION_DATA_READ);
context.registerReceiver(mGattUpdateReceiver, fi);
mContext = context;
}

public void close() {
mExecuteQueue.clear();
mRunning = null;
}

////////////////////////////////
// Accessors
////////////////////////////////

synchronized private void serviceExecuteQueue(BLEUtilRequest add) {
if(add != null) {
mExecuteQueue.addLast(add);
}
if(mRunning == null) {
if(!mExecuteQueue.isEmpty()) {
mRunning = mExecuteQueue.remove();
mRunning.payload.run();
}
}
}
synchronized private void finishRunningBlock(final UUID uuid, final int error, final byte[] value) {
if(mRunning==null) {
Log.e(TAG,"ERROR: Asked to finish a task but no task running");
return;
}
final BLEUtilCB cb = mRunning.callback;
mRunning = null;
if(cb == null) {
return;
}
cb.uuid = uuid;
cb.error = error;
cb.value = value;
cb.run();
serviceExecuteQueue(null);
}

public void req(UUID uuid, BLEUtilCB on_complete) {
final BluetoothGattCharacteristic c = bt_gatt_service.getCharacteristic(uuid);
BLEUtilRequest r = new BLEUtilRequest(new Runnable() {
@Override
public void run() {
bt_service.readCharacteristic(c);
}
}, on_complete);
serviceExecuteQueue(r);
}
public void send(final UUID uuid, final byte[] value, final BLEUtilCB on_complete) {
final BluetoothGattCharacteristic c = bt_gatt_service.getCharacteristic(uuid);
BLEUtilRequest r = new BLEUtilRequest(new Runnable() {
@Override
public void run() {
c.setValue(value);
bt_service.writeCharacteristic(c);
}
}, on_complete);
serviceExecuteQueue(r);
}
public void enableNotify(final UUID uuid, final boolean enable, final BLEUtilCB on_complete, final BLEUtilCB on_notify) {
final BluetoothGattCharacteristic c = bt_gatt_service.getCharacteristic(uuid);
// Set up the notify callback
if(on_notify != null) {
mNotifyCB.put(uuid, on_notify);
} else {
mNotifyCB.remove(uuid);
}
if(bt_service.isNotificationEnabled(c) != enable) {
// Only bother setting the notification if the status has changed
BLEUtilRequest r = new BLEUtilRequest(new Runnable() {
@Override
public void run() {
bt_service.setCharacteristicNotification(c,enable);
}
}, on_complete);
serviceExecuteQueue(r);
} else {
// Otherwise just run the callback
on_complete.run();
}
}

////////////////////////////////
// GATT Callbacks
////////////////////////////////

private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
int status = intent.getIntExtra( BluetoothLeService.EXTRA_STATUS, BluetoothGatt.GATT_SUCCESS);
String uuidStr = intent.getStringExtra( BluetoothLeService.EXTRA_UUID);
byte[] value = intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA);

UUID uuid = UUID.fromString(uuidStr);

if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
} else if ( BluetoothLeService.ACTION_DATA_READ.equals(action) ) {
finishRunningBlock(uuid, status, value);
} else if ( BluetoothLeService.ACTION_DATA_NOTIFY.equals(action) ) {
if(mNotifyCB.containsKey(uuid)) {
BLEUtilCB cb = mNotifyCB.get(uuid);
cb.uuid = uuid;
cb.error = status;
cb.value = value;
cb.run();
}
} else if (BluetoothLeService.ACTION_DATA_WRITE.equals(action)) {
finishRunningBlock(uuid, status, value);
} else if (BluetoothLeService.ACTION_DESCRIPTOR_WRITE.equals(action)) {
finishRunningBlock(uuid, status, value);
}
if (status != BluetoothGatt.GATT_SUCCESS) {
// GATT Error 133 seems to be coming up from time to time. I don't think we're doing anything wrong,
// just instability in the Android stack...
Log.e(TAG, "GATT error code: " + status);
}
}
};
}
13 changes: 0 additions & 13 deletions app/src/main/java/com/mooshim/mooshimeter/common/Block.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -199,16 +199,16 @@ private void broadcastUpdate(final String action,
private boolean checkGatt() {
if (mBtAdapter == null) {
// Log.w(TAG, "BluetoothAdapter not initialized");
return false;
//return false;
}
if (mBluetoothGatt == null) {
// Log.w(TAG, "BluetoothGatt not initialized");
return false;
//return false;
}

if (mBusy) {
// Log.w(TAG, "LeService busy");
return false;
//return false;
}
return true;

Expand Down Expand Up @@ -335,6 +335,7 @@ public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
return false;

mBusy = true;
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
return mBluetoothGatt.writeCharacteristic(characteristic);
}

Expand Down Expand Up @@ -387,22 +388,16 @@ public boolean setCharacteristicNotification(
if (clientConfig != null) {

if (enable) {
// Log.i(TAG, "Enable notification: " +
// characteristic.getUuid().toString());
ok = clientConfig
.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
} else {
// Log.i(TAG, "Disable notification: " +
// characteristic.getUuid().toString());
ok = clientConfig
.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
}

if (ok) {
mBusy = true;
ok = mBluetoothGatt.writeDescriptor(clientConfig);
// Log.i(TAG, "writeDescriptor: " +
// characteristic.getUuid().toString());
}
}
}
Expand Down
Loading